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();
 
  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;
 
  302        if (empty(
$metadata[
'OrganizationName']) ||
 
  303            empty(
$metadata[
'OrganizationDisplayName']) ||
 
  328        assert(is_bool($indexed));
 
  332        foreach ($endpoints as &$ep) {
 
  334                $t = new \SAML2\XML\md\IndexedEndpointType();
 
  336                $t = new \SAML2\XML\md\EndpointType();
 
  339            $t->Binding = $ep[
'Binding'];
 
  340            $t->Location = $ep[
'Location'];
 
  341            if (isset($ep[
'ResponseLocation'])) {
 
  342                $t->ResponseLocation = $ep[
'ResponseLocation'];
 
  344            if (isset($ep[
'hoksso:ProtocolBinding'])) {
 
  346                    \
SAML2\Constants::NS_HOK,
 
  347                    'hoksso:ProtocolBinding',
 
  348                    \
SAML2\Constants::BINDING_HTTP_REDIRECT
 
  353                if (!isset($ep[
'index'])) {
 
  356                    foreach ($endpoints as $ep) {
 
  357                        if (!isset($ep[
'index'])) {
 
  361                        if ($ep[
'index'] > $maxIndex) {
 
  362                            $maxIndex = $ep[
'index'];
 
  366                    $ep[
'index'] = $maxIndex + 1;
 
  369                $t->index = $ep[
'index'];
 
  386        \
SAML2\XML\md\SPSSODescriptor $spDesc,
 
  397        $attributesrequired = 
$metadata->getArray(
'attributes.required', array());
 
  403        $attributeconsumer = new \SAML2\XML\md\AttributeConsumingService();
 
  405        $attributeconsumer->index = 
$metadata->getInteger(
'attributes.index', 0);
 
  407        if (
$metadata->hasValue(
'attributes.isDefault')) {
 
  408            $attributeconsumer->isDefault = 
$metadata->getBoolean(
'attributes.isDefault', 
false);
 
  411        $attributeconsumer->ServiceName = 
$name;
 
  412        $attributeconsumer->ServiceDescription = 
$metadata->getLocalizedString(
'description', array());
 
  414        $nameFormat = 
$metadata->getString(
'attributes.NameFormat', \
SAML2\Constants::NAMEFORMAT_UNSPECIFIED);
 
  415        foreach (
$attributes as $friendlyName => $attribute) {
 
  416            $t = new \SAML2\XML\md\RequestedAttribute();
 
  417            $t->Name = $attribute;
 
  418            if (!is_int($friendlyName)) {
 
  419                $t->FriendlyName = $friendlyName;
 
  421            if ($nameFormat !== \
SAML2\Constants::NAMEFORMAT_UNSPECIFIED) {
 
  422                $t->NameFormat = $nameFormat;
 
  424            if (in_array($attribute, $attributesrequired, 
true)) {
 
  425                $t->isRequired = 
true;
 
  427            $attributeconsumer->RequestedAttribute[] = 
$t;
 
  430        $spDesc->AttributeConsumingService[] = $attributeconsumer;
 
  442        assert(is_string($set));
 
  448            case 'saml20-sp-remote':
 
  451            case 'saml20-idp-remote':
 
  454            case 'shib13-sp-remote':
 
  457            case 'shib13-idp-remote':
 
  460            case 'attributeauthority-remote':
 
  475    public function addMetadataSP20($metadata, $protocols = array(\SAML2\Constants::NS_SAMLP)) 
  477        assert(is_array($metadata)); 
  478        assert(is_array($protocols)); 
  479        assert(isset($metadata['entityid
'])); 
  480        assert(isset($metadata['metadata-
set'])); 
  482        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid
']); 
  484        $e = new \SAML2\XML\md\SPSSODescriptor(); 
  485        $e->protocolSupportEnumeration = $protocols; 
  487        if ($metadata->hasValue('saml20.sign.assertion
')) { 
  488            $e->WantAssertionsSigned = $metadata->getBoolean('saml20.sign.assertion
'); 
  491        if ($metadata->hasValue('redirect.validate
')) { 
  492            $e->AuthnRequestsSigned = $metadata->getBoolean('redirect.validate
'); 
  493        } elseif ($metadata->hasValue('validate.authnrequest
')) { 
  494            $e->AuthnRequestsSigned = $metadata->getBoolean('validate.authnrequest
'); 
  497        $this->addExtensions($metadata, $e); 
  499        $this->addCertificate($e, $metadata); 
  501        $e->SingleLogoutService = self::createEndpoints($metadata->getEndpoints('SingleLogoutService
'), false); 
  503        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat
', array()); 
  505        $endpoints = $metadata->getEndpoints('AssertionConsumerService
'); 
  506        foreach ($metadata->getArrayizeString('AssertionConsumerService.artifact
', array()) as $acs) { 
  507            $endpoints[] = array( 
  508                'Binding
'  => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact
', 
  512        $e->AssertionConsumerService = self::createEndpoints($endpoints, true); 
  514        $this->addAttributeConsumingService($e, $metadata); 
  516        $this->entityDescriptor->RoleDescriptor[] = $e; 
  518        foreach ($metadata->getArray('contacts
', array()) as $contact) { 
  519            if (array_key_exists('contactType
', $contact) && array_key_exists('emailAddress
', $contact)) { 
  520                $this->addContact($contact['contactType
'], \SimpleSAML\Utils\Config\Metadata::getContact($contact)); 
  531    public function addMetadataIdP20($metadata) 
  533        assert(is_array($metadata)); 
  534        assert(isset($metadata['entityid
'])); 
  535        assert(isset($metadata['metadata-
set'])); 
  537        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid
']); 
  539        $e = new \SAML2\XML\md\IDPSSODescriptor(); 
  540        $e->protocolSupportEnumeration[] = 'urn:oasis:names:tc:SAML:2.0:protocol
'; 
  542        if ($metadata->hasValue('sign.authnrequest
')) { 
  543            $e->WantAuthnRequestsSigned = $metadata->getBoolean('sign.authnrequest
'); 
  544        } elseif ($metadata->hasValue('redirect.sign
')) { 
  545            $e->WantAuthnRequestsSigned = $metadata->getBoolean('redirect.sign
'); 
  548        $this->addExtensions($metadata, $e); 
  550        $this->addCertificate($e, $metadata); 
  552        if ($metadata->hasValue('ArtifactResolutionService
')) { 
  553            $e->ArtifactResolutionService = self::createEndpoints( 
  554                $metadata->getEndpoints('ArtifactResolutionService
'), 
  559        $e->SingleLogoutService = self::createEndpoints($metadata->getEndpoints('SingleLogoutService
'), false); 
  561        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat
', array()); 
  563        $e->SingleSignOnService = self::createEndpoints($metadata->getEndpoints('SingleSignOnService
'), false); 
  565        $this->entityDescriptor->RoleDescriptor[] = $e; 
  567        foreach ($metadata->getArray('contacts
', array()) as $contact) { 
  568            if (array_key_exists('contactType
', $contact) && array_key_exists('emailAddress
', $contact)) { 
  569                $this->addContact($contact['contactType
'], \SimpleSAML\Utils\Config\Metadata::getContact($contact)); 
  580    public function addMetadataSP11($metadata) 
  582        assert(is_array($metadata)); 
  583        assert(isset($metadata['entityid
'])); 
  584        assert(isset($metadata['metadata-
set'])); 
  586        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid
']); 
  588        $e = new \SAML2\XML\md\SPSSODescriptor(); 
  589        $e->protocolSupportEnumeration[] = 'urn:oasis:names:tc:SAML:1.1:protocol
'; 
  591        $this->addCertificate($e, $metadata); 
  593        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat
', array()); 
  595        $endpoints = $metadata->getEndpoints('AssertionConsumerService
'); 
  596        foreach ($metadata->getArrayizeString('AssertionConsumerService.artifact
', array()) as $acs) { 
  597            $endpoints[] = array( 
  598                'Binding
'  => 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01
', 
  602        $e->AssertionConsumerService = self::createEndpoints($endpoints, true); 
  604        $this->addAttributeConsumingService($e, $metadata); 
  606        $this->entityDescriptor->RoleDescriptor[] = $e; 
  615    public function addMetadataIdP11($metadata) 
  617        assert(is_array($metadata)); 
  618        assert(isset($metadata['entityid
'])); 
  619        assert(isset($metadata['metadata-
set'])); 
  621        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid
']); 
  623        $e = new \SAML2\XML\md\IDPSSODescriptor(); 
  624        $e->protocolSupportEnumeration[] = 'urn:oasis:names:tc:SAML:1.1:protocol
'; 
  625        $e->protocolSupportEnumeration[] = 'urn:mace:shibboleth:1.0
'; 
  627        $this->addCertificate($e, $metadata); 
  629        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat
', array()); 
  631        $e->SingleSignOnService = self::createEndpoints($metadata->getEndpoints('SingleSignOnService
'), false); 
  633        $this->entityDescriptor->RoleDescriptor[] = $e; 
  643    public function addAttributeAuthority(array $metadata) 
  645        assert(is_array($metadata)); 
  646        assert(isset($metadata['entityid
'])); 
  647        assert(isset($metadata['metadata-
set'])); 
  649        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid
']); 
  651        $e = new \SAML2\XML\md\AttributeAuthorityDescriptor(); 
  652        $e->protocolSupportEnumeration = $metadata->getArray('protocols
', array(\SAML2\Constants::NS_SAMLP)); 
  654        $this->addExtensions($metadata, $e); 
  655        $this->addCertificate($e, $metadata); 
  657        $e->AttributeService = self::createEndpoints($metadata->getEndpoints('AttributeService
'), false); 
  658        $e->AssertionIDRequestService = self::createEndpoints( 
  659            $metadata->getEndpoints('AssertionIDRequestService
'), 
  663        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat
', array()); 
  665        $this->entityDescriptor->RoleDescriptor[] = $e; 
  682    public function addContact($type, $details) 
  684        assert(is_string($type)); 
  685        assert(is_array($details)); 
  686        assert(in_array($type, array('technical
', 'support
', 'administrative
', 'billing
', 'other
'), true)); 
  688        // TODO: remove this check as soon as getContact() is called always before calling this function 
  689        $details = \SimpleSAML\Utils\Config\Metadata::getContact($details); 
  691        $e = new \SAML2\XML\md\ContactPerson(); 
  692        $e->contactType = $type; 
  694        if (!empty($details['attributes
'])) { 
  695            $e->ContactPersonAttributes = $details['attributes
']; 
  698        if (isset($details['company
'])) { 
  699            $e->Company = $details['company
']; 
  701        if (isset($details['givenName
'])) { 
  702            $e->GivenName = $details['givenName
']; 
  704        if (isset($details['surName
'])) { 
  705            $e->SurName = $details['surName
']; 
  708        if (isset($details['emailAddress
'])) { 
  709            $eas = $details['emailAddress
']; 
  710            if (!is_array($eas)) { 
  713            foreach ($eas as $ea) { 
  714                $e->EmailAddress[] = $ea; 
  718        if (isset($details['telephoneNumber
'])) { 
  719            $tlfNrs = $details['telephoneNumber
']; 
  720            if (!is_array($tlfNrs)) { 
  721                $tlfNrs = array($tlfNrs); 
  723            foreach ($tlfNrs as $tlfNr) { 
  724                $e->TelephoneNumber[] = $tlfNr; 
  728        $this->entityDescriptor->ContactPerson[] = $e; 
  739    private function addX509KeyDescriptor(\SAML2\XML\md\RoleDescriptor $rd, $use, $x509data) 
  741        assert(in_array($use, array('encryption
', 'signing
'), true)); 
  742        assert(is_string($x509data)); 
  744        $keyDescriptor = \SAML2\Utils::createKeyDescriptor($x509data); 
  745        $keyDescriptor->use = $use; 
  746        $rd->KeyDescriptor[] = $keyDescriptor; 
  758    private function addCertificate(\SAML2\XML\md\RoleDescriptor $rd, SimpleSAML_Configuration $metadata) 
  760        $keys = $metadata->getPublicKeys(); 
  761        foreach ($keys as $key) { 
  762            if ($key['type
'] !== 'X509Certificate
') { 
  765            if (!isset($key['signing
']) || $key['signing
'] === true) { 
  766                $this->addX509KeyDescriptor($rd, 'signing
', $key['X509Certificate
']); 
  768            if (!isset($key['encryption
']) || $key['encryption
'] === true) { 
  769                $this->addX509KeyDescriptor($rd, 'encryption
', $key['X509Certificate
']); 
  773        if ($metadata->hasValue('https.certData
')) { 
  774            $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(array_key_exists('yes', $_REQUEST)) $attributes
for($i=1; $i<=count($kw_cases_sel); $i+=1) $lang
if(function_exists( 'posix_getuid') &&posix_getuid()===0) if(!array_key_exists('t', $options)) $tag