From 8878597d4dff4414e5d97af1c8dfd4a0356da047 Mon Sep 17 00:00:00 2001 From: Olav Morken <olav.morken@uninett.no> Date: Mon, 27 Oct 2008 16:13:12 +0000 Subject: [PATCH] Experimental SAML 2.0 SP authentication source. git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@949 44740490-163a-0410-bde0-09ae8108e29a --- modules/saml2/default-enable | 3 + modules/saml2/lib/Auth/Source/SP.php | 109 +++++++++++++++++++++++++++ modules/saml2/www/sp/acs.php | 51 +++++++++++++ modules/saml2/www/sp/metadata.php | 36 +++++++++ 4 files changed, 199 insertions(+) create mode 100644 modules/saml2/default-enable create mode 100644 modules/saml2/lib/Auth/Source/SP.php create mode 100644 modules/saml2/www/sp/acs.php create mode 100644 modules/saml2/www/sp/metadata.php diff --git a/modules/saml2/default-enable b/modules/saml2/default-enable new file mode 100644 index 000000000..25615cb47 --- /dev/null +++ b/modules/saml2/default-enable @@ -0,0 +1,3 @@ +This file indicates that the default state of this module +is enabled. To disable, create a file named disable in the +same directory as this file. diff --git a/modules/saml2/lib/Auth/Source/SP.php b/modules/saml2/lib/Auth/Source/SP.php new file mode 100644 index 000000000..b7217aef9 --- /dev/null +++ b/modules/saml2/lib/Auth/Source/SP.php @@ -0,0 +1,109 @@ +<?php + +/** + * SAML 2.0 SP authentication client. + * + * Example: + * 'example-openidp' => array( + * 'saml2:SP', + * 'idp' => 'https://openidp.feide.no', + * ), + * + * @package simpleSAMLphp + * @version $Id$ + */ +class sspmod_saml2_Auth_Source_SP extends SimpleSAML_Auth_Source { + + /** + * The string used to identify our states. + */ + const STAGE_SENT = 'saml2:SP-SSOSent'; + + + /** + * The key of the AuthId field in the state. + */ + const AUTHID = 'saml2:AuthId'; + + + /** + * The entity id of this SP. + */ + private $entityId; + + + /** + * The entity id of the IdP we connect to. + */ + private $idp; + + + /** + * Constructor for SAML 2.0 SP authentication source. + * + * @param array $info Information about this authentication source. + * @param array $config Configuration. + */ + public function __construct($info, $config) { + assert('is_array($info)'); + assert('is_array($config)'); + + /* Call the parent constructor first, as required by the interface. */ + parent::__construct($info, $config); + + if (array_key_exists('entityId', $config)) { + $this->entityId = $config['entityId']; + } else { + $this->entityId = SimpleSAML_Module::getModuleURL('saml2/sp/metadata.php?source=' . + urlencode($this->authId) . '&tmp'); + } + + if (array_key_exists('idp', $config)) { + $this->idp = $config['idp']; + } else { + throw new Exception('TODO: Add support for IdP discovery.'); + } + } + + + /** + * Start login. + * + * This function saves the information about the login, and redirects to the IdP. + * + * @param array &$state Information about the current authentication. + */ + public function authenticate(&$state) { + assert('is_array($state)'); + + /* We are going to need the authId in order to retrieve this authentication source later. */ + $state[self::AUTHID] = $this->authId; + + $id = SimpleSAML_Auth_State::saveState($state, self::STAGE_SENT); + + $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); + $idpMetadata = $metadata->getMetaData($this->idp, 'saml20-idp-remote'); + + $config = SimpleSAML_Configuration::getInstance(); + $sr = new SimpleSAML_XML_SAML20_AuthnRequest($config, $metadata); + $req = $sr->generate($this->entityId, $idpMetadata['SingleSignOnService']); + + $httpredirect = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata); + $httpredirect->sendMessage($req, $this->entityid, $this->idp, $id); + exit(0); + } + + + /** + * Retrieve the entity id of this SP. + * + * @return string Entity id of this SP. + */ + public function getEntityId() { + + return $this->entityId; + } + +} + +?> \ No newline at end of file diff --git a/modules/saml2/www/sp/acs.php b/modules/saml2/www/sp/acs.php new file mode 100644 index 000000000..8cf9f622e --- /dev/null +++ b/modules/saml2/www/sp/acs.php @@ -0,0 +1,51 @@ +<?php + +/** + * Assertion consumer service handler for SAML 2.0 SP authentication client. + */ + +if (!array_key_exists('SAMLResponse', $_POST)) { + throw new SimpleSAML_Error_BadRequest('Missing SAMLResponse to AssertionConsumerService'); +} + +if (!array_key_exists('RelayState', $_POST)) { + throw new SimpleSAML_Error_BadRequest('Missing RelayState to AssertionConsumerService'); +} + +$state = SimpleSAML_Auth_State::loadState($_POST['RelayState'], sspmod_saml2_Auth_Source_SP::STAGE_SENT); + +/* Find authentication source. */ +assert('array_key_exists(sspmod_saml2_Auth_Source_SP::AUTHID, $state)'); +$sourceId = $state[sspmod_saml2_Auth_Source_SP::AUTHID]; + +$source = SimpleSAML_Auth_Source::getById($sourceId); +if ($source === NULL) { + throw new Exception('Could not find authentication source with id ' . $sourceId); +} + +$config = SimpleSAML_Configuration::getInstance(); +$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); + +$binding = new SimpleSAML_Bindings_SAML20_HTTPPost($config, $metadata); +$authnResponse = $binding->decodeResponse($_POST); + +$result = $authnResponse->process(); + +/* Check status code. */ +if($result === FALSE) { + /* Not successful. */ + $statusCode = $authnResponse->findstatus(); + throw new Exception('Error authenticating: ' . $statusCode); +} + +/* The response should include the entity id of the IdP. */ +$idp = $authnResponse->getIssuer(); + +/* TODO: Check that IdP is the correct IdP. */ + +/* TODO: Save NameID & SessionIndex for logout. */ + +$state['Attributes'] = $authnResponse->getAttributes(); +SimpleSAML_Auth_Source::completeAuth($state); + +?> \ No newline at end of file diff --git a/modules/saml2/www/sp/metadata.php b/modules/saml2/www/sp/metadata.php new file mode 100644 index 000000000..a24dfcd06 --- /dev/null +++ b/modules/saml2/www/sp/metadata.php @@ -0,0 +1,36 @@ +<?php + +if (!array_key_exists('source', $_GET)) { + throw new SimpleSAML_Error_BadRequest('Missing source parameter'); +} + +$sourceId = $_GET['source']; +$source = SimpleSAML_Auth_Source::getById($sourceId); +if ($source === NULL) { + throw new SimpleSAML_Error_NotFound('Could not find authentication source with id ' . $sourceId); +} + +if (!($source instanceof sspmod_saml2_Auth_Source_SP)) { + throw new SimpleSAML_Error_NotFound('Source isn\'t a SAML 2.0 SP: ' . $sourceId); +} + +$entityId = $source->getEntityId(); + +$metaArray = array( + 'AssertionConsumerService' => SimpleSAML_Module::getModuleURL('saml2/sp/acs.php'), + ); + +$metaBuilder = new SimpleSAML_Metadata_SAMLBuilder($entityId); +$metaBuilder->addMetadataSP20($metaArray); + +$config = SimpleSAML_Configuration::getInstance(); +$metaBuilder->addContact('technical', array( + 'emailAddress' => $config->getValue('technicalcontact_email'), + 'name' => $config->getValue('technicalcontact_name'), + )); + +$xml = $metaBuilder->getEntityDescriptorText(); + +echo($xml); + +?> -- GitLab