1<?php 2 3namespace SimpleSAML\Metadata; 4 5use SAML2\Constants; 6use SAML2\XML\md\AttributeAuthorityDescriptor; 7use SAML2\XML\md\AttributeConsumingService; 8use SAML2\XML\md\EndpointType; 9use SAML2\XML\md\EntityDescriptor; 10use SAML2\XML\md\IDPSSODescriptor; 11use SAML2\XML\md\IndexedEndpointType; 12use SAML2\XML\md\Organization; 13use SAML2\XML\md\RequestedAttribute; 14use SAML2\XML\md\RoleDescriptor; 15use SAML2\XML\md\SPSSODescriptor; 16use SAML2\XML\mdattr\EntityAttributes; 17use SAML2\XML\mdrpi\RegistrationInfo; 18use SAML2\XML\mdui\DiscoHints; 19use SAML2\XML\mdui\Keywords; 20use SAML2\XML\mdui\Logo; 21use SAML2\XML\mdui\UIInfo; 22use SAML2\XML\saml\Attribute; 23use SAML2\XML\saml\AttributeValue; 24use SAML2\XML\shibmd\Scope; 25use SimpleSAML\Configuration; 26use SimpleSAML\Logger; 27use SimpleSAML\Module\adfs\SAML2\XML\fed\SecurityTokenServiceType; 28use SimpleSAML\Utils; 29 30/** 31 * Class for generating SAML 2.0 metadata from SimpleSAMLphp metadata arrays. 32 * 33 * This class builds SAML 2.0 metadata for an entity by examining the metadata for the entity. 34 * 35 * @package SimpleSAMLphp 36 */ 37 38class SAMLBuilder 39{ 40 /** 41 * The EntityDescriptor we are building. 42 * 43 * @var \SAML2\XML\md\EntityDescriptor 44 */ 45 private $entityDescriptor; 46 47 48 /** 49 * The maximum time in seconds the metadata should be cached. 50 * 51 * @var int|null 52 */ 53 private $maxCache = null; 54 55 56 /** 57 * The maximum time in seconds since the current time that this metadata should be considered valid. 58 * 59 * @var int|null 60 */ 61 private $maxDuration = null; 62 63 64 /** 65 * Initialize the SAML builder. 66 * 67 * @param string $entityId The entity id of the entity. 68 * @param int|null $maxCache The maximum time in seconds the metadata should be cached. Defaults to null 69 * @param int|null $maxDuration The maximum time in seconds this metadata should be considered valid. Defaults 70 * to null. 71 * @return void 72 */ 73 public function __construct($entityId, $maxCache = null, $maxDuration = null) 74 { 75 assert(is_string($entityId)); 76 77 $this->maxCache = $maxCache; 78 $this->maxDuration = $maxDuration; 79 80 $this->entityDescriptor = new EntityDescriptor(); 81 $this->entityDescriptor->setEntityID($entityId); 82 } 83 84 85 /** 86 * @param array $metadata 87 * @return void 88 */ 89 private function setExpiration($metadata) 90 { 91 if (array_key_exists('expire', $metadata)) { 92 if ($metadata['expire'] - time() < $this->maxDuration) { 93 $this->maxDuration = $metadata['expire'] - time(); 94 } 95 } 96 97 if ($this->maxCache !== null) { 98 $this->entityDescriptor->setCacheDuration('PT' . $this->maxCache . 'S'); 99 } 100 if ($this->maxDuration !== null) { 101 $this->entityDescriptor->setValidUntil(time() + $this->maxDuration); 102 } 103 } 104 105 106 /** 107 * Retrieve the EntityDescriptor element which is generated for this entity. 108 * 109 * @return \DOMElement The EntityDescriptor element of this entity. 110 */ 111 public function getEntityDescriptor() 112 { 113 $xml = $this->entityDescriptor->toXML(); 114 $xml->ownerDocument->appendChild($xml); 115 116 return $xml; 117 } 118 119 120 /** 121 * Retrieve the EntityDescriptor as text. 122 * 123 * This function serializes this EntityDescriptor, and returns it as text. 124 * 125 * @param bool $formatted Whether the returned EntityDescriptor should be formatted first. 126 * 127 * @return string The serialized EntityDescriptor. 128 */ 129 public function getEntityDescriptorText($formatted = true) 130 { 131 assert(is_bool($formatted)); 132 133 $xml = $this->getEntityDescriptor(); 134 if ($formatted) { 135 Utils\XML::formatDOMElement($xml); 136 } 137 138 return $xml->ownerDocument->saveXML(); 139 } 140 141 142 /** 143 * Add a SecurityTokenServiceType for ADFS metadata. 144 * 145 * @param array $metadata The metadata with the information about the SecurityTokenServiceType. 146 * @return void 147 */ 148 public function addSecurityTokenServiceType($metadata) 149 { 150 assert(is_array($metadata)); 151 assert(isset($metadata['entityid'])); 152 assert(isset($metadata['metadata-set'])); 153 154 $metadata = Configuration::loadFromArray($metadata, $metadata['entityid']); 155 $defaultEndpoint = $metadata->getDefaultEndpoint('SingleSignOnService'); 156 $e = new SecurityTokenServiceType(); 157 $e->setLocation($defaultEndpoint['Location']); 158 159 $this->addCertificate($e, $metadata); 160 161 $this->entityDescriptor->addRoleDescriptor($e); 162 } 163 164 165 /** 166 * Add extensions to the metadata. 167 * 168 * @param \SimpleSAML\Configuration $metadata The metadata to get extensions from. 169 * @param \SAML2\XML\md\RoleDescriptor $e Reference to the element where the Extensions element should be included. 170 * @return void 171 */ 172 private function addExtensions(Configuration $metadata, RoleDescriptor $e) 173 { 174 if ($metadata->hasValue('tags')) { 175 $a = new Attribute(); 176 $a->setName('tags'); 177 foreach ($metadata->getArray('tags') as $tag) { 178 $a->addAttributeValue(new AttributeValue($tag)); 179 } 180 $e->setExtensions(array_merge($e->getExtensions(), [$a])); 181 } 182 183 if ($metadata->hasValue('hint.cidr')) { 184 $a = new Attribute(); 185 $a->setName('hint.cidr'); 186 foreach ($metadata->getArray('hint.cidr') as $hint) { 187 $a->addAttributeValue(new AttributeValue($hint)); 188 } 189 $e->setExtensions(array_merge($e->getExtensions(), [$a])); 190 } 191 192 if ($metadata->hasValue('scope')) { 193 foreach ($metadata->getArray('scope') as $scopetext) { 194 $s = new Scope(); 195 $s->setScope($scopetext); 196 // Check whether $ ^ ( ) * | \ are in a scope -> assume regex. 197 if (1 === preg_match('/[\$\^\)\(\*\|\\\\]/', $scopetext)) { 198 $s->setIsRegexpScope(true); 199 } else { 200 $s->setIsRegexpScope(false); 201 } 202 $e->setExtensions(array_merge($e->getExtensions(), [$s])); 203 } 204 } 205 206 if ($metadata->hasValue('EntityAttributes')) { 207 $ea = new EntityAttributes(); 208 foreach ($metadata->getArray('EntityAttributes') as $attributeName => $attributeValues) { 209 $a = new Attribute(); 210 $a->setName($attributeName); 211 $a->setNameFormat('urn:oasis:names:tc:SAML:2.0:attrname-format:uri'); 212 213 // Attribute names that is not URI is prefixed as this: '{nameformat}name' 214 if (preg_match('/^\{(.*?)\}(.*)$/', $attributeName, $matches)) { 215 $a->setName($matches[2]); 216 $nameFormat = $matches[1]; 217 if ($nameFormat !== Constants::NAMEFORMAT_UNSPECIFIED) { 218 $a->setNameFormat($nameFormat); 219 } 220 } 221 foreach ($attributeValues as $attributeValue) { 222 $a->addAttributeValue(new AttributeValue($attributeValue)); 223 } 224 $ea->addChildren($a); 225 } 226 $this->entityDescriptor->setExtensions( 227 array_merge($this->entityDescriptor->getExtensions(), [$ea]) 228 ); 229 } 230 231 if ($metadata->hasValue('RegistrationInfo')) { 232 $ri = new RegistrationInfo(); 233 foreach ($metadata->getArray('RegistrationInfo') as $riName => $riValues) { 234 switch ($riName) { 235 case 'authority': 236 $ri->setRegistrationAuthority($riValues); 237 break; 238 case 'instant': 239 $ri->setRegistrationInstant(\SAML2\Utils::xsDateTimeToTimestamp($riValues)); 240 break; 241 case 'policies': 242 $ri->setRegistrationPolicy($riValues); 243 break; 244 } 245 } 246 $this->entityDescriptor->setExtensions( 247 array_merge($this->entityDescriptor->getExtensions(), [$ri]) 248 ); 249 } 250 251 if ($metadata->hasValue('UIInfo')) { 252 $ui = new UIInfo(); 253 foreach ($metadata->getArray('UIInfo') as $uiName => $uiValues) { 254 switch ($uiName) { 255 case 'DisplayName': 256 $ui->setDisplayName($uiValues); 257 break; 258 case 'Description': 259 $ui->setDescription($uiValues); 260 break; 261 case 'InformationURL': 262 $ui->setInformationURL($uiValues); 263 break; 264 case 'PrivacyStatementURL': 265 $ui->setPrivacyStatementURL($uiValues); 266 break; 267 case 'Keywords': 268 foreach ($uiValues as $lang => $keywords) { 269 $uiItem = new Keywords(); 270 $uiItem->setLanguage($lang); 271 $uiItem->setKeywords($keywords); 272 $ui->addKeyword($uiItem); 273 } 274 break; 275 case 'Logo': 276 foreach ($uiValues as $logo) { 277 $uiItem = new Logo(); 278 $uiItem->setUrl($logo['url']); 279 $uiItem->setWidth($logo['width']); 280 $uiItem->setHeight($logo['height']); 281 if (isset($logo['lang'])) { 282 $uiItem->setLanguage($logo['lang']); 283 } 284 $ui->addLogo($uiItem); 285 } 286 break; 287 } 288 } 289 $e->setExtensions(array_merge($e->getExtensions(), [$ui])); 290 } 291 292 if ($metadata->hasValue('DiscoHints')) { 293 $dh = new DiscoHints(); 294 foreach ($metadata->getArray('DiscoHints') as $dhName => $dhValues) { 295 switch ($dhName) { 296 case 'IPHint': 297 $dh->setIPHint($dhValues); 298 break; 299 case 'DomainHint': 300 $dh->setDomainHint($dhValues); 301 break; 302 case 'GeolocationHint': 303 $dh->setGeolocationHint($dhValues); 304 break; 305 } 306 } 307 $e->setExtensions(array_merge($e->getExtensions(), [$dh])); 308 } 309 } 310 311 312 /** 313 * Add an Organization element based on data passed as parameters 314 * 315 * @param array $orgName An array with the localized OrganizationName. 316 * @param array $orgDisplayName An array with the localized OrganizationDisplayName. 317 * @param array $orgURL An array with the localized OrganizationURL. 318 * @return void 319 */ 320 public function addOrganization(array $orgName, array $orgDisplayName, array $orgURL) 321 { 322 $org = new Organization(); 323 324 $org->setOrganizationName($orgName); 325 $org->setOrganizationDisplayName($orgDisplayName); 326 $org->setOrganizationURL($orgURL); 327 328 $this->entityDescriptor->setOrganization($org); 329 } 330 331 332 /** 333 * Add an Organization element based on metadata array. 334 * 335 * @param array $metadata The metadata we should extract the organization information from. 336 * @return void 337 */ 338 public function addOrganizationInfo(array $metadata) 339 { 340 if ( 341 empty($metadata['OrganizationName']) || 342 empty($metadata['OrganizationDisplayName']) || 343 empty($metadata['OrganizationURL']) 344 ) { 345 // empty or incomplete organization information 346 return; 347 } 348 349 $orgName = Utils\Arrays::arrayize($metadata['OrganizationName'], 'en'); 350 $orgDisplayName = Utils\Arrays::arrayize($metadata['OrganizationDisplayName'], 'en'); 351 $orgURL = Utils\Arrays::arrayize($metadata['OrganizationURL'], 'en'); 352 353 $this->addOrganization($orgName, $orgDisplayName, $orgURL); 354 } 355 356 357 /** 358 * Add a list of endpoints to metadata. 359 * 360 * @param array $endpoints The endpoints. 361 * @param bool $indexed Whether the endpoints should be indexed. 362 * 363 * @return array An array of endpoint objects, 364 * either \SAML2\XML\md\EndpointType or \SAML2\XML\md\IndexedEndpointType. 365 */ 366 private static function createEndpoints(array $endpoints, $indexed) 367 { 368 assert(is_bool($indexed)); 369 370 $ret = []; 371 372 foreach ($endpoints as &$ep) { 373 if ($indexed) { 374 $t = new IndexedEndpointType(); 375 if (!isset($ep['index'])) { 376 // Find the maximum index 377 $maxIndex = -1; 378 foreach ($endpoints as $ep) { 379 if (!isset($ep['index'])) { 380 continue; 381 } 382 383 if ($ep['index'] > $maxIndex) { 384 $maxIndex = $ep['index']; 385 } 386 } 387 388 $ep['index'] = $maxIndex + 1; 389 } 390 391 $t->setIndex($ep['index']); 392 } else { 393 $t = new EndpointType(); 394 } 395 396 $t->setBinding($ep['Binding']); 397 $t->setLocation($ep['Location']); 398 if (isset($ep['ResponseLocation'])) { 399 $t->setResponseLocation($ep['ResponseLocation']); 400 } 401 if (isset($ep['hoksso:ProtocolBinding'])) { 402 $t->setAttributeNS( 403 Constants::NS_HOK, 404 'hoksso:ProtocolBinding', 405 Constants::BINDING_HTTP_REDIRECT 406 ); 407 } 408 409 $ret[] = $t; 410 } 411 412 return $ret; 413 } 414 415 416 /** 417 * Add an AttributeConsumingService element to the metadata. 418 * 419 * @param \SAML2\XML\md\SPSSODescriptor $spDesc The SPSSODescriptor element. 420 * @param \SimpleSAML\Configuration $metadata The metadata. 421 * @return void 422 */ 423 private function addAttributeConsumingService( 424 SPSSODescriptor $spDesc, 425 Configuration $metadata 426 ) { 427 $attributes = $metadata->getArray('attributes', []); 428 $name = $metadata->getLocalizedString('name', null); 429 430 if ($name === null || count($attributes) == 0) { 431 // we cannot add an AttributeConsumingService without name and attributes 432 return; 433 } 434 435 $attributesrequired = $metadata->getArray('attributes.required', []); 436 437 /* 438 * Add an AttributeConsumingService element with information as name and description and list 439 * of requested attributes 440 */ 441 $attributeconsumer = new AttributeConsumingService(); 442 443 $attributeconsumer->setIndex($metadata->getInteger('attributes.index', 0)); 444 445 if ($metadata->hasValue('attributes.isDefault')) { 446 $attributeconsumer->setIsDefault($metadata->getBoolean('attributes.isDefault', false)); 447 } 448 449 $attributeconsumer->setServiceName($name); 450 $attributeconsumer->setServiceDescription($metadata->getLocalizedString('description', [])); 451 452 $nameFormat = $metadata->getString('attributes.NameFormat', Constants::NAMEFORMAT_UNSPECIFIED); 453 foreach ($attributes as $friendlyName => $attribute) { 454 $t = new RequestedAttribute(); 455 $t->setName($attribute); 456 if (!is_int($friendlyName)) { 457 $t->setFriendlyName($friendlyName); 458 } 459 if ($nameFormat !== Constants::NAMEFORMAT_UNSPECIFIED) { 460 $t->setNameFormat($nameFormat); 461 } 462 if (in_array($attribute, $attributesrequired, true)) { 463 $t->setIsRequired(true); 464 } 465 $attributeconsumer->addRequestedAttribute($t); 466 } 467 468 $spDesc->addAttributeConsumingService($attributeconsumer); 469 } 470 471 472 /** 473 * Add a specific type of metadata to an entity. 474 * 475 * @param string $set The metadata set this metadata comes from. 476 * @param array $metadata The metadata. 477 * @return void 478 */ 479 public function addMetadata($set, $metadata) 480 { 481 assert(is_string($set)); 482 assert(is_array($metadata)); 483 484 $this->setExpiration($metadata); 485 486 switch ($set) { 487 case 'saml20-sp-remote': 488 $this->addMetadataSP20($metadata); 489 break; 490 case 'saml20-idp-remote': 491 $this->addMetadataIdP20($metadata); 492 break; 493 case 'shib13-sp-remote': 494 $this->addMetadataSP11($metadata); 495 break; 496 case 'shib13-idp-remote': 497 $this->addMetadataIdP11($metadata); 498 break; 499 case 'attributeauthority-remote': 500 $this->addAttributeAuthority($metadata); 501 break; 502 default: 503 Logger::warning('Unable to generate metadata for unknown type \'' . $set . '\'.'); 504 } 505 } 506 507 508 /** 509 * Add SAML 2.0 SP metadata. 510 * 511 * @param array $metadata The metadata. 512 * @param array $protocols The protocols supported. Defaults to \SAML2\Constants::NS_SAMLP. 513 * @return void 514 */ 515 public function addMetadataSP20($metadata, $protocols = [Constants::NS_SAMLP]) 516 { 517 assert(is_array($metadata)); 518 assert(is_array($protocols)); 519 assert(isset($metadata['entityid'])); 520 assert(isset($metadata['metadata-set'])); 521 522 $metadata = Configuration::loadFromArray($metadata, $metadata['entityid']); 523 524 $e = new SPSSODescriptor(); 525 $e->setProtocolSupportEnumeration($protocols); 526 527 if ($metadata->hasValue('saml20.sign.assertion')) { 528 $e->setWantAssertionsSigned($metadata->getBoolean('saml20.sign.assertion')); 529 } 530 531 if ($metadata->hasValue('redirect.validate')) { 532 $e->setAuthnRequestsSigned($metadata->getBoolean('redirect.validate')); 533 } elseif ($metadata->hasValue('validate.authnrequest')) { 534 $e->setAuthnRequestsSigned($metadata->getBoolean('validate.authnrequest')); 535 } 536 537 $this->addExtensions($metadata, $e); 538 539 $this->addCertificate($e, $metadata); 540 541 $e->setSingleLogoutService(self::createEndpoints($metadata->getEndpoints('SingleLogoutService'), false)); 542 543 $e->setNameIDFormat($metadata->getArrayizeString('NameIDFormat', [])); 544 545 $endpoints = $metadata->getEndpoints('AssertionConsumerService'); 546 foreach ($metadata->getArrayizeString('AssertionConsumerService.artifact', []) as $acs) { 547 $endpoints[] = [ 548 'Binding' => Constants::BINDING_HTTP_ARTIFACT, 549 'Location' => $acs, 550 ]; 551 } 552 $e->setAssertionConsumerService(self::createEndpoints($endpoints, true)); 553 554 $this->addAttributeConsumingService($e, $metadata); 555 556 $this->entityDescriptor->addRoleDescriptor($e); 557 558 foreach ($metadata->getArray('contacts', []) as $contact) { 559 if (array_key_exists('contactType', $contact) && array_key_exists('emailAddress', $contact)) { 560 $this->addContact($contact['contactType'], Utils\Config\Metadata::getContact($contact)); 561 } 562 } 563 } 564 565 566 /** 567 * Add metadata of a SAML 2.0 identity provider. 568 * 569 * @param array $metadata The metadata. 570 * @return void 571 */ 572 public function addMetadataIdP20($metadata) 573 { 574 assert(is_array($metadata)); 575 assert(isset($metadata['entityid'])); 576 assert(isset($metadata['metadata-set'])); 577 578 $metadata = Configuration::loadFromArray($metadata, $metadata['entityid']); 579 580 $e = new IDPSSODescriptor(); 581 $e->setProtocolSupportEnumeration(array_merge($e->getProtocolSupportEnumeration(), [Constants::NS_SAMLP])); 582 583 if ($metadata->hasValue('sign.authnrequest')) { 584 $e->setWantAuthnRequestsSigned($metadata->getBoolean('sign.authnrequest')); 585 } elseif ($metadata->hasValue('redirect.sign')) { 586 $e->setWantAuthnRequestsSigned($metadata->getBoolean('redirect.sign')); 587 } 588 589 $this->addExtensions($metadata, $e); 590 591 $this->addCertificate($e, $metadata); 592 593 if ($metadata->hasValue('ArtifactResolutionService')) { 594 $e->setArtifactResolutionService(self::createEndpoints( 595 $metadata->getEndpoints('ArtifactResolutionService'), 596 true 597 )); 598 } 599 600 $e->setSingleLogoutService(self::createEndpoints($metadata->getEndpoints('SingleLogoutService'), false)); 601 602 $e->setNameIDFormat($metadata->getArrayizeString('NameIDFormat', [])); 603 604 $e->setSingleSignOnService(self::createEndpoints($metadata->getEndpoints('SingleSignOnService'), false)); 605 606 $this->entityDescriptor->addRoleDescriptor($e); 607 608 foreach ($metadata->getArray('contacts', []) as $contact) { 609 if (array_key_exists('contactType', $contact) && array_key_exists('emailAddress', $contact)) { 610 $this->addContact($contact['contactType'], Utils\Config\Metadata::getContact($contact)); 611 } 612 } 613 } 614 615 616 /** 617 * Add metadata of a SAML 1.1 service provider. 618 * 619 * @param array $metadata The metadata. 620 * @return void 621 */ 622 public function addMetadataSP11($metadata) 623 { 624 assert(is_array($metadata)); 625 assert(isset($metadata['entityid'])); 626 assert(isset($metadata['metadata-set'])); 627 628 $metadata = Configuration::loadFromArray($metadata, $metadata['entityid']); 629 630 $e = new SPSSODescriptor(); 631 $e->setProtocolSupportEnumeration( 632 array_merge( 633 $e->getProtocolSupportEnumeration(), 634 ['urn:oasis:names:tc:SAML:1.1:protocol'] 635 ) 636 ); 637 638 $this->addCertificate($e, $metadata); 639 640 $e->setNameIDFormat($metadata->getArrayizeString('NameIDFormat', [])); 641 642 $endpoints = $metadata->getEndpoints('AssertionConsumerService'); 643 foreach ($metadata->getArrayizeString('AssertionConsumerService.artifact', []) as $acs) { 644 $endpoints[] = [ 645 'Binding' => 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01', 646 'Location' => $acs, 647 ]; 648 } 649 $e->setAssertionConsumerService(self::createEndpoints($endpoints, true)); 650 651 $this->addAttributeConsumingService($e, $metadata); 652 653 $this->entityDescriptor->addRoleDescriptor($e); 654 } 655 656 657 /** 658 * Add metadata of a SAML 1.1 identity provider. 659 * 660 * @param array $metadata The metadata. 661 * @return void 662 */ 663 public function addMetadataIdP11($metadata) 664 { 665 assert(is_array($metadata)); 666 assert(isset($metadata['entityid'])); 667 assert(isset($metadata['metadata-set'])); 668 669 $metadata = Configuration::loadFromArray($metadata, $metadata['entityid']); 670 671 $e = new IDPSSODescriptor(); 672 $e->setProtocolSupportEnumeration( 673 array_merge($e->getProtocolSupportEnumeration(), [ 674 'urn:oasis:names:tc:SAML:1.1:protocol', 675 'urn:mace:shibboleth:1.0' 676 ]) 677 ); 678 679 $this->addCertificate($e, $metadata); 680 681 $e->setNameIDFormat($metadata->getArrayizeString('NameIDFormat', [])); 682 683 $e->setSingleSignOnService(self::createEndpoints($metadata->getEndpoints('SingleSignOnService'), false)); 684 685 $this->entityDescriptor->addRoleDescriptor($e); 686 } 687 688 689 /** 690 * Add metadata of a SAML attribute authority. 691 * 692 * @param array $metadata The AttributeAuthorityDescriptor, in the format returned by 693 * \SimpleSAML\Metadata\SAMLParser. 694 * @return void 695 */ 696 public function addAttributeAuthority(array $metadata) 697 { 698 assert(is_array($metadata)); 699 assert(isset($metadata['entityid'])); 700 assert(isset($metadata['metadata-set'])); 701 702 $metadata = Configuration::loadFromArray($metadata, $metadata['entityid']); 703 704 $e = new AttributeAuthorityDescriptor(); 705 $e->setProtocolSupportEnumeration($metadata->getArray('protocols', [Constants::NS_SAMLP])); 706 707 $this->addExtensions($metadata, $e); 708 $this->addCertificate($e, $metadata); 709 710 $e->setAttributeService(self::createEndpoints($metadata->getEndpoints('AttributeService'), false)); 711 $e->setAssertionIDRequestService(self::createEndpoints( 712 $metadata->getEndpoints('AssertionIDRequestService'), 713 false 714 )); 715 716 $e->setNameIDFormat($metadata->getArrayizeString('NameIDFormat', [])); 717 718 $this->entityDescriptor->addRoleDescriptor($e); 719 } 720 721 722 /** 723 * Add contact information. 724 * 725 * Accepts a contact type, and a contact array that must be previously sanitized. 726 * 727 * WARNING: This function will change its signature and no longer parse a 'name' element. 728 * 729 * @param string $type The type of contact. Deprecated. 730 * @param array $details The details about the contact. 731 * 732 * @return void 733 * @todo Change the signature to remove $type. 734 * @todo Remove the capability to pass a name and parse it inside the method. 735 */ 736 public function addContact($type, $details) 737 { 738 assert(is_string($type)); 739 assert(is_array($details)); 740 assert(in_array($type, ['technical', 'support', 'administrative', 'billing', 'other'], true)); 741 742 // TODO: remove this check as soon as getContact() is called always before calling this function 743 $details = Utils\Config\Metadata::getContact($details); 744 745 $e = new \SAML2\XML\md\ContactPerson(); 746 $e->setContactType($type); 747 748 if (!empty($details['attributes'])) { 749 $e->setContactPersonAttributes($details['attributes']); 750 } 751 752 if (isset($details['company'])) { 753 $e->setCompany($details['company']); 754 } 755 if (isset($details['givenName'])) { 756 $e->setGivenName($details['givenName']); 757 } 758 if (isset($details['surName'])) { 759 $e->setSurName($details['surName']); 760 } 761 762 if (isset($details['emailAddress'])) { 763 $eas = $details['emailAddress']; 764 if (!is_array($eas)) { 765 $eas = [$eas]; 766 } 767 foreach ($eas as $ea) { 768 $e->addEmailAddress($ea); 769 } 770 } 771 772 if (isset($details['telephoneNumber'])) { 773 $tlfNrs = $details['telephoneNumber']; 774 if (!is_array($tlfNrs)) { 775 $tlfNrs = [$tlfNrs]; 776 } 777 foreach ($tlfNrs as $tlfNr) { 778 $e->addTelephoneNumber($tlfNr); 779 } 780 } 781 782 $this->entityDescriptor->addContactPerson($e); 783 } 784 785 786 /** 787 * Add a KeyDescriptor with an X509 certificate. 788 * 789 * @param \SAML2\XML\md\RoleDescriptor $rd The RoleDescriptor the certificate should be added to. 790 * @param string $use The value of the 'use' attribute. 791 * @param string $x509data The certificate data. 792 * @return void 793 */ 794 private function addX509KeyDescriptor(RoleDescriptor $rd, $use, $x509data) 795 { 796 assert(in_array($use, ['encryption', 'signing'], true)); 797 assert(is_string($x509data)); 798 799 $keyDescriptor = \SAML2\Utils::createKeyDescriptor($x509data); 800 $keyDescriptor->setUse($use); 801 $rd->addKeyDescriptor($keyDescriptor); 802 } 803 804 805 /** 806 * Add a certificate. 807 * 808 * Helper function for adding a certificate to the metadata. 809 * 810 * @param \SAML2\XML\md\RoleDescriptor $rd The RoleDescriptor the certificate should be added to. 811 * @param \SimpleSAML\Configuration $metadata The metadata of the entity. 812 * @return void 813 */ 814 private function addCertificate(RoleDescriptor $rd, Configuration $metadata) 815 { 816 $keys = $metadata->getPublicKeys(); 817 foreach ($keys as $key) { 818 if ($key['type'] !== 'X509Certificate') { 819 continue; 820 } 821 if (!isset($key['signing']) || $key['signing'] === true) { 822 $this->addX509KeyDescriptor($rd, 'signing', $key['X509Certificate']); 823 } 824 if (!isset($key['encryption']) || $key['encryption'] === true) { 825 $this->addX509KeyDescriptor($rd, 'encryption', $key['X509Certificate']); 826 } 827 } 828 829 if ($metadata->hasValue('https.certData')) { 830 $this->addX509KeyDescriptor($rd, 'signing', $metadata->getString('https.certData')); 831 } 832 } 833} 834