From 22e1567abbe3a0ae01d4113c4fa4a6bbfbe1c296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kre=20Solberg?= <andreas.solberg@uninett.no> Date: Fri, 12 Oct 2007 08:35:07 +0000 Subject: [PATCH] Added SAML 2.0 IdP Discovery service. Read more here: http://rnd.feide.no/2007/10/12/saml-20-idp-discovery-service-implemented/ git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@23 44740490-163a-0410-bde0-09ae8108e29a --- config/config-template.php | 6 ++ lib/SimpleSAML/Session.php | 8 ++ lib/SimpleSAML/XML/MetaDataStore.php | 9 +++ lib/SimpleSAML/XML/SAML20/AuthnResponse.php | 1 + metadata-templates/saml20-idp-remote.php | 4 + templates/selectidp.php | 90 +++++++++++++++++++++ www/saml2/sp/idpdisco.php | 64 +++++++++++++++ www/saml2/sp/initSLO.php | 3 +- www/saml2/sp/initSSO.php | 17 +++- 9 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 templates/selectidp.php create mode 100644 www/saml2/sp/idpdisco.php diff --git a/config/config-template.php b/config/config-template.php index dc051d6af..c99b833f6 100644 --- a/config/config-template.php +++ b/config/config-template.php @@ -32,6 +32,12 @@ $config = array ( /* * Default IdPs. If you do not enter an idpentityid in the SSO initialization endpoints, * the default IdP configured here will be used. + * + * To enable the SAML 2.0 IdP Discovery service for a SAML 2.0 SP, you need to set the + * default-saml20-idp to be null, like this: + * + * 'default-saml20-idp' => null, + * */ 'default-saml20-idp' => 'sam.feide.no', 'default-shib13-idp' => 'urn:mace:switch.ch:aaitest:dukono.switch.ch', diff --git a/lib/SimpleSAML/Session.php b/lib/SimpleSAML/Session.php index db523b019..814be119f 100644 --- a/lib/SimpleSAML/Session.php +++ b/lib/SimpleSAML/Session.php @@ -37,6 +37,7 @@ class SimpleSAML_Session { private $shibauthreq = null; private $authnresponse = null; + private $idp = null; private $logoutrequest = null; @@ -147,6 +148,13 @@ class SimpleSAML_Session { return $this->authnresponse; } + public function setIdP($idp) { + $this->idp = $idp; + } + public function getIdP() { + return $this->idp; + } + public function setLogoutRequest(SimpleSAML_XML_SAML20_LogoutRequest $lr) { $this->logoutrequest = $lr; } diff --git a/lib/SimpleSAML/XML/MetaDataStore.php b/lib/SimpleSAML/XML/MetaDataStore.php index 1ae3bc1a0..dd426d327 100644 --- a/lib/SimpleSAML/XML/MetaDataStore.php +++ b/lib/SimpleSAML/XML/MetaDataStore.php @@ -108,6 +108,15 @@ class SimpleSAML_XML_MetaDataStore { return $this->metadata[$set][$entityid]; } + public function getList($set = 'saml20-idp-remote') { + if (!isset($this->metadata[$set])) { + $this->load($set); + } + return $this->metadata[$set]; + } + + + public function getGenerated($property, $set = 'saml20-sp-hosted') { $baseurl = SimpleSAML_Utilities::selfURLhost() . '/' . $this->configuration->getValue('baseurlpath'); diff --git a/lib/SimpleSAML/XML/SAML20/AuthnResponse.php b/lib/SimpleSAML/XML/SAML20/AuthnResponse.php index 96c52e07b..9bc4bf8f4 100644 --- a/lib/SimpleSAML/XML/SAML20/AuthnResponse.php +++ b/lib/SimpleSAML/XML/SAML20/AuthnResponse.php @@ -161,6 +161,7 @@ class SimpleSAML_XML_SAML20_AuthnResponse extends SimpleSAML_XML_AuthnResponse { $session->setNameID($nameid['NameID']); $session->setNameIDFormat($nameid['Format']); $session->setSessionIndex($this->getSessionIndex()); + $session->setIdP($this->getIssuer()); /* $nameID["NameID"] = $node->nodeValue; diff --git a/metadata-templates/saml20-idp-remote.php b/metadata-templates/saml20-idp-remote.php index b6436dadd..1062e92c3 100644 --- a/metadata-templates/saml20-idp-remote.php +++ b/metadata-templates/saml20-idp-remote.php @@ -25,6 +25,8 @@ $metadata = array( * Metadata for Feide's test environment. */ 'max.feide.no' => array( + 'name' => 'Test environment of Feide', + 'description' => 'max.feide.no: the test environment of Feide.', 'SingleSignOnService' => 'https://max.feide.no/amserver/SSORedirect/metaAlias/idp', 'SingleLogoutService' => 'https://max.feide.no/amserver/IDPSloRedirect/metaAlias/idp', 'certFingerprint' => '3fa158e8abfd4b5203315b08c0b791b6ee4715f6', @@ -35,6 +37,8 @@ $metadata = array( * Metadata for Feide's production environment. */ 'sam.feide.no' => array( + 'name' => 'Feide', + 'description' => 'Authenticate with your identity from a school or university in Norway.', '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', diff --git a/templates/selectidp.php b/templates/selectidp.php new file mode 100644 index 000000000..c1174f709 --- /dev/null +++ b/templates/selectidp.php @@ -0,0 +1,90 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<title><?php echo $data['header']; ?></title> + +<style type="text/css"> + +/* these styles are in the head of this page because this is a unique page */ + +/* THE BIG GUYS */ +* {margin:0;padding:0} +body {text-align:center;padding: 20px 0;background: #222;color:#333;font:83%/1.5 arial,tahoma,verdana,sans-serif} +img {border:none;display:block} +hr {margin: 1em 0;background:#eee;height:1px;color:#eee;border:none;clear:both} + +/* LINKS */ +a,a:link,a:link,a:link,a:hover {font-weight:bold;background:transparent;text-decoration:underline;cursor:pointer} +a:link {color:#c00} +a:visited {color:#999} +a:hover,a:active {color:#069} + +/* LISTS */ +ul {margin: .3em 0 1.5em 2em} + ul.related {margin-top:-1em} +li {margin-left:2em} +dt {font-weight:bold} +#wrap {border: 1px solid #fff;position:relative;background:#fff;width:600px;margin: 0 auto;text-align:left} +#header {background: #666 url("/<?php echo $data['baseurlpath']; ?>resources/sprites.gif") repeat-x 0 100%;margin: 0 0 25px;padding: 0 0 8px} +#header h1 {color:#fff;font-size: 145%;padding:20px 20px 12px} +#poweredby {width:96px;height:63px;position:absolute;top:0;right:0} +#content {padding: 0 20px} + +/* TYPOGRAPHY */ +p, ul, ol {margin: 0 0 1.5em} +h1, h2, h3, h4, h5, h6 {letter-spacing: -1px;font-family: arial,verdana,sans-serif;margin: 1.2em 0 .3em;color:#000;border-bottom: 1px solid #eee;padding-bottom: .1em} +h1 {font-size: 196%;margin-top:0;border:none} +h2 {font-size: 136%} +h3 {font-size: 126%} +h4 {font-size: 116%} +h5 {font-size: 106%} +h6 {font-size: 96%} + +.old {text-decoration:line-through} +</style> +</head> +<body> + +<div id="wrap"> + + <div id="header"> + <h1>SAML 2.0 IdP Discovery Service</h1> + <div id="poweredby"><img src="/<?php echo $data['baseurlpath']; ?>resources/icons/bino.png" alt="Bino" /></div> + </div> + + <div id="content"> + + <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> + + + <?php + + foreach ($data['idplist'] AS $idpentry) { + + echo '<h3>' . $idpentry['name'] . '</h3>'; + echo '<p>' . $idpentry['description'] . '<br />'; + echo '[ <a href="' . $data['urlpattern'] . $idpentry['entityid'] . '">Select this IdP</a>]</p>'; + + } + + + ?> + + + + + <hr /> + + Copyright © 2007 <a href="http://rnd.feide.no/">Feide RnD</a> + + <hr /> + + </div> + +</div> + +</body> +</html> diff --git a/www/saml2/sp/idpdisco.php b/www/saml2/sp/idpdisco.php new file mode 100644 index 000000000..d7af8c2fd --- /dev/null +++ b/www/saml2/sp/idpdisco.php @@ -0,0 +1,64 @@ +<?php + +require_once('../../_include.php'); + + +require_once('SimpleSAML/Utilities.php'); +require_once('SimpleSAML/Session.php'); +require_once('SimpleSAML/XHTML/Template.php'); +require_once('SimpleSAML/XML/MetaDataStore.php'); +require_once('SimpleSAML/XML/SAML20/AuthnRequest.php'); +//require_once('SimpleSAML/XML/SAML20/AuthnResponse.php'); +require_once('SimpleSAML/Bindings/SAML20/HTTPRedirect.php'); +//require_once('SimpleSAML/Bindings/SAML20/HTTPPost.php'); + +session_start(); + +$config = SimpleSAML_Configuration::getInstance(); +$metadata = new SimpleSAML_XML_MetaDataStore($config); + + +$session = SimpleSAML_Session::getInstance(); + +try { + + if (!isset($_GET['entityID'])) throw new Exception('Missing parameter: entityID'); + if (!isset($_GET['return'])) throw new Exception('Missing parameter: return'); + if (!isset($_GET['returnIDParam'])) throw new Exception('Missing parameter: returnIDParam'); + + $spentityid = $_GET['entityID']; + $return = $_GET['return']; + $returnidparam = $_GET['returnIDParam']; + +} catch (Exception $exception) { + + $et = new SimpleSAML_XHTML_Template($config, 'error.php'); + $et->data['message'] = 'Error getting required parameters for IdP Discovery Service'; + $et->data['e'] = $exception; + $et->show(); + exit(0); +} + + +if (isset($_GET['idpentityid'])) { + + $idpentityid = $_GET['idpentityid']; + + $returnurl = SimpleSAML_Utilities::addURLparameter($return, $returnidparam . '=' . $idpentityid); + header('Location: ' . $returnurl); + exit(0); +} + + +$idplist = $metadata->getList('saml20-idp-remote'); + + +$t = new SimpleSAML_XHTML_Template($config, 'selectidp.php'); +$t->data['header'] = 'Select your identity provider'; +$t->data['idplist'] = $idplist; +$t->data['urlpattern'] = htmlentities(SimpleSAML_Utilities::selfURL() . '&idpentityid='); +$t->show(); + + + +?> \ No newline at end of file diff --git a/www/saml2/sp/initSLO.php b/www/saml2/sp/initSLO.php index f2e4a8f05..0d3f7ebd0 100644 --- a/www/saml2/sp/initSLO.php +++ b/www/saml2/sp/initSLO.php @@ -17,7 +17,8 @@ $metadata = new SimpleSAML_XML_MetaDataStore($config); $session = SimpleSAML_Session::getInstance(); -$idpentityid = isset($_GET['idpentityid']) ? $_GET['idpentityid'] : $config->getValue('default-saml20-idp') ; +$idpentityid = $session->getIdP(); +// isset($_GET['idpentityid']) ? $_GET['idpentityid'] : $config->getValue('default-saml20-idp') ; $spentityid = isset($_GET['spentityid']) ? $_GET['spentityid'] : $metadata->getMetaDataCurrentEntityID(); diff --git a/www/saml2/sp/initSSO.php b/www/saml2/sp/initSSO.php index 183ba2901..4c24f7998 100644 --- a/www/saml2/sp/initSSO.php +++ b/www/saml2/sp/initSSO.php @@ -36,13 +36,23 @@ try { if (!isset($session) || !$session->isValid() ) { + + if ($idpentityid == null) { + + $returnURL = urlencode(SimpleSAML_Utilities::selfURL()); + $discservice = '/' . $config->getValue('baseurlpath') . 'saml2/sp/idpdisco.php?entityID=' . $spentityid . + '&return=' . $returnURL . '&returnIDParam=idpentityid'; + header('Location: ' . $discservice); + exit(0); + + } + + try { $sr = new SimpleSAML_XML_SAML20_AuthnRequest($config, $metadata); $req = $sr->generate($spentityid); - - $httpredirect = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata); $relayState = SimpleSAML_Utilities::selfURL(); @@ -65,11 +75,10 @@ if (!isset($session) || !$session->isValid() ) { } } else { - $relaystate = $session->getRelayState(); - + if (isset($relaystate) && !empty($relaystate)) { header('Location: ' . $relaystate ); } else { -- GitLab