Revision: 1815 Author: olavmrk Date: Mon Oct 5 03:53:43 2009 Log: Add support for multiple AssertionConsumerService endpoints.
This patch adds support for multiple AssertionConsumerService endpoints on the IdP, so that a SP can request that the response is sent to a specific ACS URL. Thanks to Georg Gollmann for this patch. Fixes issue 20 http://code.google.com/p/simplesamlphp/source/detail?r=1815 Modified: /trunk/lib/SimpleSAML/Metadata/SAMLParser.php /trunk/modules/saml2/lib/Message.php /trunk/www/saml2/idp/SSOService.php ======================================= --- /trunk/lib/SimpleSAML/Metadata/SAMLParser.php Wed Sep 16 04:11:31 2009 +++ /trunk/lib/SimpleSAML/Metadata/SAMLParser.php Mon Oct 5 03:53:43 2009 @@ -615,13 +615,24 @@ $ret['expire'] = $spd['expire']; } - /* Find the assertion consumer service endpoint. */ - $acs = $this->getDefaultEndpoint($spd['AssertionConsumerService'], array(self::SAML_20_POST_BINDING)); - if($acs === NULL) { + /* Find the assertion consumer service endpoints. */ + $defaultACS = $this->getDefaultEndpoint($spd['AssertionConsumerService'], array(self::SAML_20_POST_BINDING)); + if($defaultACS === NULL) { SimpleSAML_Logger::warning('Could not find a supported SAML 2.0 AssertionConsumerService endpoint for ' . var_export($ret['entityid'], TRUE) . '.'); } else { - $ret['AssertionConsumerService'] = $acs['Location']; + $defaultACS = $defaultACS['Location']; + $retACS = array($defaultACS); + + $allACS = $this->getEndpoints($spd['AssertionConsumerService'], array(self::SAML_20_POST_BINDING)); + foreach ($allACS as $acs) { + $acs = $acs['Location']; + if ($acs !== $defaultACS) { + $retACS[] = $acs; + } + } + + $ret['AssertionConsumerService'] = $retACS; } @@ -1225,32 +1236,39 @@ /** - * This function attempts to locate the default endpoint which supports one of the given bindings. + * This function attempts to locate all endpoints which supports one of the given bindings. * - * @param $endpoints Array with endpoints in the format returned by parseGenericEndpoint. - * @param $acceptedBindings Array with the accepted bindings. If this is NULL, then we accept any binding. - * @return The default endpoint which supports one of the bindings, or NULL if no endpoints supports - * one of the bindings. */ - private function getDefaultEndpoint($endpoints, $acceptedBindings = NULL) { + private function getEndpoints($endpoints, $acceptedBindings = NULL) { assert('$acceptedBindings === NULL || is_array($acceptedBindings)'); /* Filter the list of endpoints if $acceptedBindings !== NULL. */ - if($acceptedBindings !== NULL) { - $newEndpoints = array(); - - foreach($endpoints as $ep) { - /* Add it to the list of valid ACSs if it has one of the supported bindings. */ - if(in_array($ep['Binding'], $acceptedBindings, TRUE)) { - $newEndpoints[] = $ep; - } - } - - $endpoints = $newEndpoints; - } + if($acceptedBindings === NULL) return $endpoints; + + $newEndpoints = array(); + foreach($endpoints as $ep) { + /* Add it to the list of valid ACSs if it has one of the supported bindings. */ + if(in_array($ep['Binding'], $acceptedBindings, TRUE)) { + $newEndpoints[] = $ep; + } + } + return $newEndpoints; + } + /** + * This function attempts to locate the default endpoint which supports one of the given bindings. + * + * @param $endpoints Array with endpoints in the format returned by parseGenericEndpoint. + * @param $acceptedBindings Array with the accepted bindings. If this is NULL, then we accept any binding. + * @return The default endpoint which supports one of the bindings, or NULL if no endpoints supports + * one of the bindings. + */ + private function getDefaultEndpoint($endpoints, $acceptedBindings = NULL) { + + $endpoints = $this->getEndpoints($endpoints, $acceptedBindings); + /* First we look for the endpoint with isDefault set to true. */ foreach($endpoints as $ep) { ======================================= --- /trunk/modules/saml2/lib/Message.php Thu Oct 1 04:45:27 2009 +++ /trunk/modules/saml2/lib/Message.php Mon Oct 5 03:53:43 2009 @@ -541,7 +541,7 @@ * @return SAML2_Assertion The assertion. */ public static function buildAssertion(SimpleSAML_Configuration $srcMetadata, - SimpleSAML_Configuration $dstMetadata, array $attributes) { + SimpleSAML_Configuration $dstMetadata, array $attributes, $consumerURL) { $signAssertion = $dstMetadata->getBoolean('saml20.sign.assertion', NULL); if ($signAssertion === NULL) { @@ -556,7 +556,7 @@ } $a->setIssuer($srcMetadata->getString('entityid')); - $a->setDestination($dstMetadata->getString('AssertionConsumerService')); + $a->setDestination($consumerURL); $a->setValidAudiences(array($dstMetadata->getString('entityid'))); $a->setNotBefore(time() - 30); @@ -621,7 +621,7 @@ * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender (IdP). * @param SimpleSAML_Configuration $dstMetadata The metadata of the recipient (SP). */ - public static function buildResponse(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata) { + public static function buildResponse(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, $consumerURL) { $signResponse = $dstMetadata->getBoolean('saml20.sign.response', NULL); if ($signResponse === NULL) { @@ -631,7 +631,7 @@ $r = new SAML2_Response(); $r->setIssuer($srcMetadata->getString('entityid')); - $r->setDestination($dstMetadata->getString('AssertionConsumerService')); + $r->setDestination($consumerURL); if ($signResponse) { self::addSign($srcMetadata, $dstMetadata, $r); ======================================= --- /trunk/www/saml2/idp/SSOService.php Fri Sep 25 00:53:59 2009 +++ /trunk/www/saml2/idp/SSOService.php Mon Oct 5 03:53:43 2009 @@ -70,7 +70,14 @@ $idpMetadata = $metadata->getMetaDataConfig($idpentityid, 'saml20-idp-hosted'); $spMetadata = $metadata->getMetaDataConfig($issuer, 'saml20-sp-remote'); - $ar = sspmod_saml2_Message::buildResponse($idpMetadata, $spMetadata); + if (array_key_exists('ConsumerURL', $requestcache)) { + $consumerURL = $requestcache['ConsumerURL']; + } else { + $urlArray = $spMetadata->getArrayizeString('AssertionConsumerService'); + $consumerURL = $urlArray[0]; + } + + $ar = sspmod_saml2_Message::buildResponse($idpMetadata, $spMetadata, $consumerURL); $ar->setInResponseTo($requestID); $ar->setRelayState($relayState); @@ -141,6 +148,10 @@ $spentityid = $requestcache['Issuer']; $spmetadata = $metadata->getMetaData($spentityid, 'saml20-sp-remote'); + $consumerURL = $authnrequest->getAssertionConsumerServiceURL(); + $consumerArray = SimpleSAML_Utilities::arrayize($spmetadata['AssertionConsumerService']); + if (($consumerURL != NULL) && (array_search($consumerURL, $consumerArray) !== FALSE)) $requestcache['ConsumerURL'] = $consumerURL; + $IDPList = $authnrequest->getIDPList(); if(array_key_exists('IDPList', $spmetadata)) { @@ -443,8 +454,14 @@ /* Begin by creating the assertion. */ $idpMetadata = $metadata->getMetaDataConfig($idpentityid, 'saml20-idp-hosted'); $spMetadata = $metadata->getMetaDataConfig($spentityid, 'saml20-sp-remote'); - - $assertion = sspmod_saml2_Message::buildAssertion($idpMetadata, $spMetadata, $attributes); + if (array_key_exists('ConsumerURL', $requestcache)) { + $consumerURL = $requestcache['ConsumerURL']; + } else { + $urlArray = $spMetadata->getArrayizeString('AssertionConsumerService'); + $consumerURL = $urlArray[0]; + } + + $assertion = sspmod_saml2_Message::buildAssertion($idpMetadata, $spMetadata, $attributes, $consumerURL); $assertion->setInResponseTo($requestID); $nameId = $assertion->getNameId(); @@ -454,7 +471,7 @@ $assertion = sspmod_saml2_Message::encryptAssertion($idpMetadata, $spMetadata, $assertion); /* Create the response. */ - $ar = sspmod_saml2_Message::buildResponse($idpMetadata, $spMetadata); + $ar = sspmod_saml2_Message::buildResponse($idpMetadata, $spMetadata, $consumerURL); $ar->setInResponseTo($requestID); $ar->setRelayState($relayState); $ar->setAssertions(array($assertion)); --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "simpleSAMLphp commits" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/simplesamlphp-commits?hl=en -~----------~----~----~----~------~----~------~--~---
