49        assert(
'is_string($entityId)');
 
   54        $this->entityDescriptor = new \SAML2\XML\md\EntityDescriptor();
 
   55        $this->entityDescriptor->entityID = 
$entityId;
 
   61        if (array_key_exists(
'expire', 
$metadata)) {
 
   62            if (
$metadata[
'expire'] - time() < $this->maxDuration) {
 
   63                $this->maxDuration = 
$metadata[
'expire'] - time();
 
   67        if ($this->maxCache !== 
null) {
 
   68            $this->entityDescriptor->cacheDuration = 
'PT'.$this->maxCache.
'S';
 
   70        if ($this->maxDuration !== 
null) {
 
   83        $xml = $this->entityDescriptor->toXML();
 
   84        $xml->ownerDocument->appendChild(
$xml);
 
  101        assert(
'is_bool($formatted)');
 
  105            SimpleSAML\Utils\XML::formatDOMElement(
$xml);
 
  108        return $xml->ownerDocument->saveXML();
 
  119        assert(
'is_array($metadata)');
 
  120        assert(
'isset($metadata["entityid"])');
 
  121        assert(
'isset($metadata["metadata-set"])');
 
  124        $defaultEndpoint = 
$metadata->getDefaultEndpoint(
'SingleSignOnService');
 
  126        $e->Location = $defaultEndpoint[
'Location'];
 
  130        $this->entityDescriptor->RoleDescriptor[] = $e;
 
  143            $a = new \SAML2\XML\saml\Attribute();
 
  146                $a->AttributeValue[] = new \SAML2\XML\saml\AttributeValue(
$tag);
 
  148            $e->Extensions[] = $a;
 
  152            $a = new \SAML2\XML\saml\Attribute();
 
  153            $a->Name = 
'hint.cidr';
 
  154            foreach (
$metadata->getArray(
'hint.cidr') as $hint) {
 
  155                $a->AttributeValue[] = new \SAML2\XML\saml\AttributeValue($hint);
 
  157            $e->Extensions[] = $a;
 
  161            foreach (
$metadata->getArray(
'scope') as $scopetext) {
 
  162                $s = new \SAML2\XML\shibmd\Scope();
 
  163                $s->scope = $scopetext;
 
  165                if (1 === preg_match(
'/[\$\^\)\(\*\|\\\\]/', $scopetext)) {
 
  170                $e->Extensions[] = 
$s;
 
  174        if (
$metadata->hasValue(
'EntityAttributes')) {
 
  175            $ea = new \SAML2\XML\mdattr\EntityAttributes();
 
  176            foreach (
$metadata->getArray(
'EntityAttributes') as $attributeName => $attributeValues) {
 
  177                $a = new \SAML2\XML\saml\Attribute();
 
  178                $a->Name = $attributeName;
 
  179                $a->NameFormat = 
'urn:oasis:names:tc:SAML:2.0:attrname-format:uri';
 
  182                if (preg_match(
'/^\{(.*?)\}(.*)$/', $attributeName, $matches)) {
 
  183                    $a->Name = $matches[2];
 
  184                    $nameFormat = $matches[1];
 
  185                    if ($nameFormat !== \
SAML2\Constants::NAMEFORMAT_UNSPECIFIED) {
 
  186                        $a->NameFormat = $nameFormat;
 
  189                foreach ($attributeValues as $attributeValue) {
 
  190                    $a->AttributeValue[] = new \SAML2\XML\saml\AttributeValue($attributeValue);
 
  192                $ea->children[] = $a;
 
  194            $this->entityDescriptor->Extensions[] = $ea;
 
  197        if (
$metadata->hasValue(
'RegistrationInfo')) {
 
  198            $ri = new \SAML2\XML\mdrpi\RegistrationInfo();
 
  199            foreach (
$metadata->getArray(
'RegistrationInfo') as $riName => $riValues) {
 
  202                        $ri->registrationAuthority = $riValues;
 
  208                        $ri->RegistrationPolicy = $riValues;
 
  212            $this->entityDescriptor->Extensions[] = $ri;
 
  216            $ui = new \SAML2\XML\mdui\UIInfo();
 
  217            foreach (
$metadata->getArray(
'UIInfo') as $uiName => $uiValues) {
 
  220                        $ui->DisplayName = $uiValues;
 
  223                        $ui->Description = $uiValues;
 
  225                    case 'InformationURL':
 
  226                        $ui->InformationURL = $uiValues;
 
  228                    case 'PrivacyStatementURL':
 
  229                        $ui->PrivacyStatementURL = $uiValues;
 
  232                        foreach ($uiValues as 
$lang => $keywords) {
 
  233                            $uiItem = new \SAML2\XML\mdui\Keywords();
 
  234                            $uiItem->lang = 
$lang;
 
  235                            $uiItem->Keywords = $keywords;
 
  236                            $ui->Keywords[] = $uiItem;
 
  240                        foreach ($uiValues as $logo) {
 
  241                            $uiItem = new \SAML2\XML\mdui\Logo();
 
  242                            $uiItem->url = $logo[
'url'];
 
  243                            $uiItem->width = $logo[
'width'];
 
  244                            $uiItem->height = $logo[
'height'];
 
  245                            if (isset($logo[
'lang'])) {
 
  246                                $uiItem->lang = $logo[
'lang'];
 
  248                            $ui->Logo[] = $uiItem;
 
  253            $e->Extensions[] = $ui;
 
  257            $dh = new \SAML2\XML\mdui\DiscoHints();
 
  258            foreach (
$metadata->getArray(
'DiscoHints') as $dhName => $dhValues) {
 
  261                        $dh->IPHint = $dhValues;
 
  264                        $dh->DomainHint = $dhValues;
 
  266                    case 'GeolocationHint':
 
  267                        $dh->GeolocationHint = $dhValues;
 
  271            $e->Extensions[] = $dh;
 
  285        $org = new \SAML2\XML\md\Organization();
 
  288        $org->OrganizationDisplayName = $orgDisplayName;
 
  289        $org->OrganizationURL = $orgURL;
 
  291        $this->entityDescriptor->Organization = $org;
 
  304            empty(
$metadata[
'OrganizationDisplayName']) ||
 
  329        assert(
'is_bool($indexed)');
 
  333        foreach ($endpoints as &$ep) {
 
  335                $t = new \SAML2\XML\md\IndexedEndpointType();
 
  337                $t = new \SAML2\XML\md\EndpointType();
 
  340            $t->Binding = $ep[
'Binding'];
 
  341            $t->Location = $ep[
'Location'];
 
  342            if (isset($ep[
'ResponseLocation'])) {
 
  343                $t->ResponseLocation = $ep[
'ResponseLocation'];
 
  345            if (isset($ep[
'hoksso:ProtocolBinding'])) {
 
  347                    \
SAML2\Constants::NS_HOK,
 
  348                    'hoksso:ProtocolBinding',
 
  349                    \
SAML2\Constants::BINDING_HTTP_REDIRECT
 
  354                if (!isset($ep[
'index'])) {
 
  357                    foreach ($endpoints as $ep) {
 
  358                        if (!isset($ep[
'index'])) {
 
  362                        if ($ep[
'index'] > $maxIndex) {
 
  363                            $maxIndex = $ep[
'index'];
 
  367                    $ep[
'index'] = $maxIndex + 1;
 
  370                $t->index = $ep[
'index'];
 
  387        \
SAML2\XML\md\SPSSODescriptor $spDesc,
 
  398        $attributesrequired = 
$metadata->getArray(
'attributes.required', array());
 
  404        $attributeconsumer = new \SAML2\XML\md\AttributeConsumingService();
 
  406        $attributeconsumer->index = 0;
 
  408        $attributeconsumer->ServiceName = 
$name;
 
  409        $attributeconsumer->ServiceDescription = 
$metadata->getLocalizedString(
'description', array());
 
  411        $nameFormat = 
$metadata->getString(
'attributes.NameFormat', \
SAML2\Constants::NAMEFORMAT_UNSPECIFIED);
 
  412        foreach (
$attributes as $friendlyName => $attribute) {
 
  413            $t = new \SAML2\XML\md\RequestedAttribute();
 
  414            $t->Name = $attribute;
 
  415            if (!is_int($friendlyName)) {
 
  416                $t->FriendlyName = $friendlyName;
 
  418            if ($nameFormat !== \
SAML2\Constants::NAMEFORMAT_UNSPECIFIED) {
 
  419                $t->NameFormat = $nameFormat;
 
  421            if (in_array($attribute, $attributesrequired, 
true)) {
 
  422                $t->isRequired = 
true;
 
  424            $attributeconsumer->RequestedAttribute[] = 
$t;
 
  427        $spDesc->AttributeConsumingService[] = $attributeconsumer;
 
  439        assert(
'is_string($set)');
 
  440        assert(
'is_array($metadata)');
 
  445            case 'saml20-sp-remote':
 
  448            case 'saml20-idp-remote':
 
  451            case 'shib13-sp-remote':
 
  454            case 'shib13-idp-remote':
 
  457            case 'attributeauthority-remote':
 
  472    public function addMetadataSP20($metadata, $protocols = array(\SAML2\Constants::NS_SAMLP)) 
  475        assert('is_array($protocols)
'); 
  477        assert('isset(
$metadata[
"metadata-set"])
'); 
  479        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid
']); 
  481        $e = new \SAML2\XML\md\SPSSODescriptor(); 
  482        $e->protocolSupportEnumeration = $protocols; 
  484        if ($metadata->hasValue('saml20.sign.assertion
')) { 
  485            $e->WantAssertionsSigned = $metadata->getBoolean('saml20.sign.assertion
'); 
  488        if ($metadata->hasValue('redirect.validate
')) { 
  489            $e->AuthnRequestsSigned = $metadata->getBoolean('redirect.validate
'); 
  490        } elseif ($metadata->hasValue('validate.authnrequest
')) { 
  491            $e->AuthnRequestsSigned = $metadata->getBoolean('validate.authnrequest
'); 
  494        $this->addExtensions($metadata, $e); 
  496        $this->addCertificate($e, $metadata); 
  498        $e->SingleLogoutService = self::createEndpoints($metadata->getEndpoints('SingleLogoutService
'), false); 
  500        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat
', array()); 
  502        $endpoints = $metadata->getEndpoints('AssertionConsumerService
'); 
  503        foreach ($metadata->getArrayizeString('AssertionConsumerService.artifact
', array()) as $acs) { 
  504            $endpoints[] = array( 
  505                'Binding
'  => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact
', 
  509        $e->AssertionConsumerService = self::createEndpoints($endpoints, true); 
  511        $this->addAttributeConsumingService($e, $metadata); 
  513        $this->entityDescriptor->RoleDescriptor[] = $e; 
  515        foreach ($metadata->getArray('contacts
', array()) as $contact) { 
  516            if (array_key_exists('contactType
', $contact) && array_key_exists('emailAddress
', $contact)) { 
  517                $this->addContact($contact['contactType
'], \SimpleSAML\Utils\Config\Metadata::getContact($contact)); 
  528    public function addMetadataIdP20($metadata) 
  532        assert('isset(
$metadata[
"metadata-set"])
'); 
  534        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid
']); 
  536        $e = new \SAML2\XML\md\IDPSSODescriptor(); 
  537        $e->protocolSupportEnumeration[] = 'urn:oasis:names:tc:SAML:2.0:protocol
'; 
  539        if ($metadata->hasValue('sign.authnrequest
')) { 
  540            $e->WantAuthnRequestsSigned = $metadata->getBoolean('sign.authnrequest
'); 
  541        } elseif ($metadata->hasValue('redirect.sign
')) { 
  542            $e->WantAuthnRequestsSigned = $metadata->getBoolean('redirect.sign
'); 
  545        $this->addExtensions($metadata, $e); 
  547        $this->addCertificate($e, $metadata); 
  549        if ($metadata->hasValue('ArtifactResolutionService
')) { 
  550            $e->ArtifactResolutionService = self::createEndpoints( 
  551                $metadata->getEndpoints('ArtifactResolutionService
'), 
  556        $e->SingleLogoutService = self::createEndpoints($metadata->getEndpoints('SingleLogoutService
'), false); 
  558        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat
', array()); 
  560        $e->SingleSignOnService = self::createEndpoints($metadata->getEndpoints('SingleSignOnService
'), false); 
  562        $this->entityDescriptor->RoleDescriptor[] = $e; 
  564        foreach ($metadata->getArray('contacts
', array()) as $contact) { 
  565            if (array_key_exists('contactType
', $contact) && array_key_exists('emailAddress
', $contact)) { 
  566                $this->addContact($contact['contactType
'], \SimpleSAML\Utils\Config\Metadata::getContact($contact)); 
  577    public function addMetadataSP11($metadata) 
  581        assert('isset(
$metadata[
"metadata-set"])
'); 
  583        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid
']); 
  585        $e = new \SAML2\XML\md\SPSSODescriptor(); 
  586        $e->protocolSupportEnumeration[] = 'urn:oasis:names:tc:SAML:1.1:protocol
'; 
  588        $this->addCertificate($e, $metadata); 
  590        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat
', array()); 
  592        $endpoints = $metadata->getEndpoints('AssertionConsumerService
'); 
  593        foreach ($metadata->getArrayizeString('AssertionConsumerService.artifact
', array()) as $acs) { 
  594            $endpoints[] = array( 
  595                'Binding
'  => 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01
', 
  599        $e->AssertionConsumerService = self::createEndpoints($endpoints, true); 
  601        $this->addAttributeConsumingService($e, $metadata); 
  603        $this->entityDescriptor->RoleDescriptor[] = $e; 
  612    public function addMetadataIdP11($metadata) 
  616        assert('isset(
$metadata[
"metadata-set"])
'); 
  618        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid
']); 
  620        $e = new \SAML2\XML\md\IDPSSODescriptor(); 
  621        $e->protocolSupportEnumeration[] = 'urn:oasis:names:tc:SAML:1.1:protocol
'; 
  622        $e->protocolSupportEnumeration[] = 'urn:mace:shibboleth:1.0
'; 
  624        $this->addCertificate($e, $metadata); 
  626        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat
', array()); 
  628        $e->SingleSignOnService = self::createEndpoints($metadata->getEndpoints('SingleSignOnService
'), false); 
  630        $this->entityDescriptor->RoleDescriptor[] = $e; 
  640    public function addAttributeAuthority(array $metadata) 
  644        assert('isset(
$metadata[
"metadata-set"])
'); 
  646        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid
']); 
  648        $e = new \SAML2\XML\md\AttributeAuthorityDescriptor(); 
  649        $e->protocolSupportEnumeration = $metadata->getArray('protocols
', array(\SAML2\Constants::NS_SAMLP)); 
  651        $this->addExtensions($metadata, $e); 
  652        $this->addCertificate($e, $metadata); 
  654        $e->AttributeService = self::createEndpoints($metadata->getEndpoints('AttributeService
'), false); 
  655        $e->AssertionIDRequestService = self::createEndpoints( 
  656            $metadata->getEndpoints('AssertionIDRequestService
'), 
  660        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat
', array()); 
  662        $this->entityDescriptor->RoleDescriptor[] = $e; 
  679    public function addContact($type, $details) 
  681        assert('is_string(
$type)
'); 
  682        assert('is_array($details)
'); 
  683        assert('in_array(
$type, array(
"technical", 
"support", 
"administrative", 
"billing", 
"other"), TRUE)
'); 
  685        // TODO: remove this check as soon as getContact() is called always before calling this function 
  686        $details = \SimpleSAML\Utils\Config\Metadata::getContact($details); 
  688        $e = new \SAML2\XML\md\ContactPerson(); 
  689        $e->contactType = $type; 
  691        if (!empty($details['attributes
'])) { 
  692            $e->ContactPersonAttributes = $details['attributes
']; 
  695        if (isset($details['company
'])) { 
  696            $e->Company = $details['company
']; 
  698        if (isset($details['givenName
'])) { 
  699            $e->GivenName = $details['givenName
']; 
  701        if (isset($details['surName
'])) { 
  702            $e->SurName = $details['surName
']; 
  705        if (isset($details['emailAddress
'])) { 
  706            $eas = $details['emailAddress
']; 
  707            if (!is_array($eas)) { 
  710            foreach ($eas as $ea) { 
  711                $e->EmailAddress[] = $ea; 
  715        if (isset($details['telephoneNumber
'])) { 
  716            $tlfNrs = $details['telephoneNumber
']; 
  717            if (!is_array($tlfNrs)) { 
  718                $tlfNrs = array($tlfNrs); 
  720            foreach ($tlfNrs as $tlfNr) { 
  721                $e->TelephoneNumber[] = $tlfNr; 
  725        $this->entityDescriptor->ContactPerson[] = $e; 
  736    private function addX509KeyDescriptor(\SAML2\XML\md\RoleDescriptor $rd, $use, $x509data) 
  738        assert('in_array($use, array(
"encryption", 
"signing"), TRUE)
'); 
  739        assert('is_string($x509data)
'); 
  741        $keyDescriptor = \SAML2\Utils::createKeyDescriptor($x509data); 
  742        $keyDescriptor->use = $use; 
  743        $rd->KeyDescriptor[] = $keyDescriptor; 
  755    private function addCertificate(\SAML2\XML\md\RoleDescriptor $rd, SimpleSAML_Configuration $metadata) 
  757        $keys = $metadata->getPublicKeys(); 
  758        if ($keys !== null) { 
  759            foreach ($keys as $key) { 
  760                if ($key['type
'] !== 'X509Certificate
') { 
  763                if (!isset($key['signing
']) || $key['signing
'] === true) { 
  764                    $this->addX509KeyDescriptor($rd, 'signing
', $key['X509Certificate
']); 
  766                if (!isset($key['encryption
']) || $key['encryption
'] === true) { 
  767                    $this->addX509KeyDescriptor($rd, 'encryption
', $key['X509Certificate
']); 
  772        if ($metadata->hasValue('https.certData
')) { 
  773            $this->addX509KeyDescriptor($rd, 'signing
', $metadata->getString('https.certData
')); 
$metadata['__DYNAMIC:1__']
An exception for terminatinating execution or to throw for unit testing.
static xsDateTimeToTimestamp($time)
This function converts a SAML2 timestamp on the form yyyy-mm-ddThh:mm:ss(.s+)?Z to a UNIX timestamp.
static arrayize($data, $index=0)
Put a non-array variable into an array.
static loadFromArray($config, $location='[ARRAY]', $instance=null)
Loads a configuration from the given array.
if(function_exists( 'posix_getuid') &&posix_getuid()===0) if(!array_key_exists('t', $options)) $tag