Skip to content
Snippets Groups Projects
Commit d2171453 authored by Olav Morken's avatar Olav Morken
Browse files

saml2: Remove saml2:SP authsource.

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@2371 44740490-163a-0410-bde0-09ae8108e29a
parent 73f8d57a
No related branches found
No related tags found
No related merge requests found
<?php
/**
* SAML 2.0 SP authentication client.
*
* Note: This authentication source is depreceated. You should
* use saml:sp instead.
*
* 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 identifier for the stage where we have sent a discovery service request.
*/
const STAGE_DISCO = 'saml2:SP-DiscoSent';
/**
* The identifier for the stage where we have sent a SSO request.
*/
const STAGE_SENT = 'saml2:SP-SSOSent';
/**
* The string used to identify our logout state.
*/
const STAGE_LOGOUTSENT = 'saml2:SP-LogoutSent';
/**
* The key of the AuthId field in the state.
*/
const AUTHID = 'saml2:AuthId';
/**
* The key for the IdP entity id in the logout state.
*/
const LOGOUT_IDP = 'saml2:SP-Logout-IdP';
/**
* The key for the NameID in the logout state.
*/
const LOGOUT_NAMEID = 'saml2:SP-Logout-NameID';
/**
* The key for the SessionIndex in the logout state.
*/
const LOGOUT_SESSIONINDEX = 'saml2:SP-Logout-SessionIndex';
/**
* The metadata for this SP.
*
* @var SimpleSAML_Configuration
*/
private $metadata;
/**
* 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);
/* For compatibility with code that assumes that $metadata->getString('entityid') gives the entity id. */
if (array_key_exists('entityId', $config)) {
$config['entityid'] = $config['entityId'];
} else {
$config['entityid'] = SimpleSAML_Module::getModuleURL('saml2/sp/metadata.php?source=' . urlencode($this->authId));
}
/* For backwards-compatibility with configuration in saml20-sp-hosted. */
try {
$metadataHandler = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$oldMetadata = $metadataHandler->getMetaData($config['entityid'], 'saml20-sp-hosted');
SimpleSAML_Logger::warning('Depreceated metadata for ' . var_export($config['entityid'], TRUE) .
' in saml20-sp-hosted. The metadata in should be moved into authsources.php.');
$config = array_merge($oldMetadata, $config);
} catch (Exception $e) {};
$this->metadata = SimpleSAML_Configuration::loadFromArray($config, 'authsources[' . var_export($this->authId, TRUE) . ']');
$this->entityId = $this->metadata->getString('entityid');
$this->idp = $this->metadata->getString('idp', NULL);
}
/**
* 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;
if ($this->idp === NULL) {
$this->initDisco($state);
}
$this->initSSO($this->idp, $state);
}
/**
* Send authentication request to specified IdP.
*
* @param string $idp The IdP we should send the request to.
* @param array $state Our state array.
*/
public function initDisco($state) {
assert('is_array($state)');
$id = SimpleSAML_Auth_State::saveState($state, self::STAGE_DISCO);
$config = SimpleSAML_Configuration::getInstance();
$discoURL = $config->getString('idpdisco.url.saml20', NULL);
if ($discoURL === NULL) {
/* Fallback to internal discovery service. */
$discoURL = SimpleSAML_Module::getModuleURL('saml2/disco.php');
}
$returnTo = SimpleSAML_Module::getModuleURL('saml2/sp/discoresp.php', array('AuthID' => $id));
SimpleSAML_Utilities::redirect($discoURL, array(
'entityID' => $this->entityId,
'return' => $returnTo,
'returnIDParam' => 'idpentityid')
);
}
/**
* Send authentication request to specified IdP.
*
* @param string $idp The IdP we should send the request to.
* @param array $state Our state array.
*/
public function initSSO($idp, $state) {
assert('is_string($idp)');
assert('is_array($state)');
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$idpMetadata = $metadata->getMetaDataConfig($idp, 'saml20-idp-remote');
$ar = sspmod_saml2_Message::buildAuthnRequest($this->metadata, $idpMetadata);
$ar->setAssertionConsumerServiceURL(SimpleSAML_Module::getModuleURL('saml2/sp/acs.php'));
$ar->setProtocolBinding(SAML2_Const::BINDING_HTTP_POST);
$id = SimpleSAML_Auth_State::saveState($state, self::STAGE_SENT);
$ar->setRelayState($id);
$b = new SAML2_HTTPRedirect();
$b->setDestination(sspmod_SAML2_Message::getDebugDestination());
$b->send($ar);
assert('FALSE');
}
/**
* Retrieve the entity id of this SP.
*
* @return string Entity id of this SP.
*/
public function getEntityId() {
return $this->entityId;
}
/**
* Retrieve the metadata for this SP.
*
* @return SimpleSAML_Configuration The metadata, as a configuration object.
*/
public function getMetadata() {
return $this->metadata;
}
/**
* Retrieve the NameIDFormat used by this SP.
*
* @return string NameIDFormat used by this SP.
*/
public function getNameIDFormat() {
return $this->metadata->getString('NameIDFormat', 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient');
}
/**
* Check if the IdP entity id is allowed to authenticate users for this authentication source.
*
* @param string $idpEntityId The entity id of the IdP.
* @return boolean TRUE if it is valid, FALSE if not.
*/
public function isIdPValid($idpEntityId) {
assert('is_string($idpEntityId)');
if ($this->idp === NULL) {
/* No IdP configured - all are allowed. */
return TRUE;
}
if ($this->idp === $idpEntityId) {
return TRUE;
}
return FALSE;
}
/**
* Handle logout operation.
*
* @param array $state The logout state.
*/
public function logout(&$state) {
assert('is_array($state)');
assert('array_key_exists(self::LOGOUT_IDP, $state)');
assert('array_key_exists(self::LOGOUT_NAMEID, $state)');
assert('array_key_exists(self::LOGOUT_SESSIONINDEX, $state)');
$id = SimpleSAML_Auth_State::saveState($state, self::STAGE_LOGOUTSENT);
$idp = $state[self::LOGOUT_IDP];
$nameId = $state[self::LOGOUT_NAMEID];
$sessionIndex = $state[self::LOGOUT_SESSIONINDEX];
if (array_key_exists('value', $nameId)) {
/*
* This session was saved by an old version of simpleSAMLphp.
* Convert to the new NameId format.
*
* TODO: Remove this conversion once every session should use the new format.
*/
$nameId['Value'] = $nameId['value'];
unset($nameId['value']);
}
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$idpMetadata = $metadata->getMetaDataConfig($idp, 'saml20-idp-remote');
$lr = sspmod_saml2_Message::buildLogoutRequest($this->metadata, $idpMetadata);
$lr->setNameId($nameId);
$lr->setSessionIndex($sessionIndex);
$lr->setRelayState($id);
$b = new SAML2_HTTPRedirect();
$b->setDestination(sspmod_SAML2_Message::getDebugDestination());
$b->send($lr);
assert('FALSE');
}
/**
* Called when we receive a logout request.
*
* @param string $idpEntityId Entity id of the IdP.
*/
public function onLogout($idpEntityId) {
assert('is_string($idpEntityId)');
/* Call the logout callback we registered in onProcessingCompleted(). */
$this->callLogoutCallback($idpEntityId);
}
/**
* Called when we have completed the procssing chain.
*
* @param array $authProcState The processing chain state.
*/
public static function onProcessingCompleted(array $authProcState) {
assert('array_key_exists("saml2:sp:IdP", $authProcState)');
assert('array_key_exists("saml2:sp:State", $authProcState)');
assert('array_key_exists("Attributes", $authProcState)');
$idp = $authProcState['saml2:sp:IdP'];
$state = $authProcState['saml2:sp: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);
}
/* Register a callback that we can call if we receive a logout request from the IdP. */
$source->addLogoutCallback($idp, $state);
$state['Attributes'] = $authProcState['Attributes'];
SimpleSAML_Auth_Source::completeAuth($state);
}
}
?>
\ No newline at end of file
<?php
/**
* Builtin IdP discovery service.
*/
$discoHandler = new SimpleSAML_XHTML_IdPDisco(array('saml20-idp-remote'), 'saml20');
$discoHandler->handleRequest();
?>
\ No newline at end of file
<?php
/**
* Assertion consumer service handler for SAML 2.0 SP authentication client.
*/
$b = SAML2_Binding::getCurrentBinding();
$response = $b->receive();
if (!($response instanceof SAML2_Response)) {
throw new SimpleSAML_Error_BadRequest('Invalid message received to AssertionConsumerService endpoint.');
}
$relayState = $response->getRelayState();
if (empty($relayState)) {
throw new SimpleSAML_Error_BadRequest('Missing relaystate in message received on AssertionConsumerService endpoint.');
}
$state = SimpleSAML_Auth_State::loadState($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);
}
$idp = $response->getIssuer();
if ($idp === NULL) {
throw new Exception('Missing <saml:Issuer> in message delivered to AssertionConsumerService.');
}
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$idpMetadata = $metadata->getMetaDataConfig($idp, 'saml20-idp-remote');
$spMetadata = $source->getMetadata();
/* Check if the IdP is allowed to authenticate users for this authentication source. */
if (!$source->isIdPValid($idp)) {
throw new Exception('Invalid IdP responded for authentication source with id ' . $sourceId .
'. The IdP was ' . var_export($idp, TRUE));
}
try {
$assertion = sspmod_saml2_Message::processResponse($spMetadata, $idpMetadata, $response);
} catch (sspmod_saml2_Error $e) {
/* The status of the response wasn't "success". */
$e = $e->toException();
SimpleSAML_Auth_State::throwException($state, $e);
}
$nameId = $assertion->getNameId();
$sessionIndex = $assertion->getSessionIndex();
/* We need to save the NameID and SessionIndex for logout. */
$logoutState = array(
sspmod_saml2_Auth_Source_SP::LOGOUT_IDP => $idp,
sspmod_saml2_Auth_Source_SP::LOGOUT_NAMEID => $nameId,
sspmod_saml2_Auth_Source_SP::LOGOUT_SESSIONINDEX => $sessionIndex,
);
$state['LogoutState'] = $logoutState;
$spMetadataArray = $spMetadata->toArray();
$idpMetadataArray = $idpMetadata->toArray();
$pc = new SimpleSAML_Auth_ProcessingChain($idpMetadataArray, $spMetadataArray, 'sp');
$authProcState = array(
'saml2:sp:IdP' => $idp,
'saml2:sp:State' => $state,
'ReturnCall' => array('sspmod_saml2_Auth_Source_SP', 'onProcessingCompleted'),
'Attributes' => $assertion->getAttributes(),
'Destination' => $spMetadataArray,
'Source' => $idpMetadataArray,
);
$pc->processState($authProcState);
sspmod_saml2_Auth_Source_SP::onProcessingCompleted($authProcState);
?>
\ No newline at end of file
<?php
/**
* Handler for response from IdP discovery service.
*/
if (!array_key_exists('AuthID', $_REQUEST)) {
throw new SimpleSAML_Error_BadRequest('Missing AuthID to discovery service response handler');
}
if (!array_key_exists('idpentityid', $_REQUEST)) {
throw new SimpleSAML_Error_BadRequest('Missing idpentityid to discovery service response handler');
}
$state = SimpleSAML_Auth_State::loadState($_REQUEST['AuthID'], sspmod_saml2_Auth_Source_SP::STAGE_DISCO);
/* 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);
}
$source->initSSO($_REQUEST['idpentityid'], $state);
?>
\ No newline at end of file
<?php
/**
* Logout endpoint handler for SAML 2.0 SP authentication client.
*
* This endpoint handles both logout requests and logout responses.
*/
if (!array_key_exists('PATH_INFO', $_SERVER)) {
throw new SimpleSAML_Error_BadRequest('Missing authentication source id in logout URL');
}
$sourceId = substr($_SERVER['PATH_INFO'], 1);
$source = SimpleSAML_Auth_Source::getById($sourceId);
if ($source === NULL) {
throw new Exception('Could not find authentication source with id ' . $sourceId);
}
$binding = SAML2_Binding::getCurrentBinding();
$message = $binding->receive();
$idpEntityId = $message->getIssuer();
if ($idpEntityId === NULL) {
/* Without an issuer we have no way to respond to the message. */
throw new SimpleSAML_Error_BadRequest('Received message on logout endpoint without issuer.');
}
$spEntityId = $source->getEntityId();
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$idpMetadata = $metadata->getMetaDataConfig($idpEntityId, 'saml20-idp-remote');
$spMetadata = $source->getMetadata();
sspmod_saml2_Message::validateMessage($idpMetadata, $spMetadata, $message);
if ($message instanceof SAML2_LogoutResponse) {
$relayState = $message->getRelayState();
if ($relayState === NULL) {
/* Somehow, our RelayState has been lost. */
throw new SimpleSAML_Error_BadRequest('Missing RelayState in logout response.');
}
if (!$message->isSuccess()) {
SimpleSAML_Logger::warning('Unsuccessful logout. Status was: ' . sspmod_saml2_Message::getResponseError($message));
}
$state = SimpleSAML_Auth_State::loadState($relayState, sspmod_saml2_Auth_Source_SP::STAGE_LOGOUTSENT);
SimpleSAML_Auth_Source::completeLogout($state);
} elseif ($message instanceof SAML2_LogoutRequest) {
SimpleSAML_Logger::debug('module/saml2/sp/logout: Request from ' . $idpEntityId);
SimpleSAML_Logger::stats('saml20-idp-SLO idpinit ' . $spEntityId . ' ' . $idpEntityId);
/* Notify source of logout, so that it may call logout callbacks. */
$source->onLogout($idpEntityId);
/* Create an send response. */
$lr = sspmod_saml2_Message::buildLogoutResponse($spMetadata, $idpMetadata);
$lr->setRelayState($message->getRelayState());
$lr->setInResponseTo($message->getId());
$binding = new SAML2_HTTPRedirect();
$binding->setDestination(sspmod_SAML2_Message::getDebugDestination());
$binding->send($lr);
} else {
throw new SimpleSAML_Error_BadRequest('Unknown message received on logout endpoint: ' . get_class($message));
}
<?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(
'metadata-set' => 'saml20-sp-remote',
'entityid' => $entityId,
'AssertionConsumerService' => SimpleSAML_Module::getModuleURL('saml2/sp/acs.php'),
'SingleLogoutService' => SimpleSAML_Module::getModuleURL('saml2/sp/logout.php/' . $sourceId),
'NameIDFormat' => $source->getNameIDFormat(),
);
$metaBuilder = new SimpleSAML_Metadata_SAMLBuilder($entityId);
$metaBuilder->addMetadataSP20($metaArray);
$config = SimpleSAML_Configuration::getInstance();
$metaBuilder->addContact('technical', array(
'emailAddress' => $config->getString('technicalcontact_email', NULL),
'name' => $config->getString('technicalcontact_name', NULL),
));
$xml = $metaBuilder->getEntityDescriptorText();
echo($xml);
?>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment