From 7bea57bbdb4a6d6b3de3f40a3401384c3e36d8a3 Mon Sep 17 00:00:00 2001 From: Olav Morken <olav.morken@uninett.no> Date: Tue, 15 May 2012 09:39:12 +0000 Subject: [PATCH] saml:SP: Add support for specifying bindings and required attributes in metadata. This patch adds two enhancements to metadata generation: * Support for specifying attributes that are required. * Support for removing some of the AssertionConsumerService bindings. Thanks to Benjamin Andresen for implementing this! git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@3092 44740490-163a-0410-bde0-09ae8108e29a --- modules/saml/docs/sp.txt | 46 +++++++++++++++++ modules/saml/www/sp/metadata.php | 85 +++++++++++++++++++------------- 2 files changed, 97 insertions(+), 34 deletions(-) diff --git a/modules/saml/docs/sp.txt b/modules/saml/docs/sp.txt index 5e5c66a0c..673d69ca9 100644 --- a/modules/saml/docs/sp.txt +++ b/modules/saml/docs/sp.txt @@ -105,6 +105,38 @@ Here we will list some examples for this authentication source. ), +### Specifying attributes and required attributes + + An SP that wants eduPersonPrincipalName and mail, where eduPersonPrincipalName should be listed as required: + + 'example-attributes => array( + 'saml:SP', + 'name' => array( //Name required for AttributeConsumingService-element. + 'en' => 'Example service', + 'no' => 'Eksempeltjeneste', + ), + 'attributes' => array( + 'eduPersonPrincipalName', + 'mail', + ) + 'attributes.required' => array ( + 'eduPersonPrincipalName', + ), + 'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic', + ), + + +### Limiting supported AssertionConsumerService endpoint bindings + + 'example-acs-limit' => array( + 'saml:SP', + 'acs.Bindings' => array( + 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', + 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post', + ), + ), + + ### Requesting a specific authentication method. $auth = new SimpleSAML_Auth_Simple('default-sp'); @@ -127,6 +159,16 @@ Here we will list some examples for this authentication source. Options ------- +`acs.Bindings` +: List of bindings the SP should support. If it is unset, all will be added. +: Possible values: + + * `urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST` + * `urn:oasis:names:tc:SAML:1.0:profiles:browser-post` + * `urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact` + * `urn:oasis:names:tc:SAML:1.0:profiles:artifact-01` + * `urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser` + `assertion.encryption` : Whether assertions received by this SP must be encrypted. The default value is `FALSE`. If this option is set to `TRUE`, unencrypted assertions will be rejected. @@ -147,6 +189,10 @@ Options `attributes.NameFormat` : The `NameFormat` for the requested attributes. +`attributes.required` +: If you have attributes added you can here specify which should be marked as required. +: The attributes should still be present in `attributes`. + `AuthnContextClassRef` : The SP can request authentication with a specific authentication context class. One example of usage could be if the IdP supports both username/password authentication as well as software-PKI. diff --git a/modules/saml/www/sp/metadata.php b/modules/saml/www/sp/metadata.php index b19a39219..25e9d7fd2 100644 --- a/modules/saml/www/sp/metadata.php +++ b/modules/saml/www/sp/metadata.php @@ -1,6 +1,5 @@ <?php - if (!array_key_exists('PATH_INFO', $_SERVER)) { throw new SimpleSAML_Error_BadRequest('Missing authentication source id in metadata URL'); } @@ -48,36 +47,48 @@ if ($store instanceof SimpleSAML_Store_SQL) { $sp->SingleLogoutService[] = $slo; } -$acs = new SAML2_XML_md_IndexedEndpointType(); -$acs->index = 0; -$acs->Binding = SAML2_Const::BINDING_HTTP_POST; -$acs->Location = SimpleSAML_Module::getModuleURL('saml/sp/saml2-acs.php/' . $sourceId); -$sp->AssertionConsumerService[] = $acs; - -$acs = new SAML2_XML_md_IndexedEndpointType(); -$acs->index = 1; -$acs->Binding = 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post'; -$acs->Location = SimpleSAML_Module::getModuleURL('saml/sp/saml1-acs.php/' . $sourceId); -$sp->AssertionConsumerService[] = $acs; - -$acs = new SAML2_XML_md_IndexedEndpointType(); -$acs->index = 2; -$acs->Binding = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact'; -$acs->Location = SimpleSAML_Module::getModuleURL('saml/sp/saml2-acs.php/' . $sourceId); -$sp->AssertionConsumerService[] = $acs; - -$acs = new SAML2_XML_md_IndexedEndpointType(); -$acs->index = 3; -$acs->Binding = 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01'; -$acs->Location = SimpleSAML_Module::getModuleURL('saml/sp/saml1-acs.php/' . $sourceId . '/artifact'); -$sp->AssertionConsumerService[] = $acs; - -$acs = new SAML2_XML_md_IndexedEndpointType(); -$acs->index = 4; -$acs->Binding = 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser'; -$acs->ProtocolBinding = SAML2_Const::BINDING_HTTP_POST; -$acs->Location = SimpleSAML_Module::getModuleURL('saml/sp/saml2-acs.php/' . $sourceId); -$sp->AssertionConsumerService[] = $acs; +$assertionsconsumerservicesdefault = array( + 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', + 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post', + 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact', + 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01', + 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser', +); + +$assertionsconsumerservices = $spconfig->getArray('acs.Bindings', $assertionsconsumerservicesdefault); + +$index = 0; +foreach ($assertionsconsumerservices as $services) { + + $acs = new SAML2_XML_md_IndexedEndpointType(); + $acs->index = $index; + switch ($services) { + case 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST': + $acs->Binding = SAML2_Const::BINDING_HTTP_POST; + $acs->Location = SimpleSAML_Module::getModuleURL('saml/sp/saml2-acs.php/' . $sourceId); + break; + case 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post': + $acs->Binding = 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post'; + $acs->Location = SimpleSAML_Module::getModuleURL('saml/sp/saml1-acs.php/' . $sourceId); + break; + case 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact': + $acs->Binding = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact'; + $acs->Location = SimpleSAML_Module::getModuleURL('saml/sp/saml2-acs.php/' . $sourceId); + break; + case 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01': + $acs->Binding = 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01'; + $acs->Location = SimpleSAML_Module::getModuleURL('saml/sp/saml1-acs.php/' . $sourceId . '/artifact'); + break; + case 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser': + $acs->Binding = 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser'; + $acs->ProtocolBinding = SAML2_Const::BINDING_HTTP_POST; + $acs->Location = SimpleSAML_Module::getModuleURL('saml/sp/saml2-acs.php/' . $sourceId); + break; + } + $sp->AssertionConsumerService[] = $acs; + $index++; +} + $keys = array(); $certInfo = SimpleSAML_Utilities::loadPublicKey($spconfig, FALSE, 'new_'); @@ -99,7 +110,6 @@ if ($certInfo !== NULL && array_key_exists('certData', $certInfo)) { 'encryption' => TRUE, 'X509Certificate' => $certInfo['certData'], ); - } else { $hasNewCert = FALSE; } @@ -124,14 +134,17 @@ if ($certInfo !== NULL && array_key_exists('certData', $certInfo)) { 'encryption' => ($hasNewCert ? FALSE : TRUE), 'X509Certificate' => $certInfo['certData'], ); - } else { $certData = NULL; } $name = $spconfig->getLocalizedString('name', NULL); $attributes = $spconfig->getArray('attributes', array()); + if ($name !== NULL && !empty($attributes)) { + + $attributesrequired = $spconfig->getArray('attributes.required', array()); + /* We have everything necessary to add an AttributeConsumingService. */ $acs = new SAML2_XML_md_AttributeConsumingService(); $sp->AttributeConsumingService[] = $acs; @@ -149,6 +162,10 @@ if ($name !== NULL && !empty($attributes)) { $a = new SAML2_XML_md_RequestedAttribute(); $a->Name = $attribute; $a->NameFormat = $nameFormat; + // Is the attribute required + if (in_array($attribute, $attributesrequired)) + $a->isRequired = true; + $acs->RequestedAttribute[] = $a; } @@ -163,6 +180,7 @@ if ($name !== NULL && !empty($attributes)) { } } + $orgName = $spconfig->getLocalizedString('OrganizationName', NULL); if ($orgName !== NULL) { $o = new SAML2_XML_md_Organization(); @@ -233,5 +251,4 @@ if (array_key_exists('output', $_REQUEST) && $_REQUEST['output'] == 'xhtml') { header('Content-Type: application/samlmetadata+xml'); echo($xml); } - ?> -- GitLab