From b170f27d1be48e2069d99e8e53cfd6d328d21637 Mon Sep 17 00:00:00 2001 From: Olav Morken <olav.morken@uninett.no> Date: Wed, 19 Aug 2009 08:30:48 +0000 Subject: [PATCH] SimpleSAML_XHTML_IdPDisco: Support multiple metadata sets. git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@1694 44740490-163a-0410-bde0-09ae8108e29a --- lib/SimpleSAML/XHTML/IdPDisco.php | 110 ++++++++++++++--------- modules/discopower/lib/PowerIdPDisco.php | 13 +-- modules/discopower/www/disco.php | 2 +- modules/saml2/www/disco.php | 2 +- www/saml2/sp/idpdisco.php | 2 +- www/shib13/sp/idpdisco.php | 2 +- www/wsfed/sp/idpdisco.php | 2 +- 7 files changed, 82 insertions(+), 51 deletions(-) diff --git a/lib/SimpleSAML/XHTML/IdPDisco.php b/lib/SimpleSAML/XHTML/IdPDisco.php index c952b75dc..d694111e3 100644 --- a/lib/SimpleSAML/XHTML/IdPDisco.php +++ b/lib/SimpleSAML/XHTML/IdPDisco.php @@ -15,25 +15,16 @@ class SimpleSAML_XHTML_IdPDisco { /** - * The various discovery services we can host. + * An instance of the configuration class. */ - protected static $discoTypes = array( - 'saml20' => array( - 'metadata' => 'saml20-idp-remote', - ), - 'shib13' => array( - 'metadata' => 'shib13-idp-remote', - ), - 'wsfed' => array( - 'metadata' => 'wsfed-idp-remote', - ), - ); - + protected $config; /** - * An instance of the configuration class. + * The identifier of this discovery service. + * + * @var string */ - protected $config; + protected $instance; /** @@ -49,9 +40,11 @@ class SimpleSAML_XHTML_IdPDisco { /** - * Our discovery service type. + * The metadata sets we find allowed entities in, in prioritized order. + * + * @var array */ - protected $discoType; + protected $metadataSets; /** @@ -90,22 +83,18 @@ class SimpleSAML_XHTML_IdPDisco { * The constructor does the parsing of the request. If this is an invalid request, it will * throw an exception. * - * @param $discoType String which identifies the type of discovery service. + * @param array $metadataSets Array with metadata sets we find remote entities in. + * @param string $instance The name of this instance of the discovery service. */ - public function __construct($discoType) { + public function __construct(array $metadataSets, $instance) { + assert('is_string($instance)'); /* Initialize standard classes. */ $this->config = SimpleSAML_Configuration::getInstance(); $this->metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); $this->session = SimpleSAML_Session::getInstance(); - - - if(!array_key_exists($discoType, self::$discoTypes)) { - throw new Exception('Unknown discovery service type: ' . $discoType); - } - - $this->discoType = self::$discoTypes[$discoType]; - $this->discoType['type'] = $discoType; + $this->instance = $instance; + $this->metadataSets = $metadataSets; $this->log('Accessing discovery service.'); @@ -156,7 +145,7 @@ class SimpleSAML_XHTML_IdPDisco { * @param $message The message which should be logged. */ protected function log($message) { - SimpleSAML_Logger::info('idpDisco.' . $this->discoType['type'] . ': ' . $message); + SimpleSAML_Logger::info('idpDisco.' . $this->instance . ': ' . $message); } @@ -170,7 +159,7 @@ class SimpleSAML_XHTML_IdPDisco { * @return The value of the cookie with the given name, or NULL if no cookie with that name exists. */ protected function getCookie($name) { - $prefixedName = 'idpdisco_' . $this->discoType['type'] . '_' . $name; + $prefixedName = 'idpdisco_' . $this->instance . '_' . $name; if(array_key_exists($prefixedName, $_COOKIE)) { return $_COOKIE[$prefixedName]; } else { @@ -189,7 +178,7 @@ class SimpleSAML_XHTML_IdPDisco { * @param $value The value of the cookie. */ protected function setCookie($name, $value) { - $prefixedName = 'idpdisco_' . $this->discoType['type'] . '_' . $name; + $prefixedName = 'idpdisco_' . $this->instance . '_' . $name; /* We save the cookies for 90 days. */ $saveUntil = time() + 60*60*24*90; @@ -219,14 +208,16 @@ class SimpleSAML_XHTML_IdPDisco { return $idp; } - try { - $this->metadata->getMetaData($idp, $this->discoType['metadata']); - return $idp; - } catch(Exception $e) { - $this->log('Unable to validate IdP entity id [' . $idp . '].'); - /* The entity id wasn't valid. */ - return NULL; + foreach ($this->metadataSets AS $metadataSet) { + try { + $this->metadata->getMetaData($idp, $metadataSet); + return $idp; + } catch(Exception $e) { } } + + $this->log('Unable to validate IdP entity id [' . $idp . '].'); + /* The entity id wasn't valid. */ + return NULL; } @@ -305,6 +296,24 @@ class SimpleSAML_XHTML_IdPDisco { } + /** + * Retrieve a recommended IdP based on the IP address of the client. + * + * @return string|NULL The entity ID of the IdP if one is found, or NULL if not. + */ + protected function getFromCIDRhint() { + + foreach ($this->metadataSets as $metadataSet) { + $idp = $this->metadata->getPreferredEntityIdFromCIDRhint($metadataSet, $_SERVER['REMOTE_ADDR']); + if (!empty($idp)) { + return $idp; + } + } + + return NULL; + } + + /** * Try to determine which IdP the user should most likely use. * @@ -321,8 +330,7 @@ class SimpleSAML_XHTML_IdPDisco { return $idp; } - $idp = $this->metadata->getPreferredEntityIdFromCIDRhint( - $this->discoType['metadata'], $_SERVER['REMOTE_ADDR']); + $idp = $this->getFromCIDRhint(); if(!empty($idp)) { $this->log('Preferred IdP from CIDR hint [' . $idp . '].'); @@ -389,6 +397,28 @@ class SimpleSAML_XHTML_IdPDisco { } + /** + * Retrieve the list of IdPs which are stored in the metadata. + * + * @return array Array with entityid=>metadata mappings. + */ + protected function getIdPList() { + + $idpList = array(); + foreach ($this->metadataSets AS $metadataSet) { + $newList = $this->metadata->getList($metadataSet); + /* + * Note that we merge the entities in reverse order. This ensuers + * that it is the entity in the first metadata set that "wins" if + * two metadata sets have the same entity. + */ + $idpList = array_merge($newList, $idpList); + } + + return $idpList; + } + + /** * Handles a request to this discovery service. * @@ -427,7 +457,7 @@ class SimpleSAML_XHTML_IdPDisco { /* No choice made. Show discovery service page. */ - $idpList = $this->metadata->getList($this->discoType['metadata']); + $idpList = $this->getIdPList(); $preferredIdP = $this->getRecommendedIdP(); /* diff --git a/modules/discopower/lib/PowerIdPDisco.php b/modules/discopower/lib/PowerIdPDisco.php index e49b134f6..42b64be2b 100644 --- a/modules/discopower/lib/PowerIdPDisco.php +++ b/modules/discopower/lib/PowerIdPDisco.php @@ -21,11 +21,12 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco { * The constructor does the parsing of the request. If this is an invalid request, it will * throw an exception. * - * @param $discoType String which identifies the type of discovery service. + * @param array $metadataSets Array with metadata sets we find remote entities in. + * @param string $instance The name of this instance of the discovery service. */ - public function __construct($discoType) { + public function __construct(array $metadataSets, $instance) { - parent::__construct($discoType); + parent::__construct($metadataSets, $instance); $this->discoconfig = SimpleSAML_Configuration::getConfig('module_discopower.php'); @@ -41,7 +42,7 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco { * @param $message The message which should be logged. */ protected function log($message) { - SimpleSAML_Logger::info('PowerIdPDisco.' . $this->discoType['type'] . ': ' . $message); + SimpleSAML_Logger::info('PowerIdPDisco.' . $this->instance . ': ' . $message); } /* @@ -159,8 +160,8 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco { } /* No choice made. Show discovery service page. */ - - $idpList = $this->idplistStructured($this->filterList($this->metadata->getList($this->discoType['metadata']))); + $idpList = $this->getIdPList(); + $idpList = $this->idplistStructured($this->filterList($idpList)); $preferredIdP = $this->getRecommendedIdP(); $t = new SimpleSAML_XHTML_Template($this->config, 'discopower:disco-tpl.php', 'disco'); diff --git a/modules/discopower/www/disco.php b/modules/discopower/www/disco.php index 8db43947f..daf51ea78 100644 --- a/modules/discopower/www/disco.php +++ b/modules/discopower/www/disco.php @@ -5,7 +5,7 @@ require_once('../www/_include.php'); $session = SimpleSAML_Session::getInstance(); try { - $discoHandler = new sspmod_discopower_PowerIdPDisco('saml20'); + $discoHandler = new sspmod_discopower_PowerIdPDisco(array('saml20-idp-remote', 'shib13-idp-remote'), 'poweridpdisco'); } catch (Exception $exception) { /* An error here should be caused by invalid query parameters. */ SimpleSAML_Utilities::fatalError($session->getTrackID(), 'DISCOPARAMS', $exception); diff --git a/modules/saml2/www/disco.php b/modules/saml2/www/disco.php index f3e526c5a..c1608dc44 100644 --- a/modules/saml2/www/disco.php +++ b/modules/saml2/www/disco.php @@ -4,7 +4,7 @@ * Builtin IdP discovery service. */ -$discoHandler = new SimpleSAML_XHTML_IdPDisco('saml20'); +$discoHandler = new SimpleSAML_XHTML_IdPDisco(array('saml20-idp-remote'), 'saml20'); $discoHandler->handleRequest(); ?> \ No newline at end of file diff --git a/www/saml2/sp/idpdisco.php b/www/saml2/sp/idpdisco.php index 0566025b2..3cfdc17e3 100644 --- a/www/saml2/sp/idpdisco.php +++ b/www/saml2/sp/idpdisco.php @@ -5,7 +5,7 @@ require_once('../../_include.php'); $session = SimpleSAML_Session::getInstance(); try { - $discoHandler = new SimpleSAML_XHTML_IdPDisco('saml20'); + $discoHandler = new SimpleSAML_XHTML_IdPDisco(array('saml20-idp-remote'), 'saml20'); } catch (Exception $exception) { /* An error here should be caused by invalid query parameters. */ SimpleSAML_Utilities::fatalError($session->getTrackID(), 'DISCOPARAMS', $exception); diff --git a/www/shib13/sp/idpdisco.php b/www/shib13/sp/idpdisco.php index ce4c7233b..dfaf3e86b 100644 --- a/www/shib13/sp/idpdisco.php +++ b/www/shib13/sp/idpdisco.php @@ -5,7 +5,7 @@ require_once('../../_include.php'); $session = SimpleSAML_Session::getInstance(); try { - $discoHandler = new SimpleSAML_XHTML_IdPDisco('shib13'); + $discoHandler = new SimpleSAML_XHTML_IdPDisco(array('shib13-idp-remote'), 'shib13'); } catch (Exception $exception) { /* An error here should be caused by invalid query parameters. */ SimpleSAML_Utilities::fatalError($session->getTrackID(), 'DISCOPARAMS', $exception); diff --git a/www/wsfed/sp/idpdisco.php b/www/wsfed/sp/idpdisco.php index ab83d6d6e..1a9e58473 100644 --- a/www/wsfed/sp/idpdisco.php +++ b/www/wsfed/sp/idpdisco.php @@ -5,7 +5,7 @@ require_once('../../_include.php'); $session = SimpleSAML_Session::getInstance(); try { - $discoHandler = new SimpleSAML_XHTML_IdPDisco('wsfed'); + $discoHandler = new SimpleSAML_XHTML_IdPDisco(array('wsfed-idp-remote'), 'wsfed'); } catch (Exception $exception) { /* An error here should be caused by invalid query parameters. */ SimpleSAML_Utilities::fatalError($session->getTrackID(), 'DISCOPARAMS', $exception); -- GitLab