From d89c8da19a62b0f578a489357c62daf42e2209cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kre=20Solberg?= <andreas.solberg@uninett.no> Date: Wed, 5 Mar 2008 07:11:56 +0000 Subject: [PATCH] Adding support for CIDR based hinting. this means you can add a IP range to a remote saml 2 iudp, and that idp will show up as preferred to users within that ip range git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@349 44740490-163a-0410-bde0-09ae8108e29a --- COPYING | 4 ++ .../Metadata/MetaDataStorageHandler.php | 23 ++++++++++- .../Metadata/MetaDataStorageSource.php | 31 +++++++++++++++ lib/SimpleSAML/Utilities.php | 17 +++++++++ metadata-templates/saml20-idp-remote.php | 6 ++- templates/default/en/selectidp-dropdown.php | 9 +++-- templates/default/en/selectidp-links.php | 22 ++++++++--- www/admin/metadata.php | 2 +- www/resources/default.css | 6 ++- www/resources/icons/star.png | Bin 0 -> 3250 bytes www/saml2/sp/idpdisco.php | 36 +++++++++++------- 11 files changed, 130 insertions(+), 26 deletions(-) create mode 100644 www/resources/icons/star.png diff --git a/COPYING b/COPYING index 380e3f66c..014d80887 100644 --- a/COPYING +++ b/COPYING @@ -1,5 +1,9 @@ Note that some of the embedded libraries may be using other licences. In example xmlseclibs uses BSD licence. + +If you will be using simpleSAMLphp in a commercial context, please do not use +the embedded default template which contains some icons with licence that are limited +to non-commercial use. -- simpleSAMLphp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php index 03074e5c1..555628ba6 100644 --- a/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php +++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php @@ -214,7 +214,28 @@ class SimpleSAML_Metadata_MetaDataStorageHandler { /* We were unable to find the hostname/path in any metadata source. */ throw new Exception('Could not find any default metadata entities in set [' . $set . '] for host [' . $currenthost . ' : ' . $currenthostwithpath . ']'); } - + + /** + * This method will call getPreferredEntityIdFromCIDRhint() on all of the + * sources. + * + * @param $set Which set of metadata we are looking it up in. + * @param $ip IP address + * @return The entity id of a entity which have a CIDR hint where the provided + * IP address match. + */ + public function getPreferredEntityIdFromCIDRhint($set, $ip) { + + foreach($this->sources as $source) { + $entityId = $source->getPreferredEntityIdFromCIDRhint($set, $ip); + if($entityId !== NULL) { + return $entityId; + } + } + + return NULL; + + } /** * This function looks up the metadata for the given entity id in the given set. It will throw an diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageSource.php b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php index c80e66072..ef6371b9d 100644 --- a/lib/SimpleSAML/Metadata/MetaDataStorageSource.php +++ b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php @@ -91,6 +91,37 @@ abstract class SimpleSAML_Metadata_MetaDataStorageSource { /* No entries matched - we should return NULL. */ return NULL; } + + /** + * This function will go through all the metadata, and check the hint.cidr + * parameter, which defines a network space (ip range) for each remote entry. + * This function returns the entityID for any of the entities that have an + * IP range which the IP falls within. + * + * @param $set Which set of metadata we are looking it up in. + * @param $ip IP address + * @return The entity id of a entity which have a CIDR hint where the provided + * IP address match. + */ + public function getPreferredEntityIdFromCIDRhint($set, $ip) { + + $metadataSet = $this->getMetadataSet($set); + + foreach($metadataSet AS $entityId => $entry) { + + if(!array_key_exists('hint.cidr', $entry)) continue; + if(!is_array($entry['hint.cidr'])) continue; + + foreach ($entry['hint.cidr'] AS $hint_entry) { + if (ipCIDRcheck($hint_entry, $ip)) + return $entityId; + } + + } + + /* No entries matched - we should return NULL. */ + return NULL; + } /** diff --git a/lib/SimpleSAML/Utilities.php b/lib/SimpleSAML/Utilities.php index 91d6ce1eb..1aff02c74 100644 --- a/lib/SimpleSAML/Utilities.php +++ b/lib/SimpleSAML/Utilities.php @@ -365,6 +365,23 @@ class SimpleSAML_Utilities { exit; } + + /** + * Check whether an IP address is part of an CIDR. + */ + static function ipCIDRcheck($cidr, $ip = null) { + if ($ip == null) $ip = $_SERVER['REMOTE_ADDR']; + list ($net, $mask) = split ("/", $cidr); + + $ip_net = ip2long ($net); + $ip_mask = ~((1 << (32 - $mask)) - 1); + + $ip_ip = ip2long ($ip); + + $ip_ip_net = $ip_ip & $ip_mask; + + return ($ip_ip_net == $ip_net); + } /* This function redirects the user to the specified address. diff --git a/metadata-templates/saml20-idp-remote.php b/metadata-templates/saml20-idp-remote.php index 63dcb3687..34f3c51e1 100644 --- a/metadata-templates/saml20-idp-remote.php +++ b/metadata-templates/saml20-idp-remote.php @@ -76,7 +76,8 @@ $metadata = array( 'SingleSignOnService' => 'https://max.feide.no/amserver/SSORedirect/metaAlias/idp', 'SingleLogoutService' => 'https://max.feide.no/amserver/IDPSloRedirect/metaAlias/idp', 'certFingerprint' => '3fa158e8abfd4b5203315b08c0b791b6ee4715f6', - 'base64attributes' => true + 'base64attributes' => true, + 'hint.cidr' => '158.38.0.0/16' ), /* @@ -88,7 +89,8 @@ $metadata = array( 'SingleSignOnService' => 'https://sam.feide.no/amserver/SSORedirect/metaAlias/idp', 'SingleLogoutService' => 'https://sam.feide.no/amserver/IDPSloRedirect/metaAlias/idp', 'certFingerprint' => '3a:e7:d3:d3:06:ba:57:fd:7f:62:6a:4b:a8:64:b3:4a:53:d9:5d:d0', - 'base64attributes' => true + 'base64attributes' => true, + 'hint.cidr' => '158.38.0.0/16' ) ); diff --git a/templates/default/en/selectidp-dropdown.php b/templates/default/en/selectidp-dropdown.php index 51964b36e..3ba59d5bb 100644 --- a/templates/default/en/selectidp-dropdown.php +++ b/templates/default/en/selectidp-dropdown.php @@ -7,18 +7,21 @@ <h2><?php if (isset($data['header'])) { echo $data['header']; } else { echo "Select your IdP"; } ?></h2> <p>Please select the identity provider where you want to authenticate:</p> - + <form method="get" action="<?php echo $data['urlpattern']; ?>"> <input type="hidden" name="entityID" value="<?php echo htmlspecialchars($data['entityID']); ?>" /> <input type="hidden" name="return" value="<?php echo htmlspecialchars($data['return']); ?>" /> <input type="hidden" name="returnIDParam" value="<?php echo htmlspecialchars($data['returnIDParam']); ?>" /> <select name="idpentityid"> <?php - + foreach ($data['idplist'] AS $idpentry) { echo '<option value="'.htmlspecialchars($idpentry['entityid']).'"'; - if ($idpentry['entityid'] == $data['preferedidp']) echo ' selected="selected"'; + if (isset($this->data['preferredidp']) && + $idpentry['entityid'] == $this->data['preferredidp']) + echo ' selected="selected"'; + echo '>'.htmlspecialchars($idpentry['name']).'</option>'; } diff --git a/templates/default/en/selectidp-links.php b/templates/default/en/selectidp-links.php index 7d5cf1ec5..daab97926 100644 --- a/templates/default/en/selectidp-links.php +++ b/templates/default/en/selectidp-links.php @@ -9,13 +9,25 @@ <?php + - foreach ($data['idplist'] AS $idpentry) { - - echo '<h3>' . htmlspecialchars($idpentry['name']) . '</h3>'; - echo '<p>' . htmlspecialchars($idpentry['description']) . '<br />'; - echo '[ <a href="' . $data['urlpattern'] . htmlspecialchars($idpentry['entityid']) . '">Select this IdP</a>]</p>'; + if (!empty($this->data['preferredidp']) && array_key_exists($this->data['preferredidp'], $this->data['idplist'])) { + $idpentry = $this->data['idplist'][$this->data['preferredidp']]; + echo '<div class="preferredidp">'; + echo ' <img src="/' . $this->data['baseurlpath'] .'resources/icons/star.png" style="float: right" />'; + echo ' <h3>' . htmlspecialchars($idpentry['name']) . '</h3>'; + echo ' <p>' . htmlspecialchars($idpentry['description']) . '<br />'; + echo ' [ <a href="' . $data['urlpattern'] . htmlspecialchars($idpentry['entityid']) . '">Select this IdP</a>]</p>'; + echo '</div>'; + } + + foreach ($data['idplist'] AS $idpentry) { + if ($idpentry['entityid'] != $this->data['preferredidp']) { + echo '<h3>' . htmlspecialchars($idpentry['name']) . '</h3>'; + echo '<p>' . htmlspecialchars($idpentry['description']) . '<br />'; + echo '[ <a href="' . $data['urlpattern'] . htmlspecialchars($idpentry['entityid']) . '">Select this IdP</a>]</p>'; + } } ?> diff --git a/www/admin/metadata.php b/www/admin/metadata.php index a40491f2c..ce5ad8e89 100644 --- a/www/admin/metadata.php +++ b/www/admin/metadata.php @@ -44,7 +44,7 @@ try { foreach ($metalist AS $entityid => $mentry) { $results[$entityid] = SimpleSAML_Utilities::checkAssocArrayRules($mentry, array('entityid', 'SingleSignOnService', 'SingleLogoutService', 'certFingerprint'), - array('name', 'description', 'base64attributes','request.signing','certificate') + array('name', 'description', 'base64attributes','request.signing','certificate', 'hint.cidr') ); } $et->data['metadata.saml20-idp-remote'] = $results; diff --git a/www/resources/default.css b/www/resources/default.css index 770f3c60c..2ef216c16 100644 --- a/www/resources/default.css +++ b/www/resources/default.css @@ -244,4 +244,8 @@ th.rowtitle { border: 1px solid #eee; padding: 2px; } - +div.preferredidp { + border: 1px dashed #ccc; + background: #eee; + padding: 2px 2em 2px 2em; +} \ No newline at end of file diff --git a/www/resources/icons/star.png b/www/resources/icons/star.png new file mode 100644 index 0000000000000000000000000000000000000000..2713202e0d6e2263c81149e779902ff943c9ce67 GIT binary patch literal 3250 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 literal 0 HcmV?d00001 diff --git a/www/saml2/sp/idpdisco.php b/www/saml2/sp/idpdisco.php index ce16c0bfe..b6cc018fc 100644 --- a/www/saml2/sp/idpdisco.php +++ b/www/saml2/sp/idpdisco.php @@ -2,7 +2,6 @@ require_once('../../_include.php'); - require_once('SimpleSAML/Utilities.php'); require_once('SimpleSAML/Session.php'); require_once('SimpleSAML/XHTML/Template.php'); @@ -11,10 +10,8 @@ require_once('SimpleSAML/Metadata/MetaDataStorageHandler.php'); $config = SimpleSAML_Configuration::getInstance(); $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); - $session = SimpleSAML_Session::getInstance(); - SimpleSAML_Logger::info('SAML2.0 - SP.idpDisco: Accessing SAML 2.0 discovery service'); if (!$config->getValue('enable.saml20-sp', false)) @@ -50,26 +47,39 @@ if (isset($_GET['idpentityid'])) { try { $idplist = $metadata->getList('saml20-idp-remote'); + $preferredidp = $metadata->getPreferredEntityIdFromCIDRhint('saml20-idp-remote', $_SERVER['REMOTE_ADDR']); + + if (!empty($preferredidp)) + SimpleSAML_Logger::info('SAML2.0 - SP.idpDisco: Preferred IdP from CIDR hint [ ' . $preferredidp . '].'); + } catch (Exception $exception) { SimpleSAML_Utilities::fatalError($session->getTrackID(), 'METADATA', $exception); } +if (!empty($_COOKIE['preferedidp'])) { + $preferredidp = $_COOKIE['preferedidp']; + SimpleSAML_Logger::info('SAML2.0 - SP.idpDisco: Preferred IdP overridden from cookie [ ' . $preferredidp . '].'); +} + + +/** + * Make use of an XHTML template to present the select IdP choice to the user. + * Currently the supported options is either a drop down menu or a list view. + */ +$templatefile = ($config->getValue('idpdisco.layout') == 'dropdown' ? 'selectidp-dropdown.php' : 'selectidp-links.php'); +$t = new SimpleSAML_XHTML_Template($config, $templatefile); +$t->data['header'] = 'Select your identity provider'; +$t->data['idplist'] = $idplist; +$t->data['preferredidp'] = $preferredidp; + if ($config->getValue('idpdisco.layout') == 'dropdown') { - $t = new SimpleSAML_XHTML_Template($config, 'selectidp-dropdown.php'); - $t->data['header'] = 'Select your identity provider'; - $t->data['idplist'] = $idplist; $t->data['return']= $return; $t->data['returnIDParam'] = $returnidparam; $t->data['entityID'] = $spentityid; - $t->data['preferedidp'] = (!empty($_COOKIE['preferedidp'])) ? $_COOKIE['preferedidp'] : null; $t->data['urlpattern'] = htmlentities(SimpleSAML_Utilities::selfURLNoQuery()); $t->show(); -} -else -{ - $t = new SimpleSAML_XHTML_Template($config, 'selectidp-links.php'); - $t->data['header'] = 'Select your identity provider'; - $t->data['idplist'] = $idplist; + +} else { $t->data['urlpattern'] = htmlentities(SimpleSAML_Utilities::selfURL() . '&idpentityid='); $t->show(); } -- GitLab