Skip to content
Snippets Groups Projects
Commit 8770e20e authored by Andreas Åkre Solberg's avatar Andreas Åkre Solberg
Browse files

Adding support for the IdP-first flow with SAML 2.0, where there is no...

Adding support for the IdP-first flow with SAML 2.0, where there is no authentication request, and an unsolited response is sent back to the SP.



git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@1242 44740490-163a-0410-bde0-09ae8108e29a
parent e586d2a9
No related branches found
No related tags found
No related merge requests found
...@@ -689,6 +689,8 @@ redirect.validate ...@@ -689,6 +689,8 @@ redirect.validate
Configuring metadata for a Shibboleth 1.3 IdP Configuring metadata for a Shibboleth 1.3 IdP
--------------------------------------------- ---------------------------------------------
...@@ -717,6 +719,9 @@ used as the scope. ...@@ -717,6 +719,9 @@ used as the scope.
*/ */
'scopedattributes' => array('eduPersonPrincipalName'), 'scopedattributes' => array('eduPersonPrincipalName'),
Test IdP Test IdP
-------- --------
...@@ -752,7 +757,19 @@ improvements or contribute with code or plugins of your own. ...@@ -752,7 +757,19 @@ improvements or contribute with code or plugins of your own.
[Visit and contribute to the simpleSAMLphp wiki](https://ow.feide.no/simplesamlphp:start) [Visit and contribute to the simpleSAMLphp wiki](https://ow.feide.no/simplesamlphp:start)
A. Writing your own authentication module
A. IdP-first setup
------------------
If you do not want to start the SSO flow at the SP, you may use the IdP-first setup. To do this, redirect the user to the SSOService endpoint on the IdP with one parameter `spentityid` that match the SP EntityId that the user should be logged into.
Here is an example of such an url:
https://sp.example.org/simplesaml/saml2/idp/SSOService.php?spentityid=dev.andreas.feide.no
B. Writing your own authentication module
---------------------------------------------- ----------------------------------------------
You can write your own authentication module. Just copy one of the You can write your own authentication module. Just copy one of the
......
...@@ -165,6 +165,9 @@ idpdisco.url ...@@ -165,6 +165,9 @@ idpdisco.url
one is also unset, the builtin default discovery service will be one is also unset, the builtin default discovery service will be
used. used.
RelayState
: This may be a relative or absolute URL on the Service Provider that the user should be redirected to after successful authentication. This parameter MUST be used if you are using an IdP-first setup with SAML 2.0, where no AuthNRequest is sent.
privatekey privatekey
: File name of private key to be used for signing messages. : File name of private key to be used for signing messages.
......
...@@ -243,8 +243,6 @@ class SimpleSAML_Bindings_SAML20_HTTPRedirect { ...@@ -243,8 +243,6 @@ class SimpleSAML_Bindings_SAML20_HTTPRedirect {
SimpleSAML_Utilities::redirect($redirectURL); SimpleSAML_Utilities::redirect($redirectURL);
} }
} }
......
...@@ -718,8 +718,9 @@ class SimpleSAML_XML_SAML20_AuthnResponse extends SimpleSAML_XML_AuthnResponse { ...@@ -718,8 +718,9 @@ class SimpleSAML_XML_SAML20_AuthnResponse extends SimpleSAML_XML_AuthnResponse {
$nameid = $this->generateNameID($nameidformat, $nameIdValue, $spnamequalifier); $nameid = $this->generateNameID($nameidformat, $nameIdValue, $spnamequalifier);
} }
$inresponsetoText = '';
if (!empty($inresponseto)) $inresponsetoText = 'InResponseTo="' . htmlspecialchars($inresponseto). '" ';
$assertion = ""; $assertion = "";
if ($status === 'Success') { if ($status === 'Success') {
$assertion = '<saml:Assertion Version="2.0" $assertion = '<saml:Assertion Version="2.0"
...@@ -729,7 +730,7 @@ class SimpleSAML_XML_SAML20_AuthnResponse extends SimpleSAML_XML_AuthnResponse { ...@@ -729,7 +730,7 @@ class SimpleSAML_XML_SAML20_AuthnResponse extends SimpleSAML_XML_AuthnResponse {
' . $nameid . ' ' . $nameid . '
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="' . $assertionExpire . '" <saml:SubjectConfirmationData NotOnOrAfter="' . $assertionExpire . '"
InResponseTo="' . htmlspecialchars($inresponseto). '" ' . $inresponsetoText . '
Recipient="' . htmlspecialchars($destination) . '"/> Recipient="' . htmlspecialchars($destination) . '"/>
</saml:SubjectConfirmation> </saml:SubjectConfirmation>
</saml:Subject> </saml:Subject>
...@@ -763,7 +764,7 @@ class SimpleSAML_XML_SAML20_AuthnResponse extends SimpleSAML_XML_AuthnResponse { ...@@ -763,7 +764,7 @@ class SimpleSAML_XML_SAML20_AuthnResponse extends SimpleSAML_XML_AuthnResponse {
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
ID="' . $id . '" ID="' . $id . '"
InResponseTo="' . htmlspecialchars($inresponseto) . '" Version="2.0" ' . $inresponsetoText . ' Version="2.0"
IssueInstant="' . $issueInstant . '" IssueInstant="' . $issueInstant . '"
Destination="' . htmlspecialchars($destination) . '"> Destination="' . htmlspecialchars($destination) . '">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">' . htmlspecialchars($issuer) . '</saml:Issuer> <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">' . htmlspecialchars($issuer) . '</saml:Issuer>
......
...@@ -34,6 +34,11 @@ if (!$config->getValue('enable.saml20-idp', false)) ...@@ -34,6 +34,11 @@ if (!$config->getValue('enable.saml20-idp', false))
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NOACCESS'); SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NOACCESS');
/*
* Initiate some variables
*/
$isPassive = FALSE;
/* /*
* If the SAMLRequest query parameter is set, we got an incoming Authentication Request * If the SAMLRequest query parameter is set, we got an incoming Authentication Request
* at this interface. * at this interface.
...@@ -145,6 +150,19 @@ if (isset($_GET['SAMLRequest'])) { ...@@ -145,6 +150,19 @@ if (isset($_GET['SAMLRequest'])) {
$authProcState = SimpleSAML_Auth_ProcessingChain::fetchProcessedState($authProcId); $authProcState = SimpleSAML_Auth_ProcessingChain::fetchProcessedState($authProcId);
$requestcache = $authProcState['core:saml20-idp:requestcache']; $requestcache = $authProcState['core:saml20-idp:requestcache'];
/**
* If the spentityid parameter is provided, we will fallback to a unsolited response to the SP.
*/
} elseif(array_key_exists('spentityid', $_GET)) {
/* Creating a request cache, even though there was no request, and adding the
* information that is neccessary to be able to respond with an unsolited response
*/
$requestcache = array(
'Issuer' => $_GET['spentityid'],
);
} else { } else {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'SSOSERVICEPARAMS'); SimpleSAML_Utilities::fatalError($session->getTrackID(), 'SSOSERVICEPARAMS');
} }
...@@ -322,14 +340,17 @@ if($needAuth && !$isPassive) { ...@@ -322,14 +340,17 @@ if($needAuth && !$isPassive) {
// Right now the list is used for SAML 2.0 only. // Right now the list is used for SAML 2.0 only.
$session->add_sp_session($spentityid); $session->add_sp_session($spentityid);
$requestID = NULL; $relayState = NULL;
if (array_key_exists('RequestID', $requestcache)) $requestID = $requestcache['RequestID'];
if (array_key_exists('RelayState', $requestcache)) $relayState = $requestcache['RelayState'];
// Generate an SAML 2.0 AuthNResponse message // Generate an SAML 2.0 AuthNResponse message
$ar = new SimpleSAML_XML_SAML20_AuthnResponse($config, $metadata); $ar = new SimpleSAML_XML_SAML20_AuthnResponse($config, $metadata);
$authnResponseXML = $ar->generate($idpentityid, $spentityid, $requestcache['RequestID'], null, $attributes); $authnResponseXML = $ar->generate($idpentityid, $spentityid, $requestID, null, $attributes);
// Sending the AuthNResponse using HTTP-Post SAML 2.0 binding // Sending the AuthNResponse using HTTP-Post SAML 2.0 binding
$httppost = new SimpleSAML_Bindings_SAML20_HTTPPost($config, $metadata); $httppost = new SimpleSAML_Bindings_SAML20_HTTPPost($config, $metadata);
$httppost->sendResponse($authnResponseXML, $idmetaindex, $spentityid, $requestcache['RelayState']); $httppost->sendResponse($authnResponseXML, $idmetaindex, $spentityid, $relayState);
} catch(Exception $exception) { } catch(Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATEAUTHNRESPONSE', $exception); SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATEAUTHNRESPONSE', $exception);
......
...@@ -70,7 +70,8 @@ if (empty($_POST['SAMLResponse'])) ...@@ -70,7 +70,8 @@ if (empty($_POST['SAMLResponse']))
try { try {
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$spmetadata = $metadata->getMetaDataCurrent();
$binding = new SimpleSAML_Bindings_SAML20_HTTPPost($config, $metadata); $binding = new SimpleSAML_Bindings_SAML20_HTTPPost($config, $metadata);
$authnResponse = $binding->decodeResponse($_POST); $authnResponse = $binding->decodeResponse($_POST);
...@@ -83,7 +84,12 @@ try { ...@@ -83,7 +84,12 @@ try {
/* Fall back to RelayState. */ /* Fall back to RelayState. */
$info = array(); $info = array();
$info['RelayState'] = $authnResponse->getRelayState(); $info['RelayState'] = $authnResponse->getRelayState();
if(!isset($info['RelayState'])) { if(empty($info['RelayState'])) {
if (array_key_exists('RelayState', $spmetadata)) {
$info['RelayState'] = $spmetadata['RelayState'];
}
}
if(empty($info['RelayState'])) {
/* RelayState missing. */ /* RelayState missing. */
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NORELAYSTATE'); SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NORELAYSTATE');
} }
...@@ -111,7 +117,7 @@ try { ...@@ -111,7 +117,7 @@ try {
$idpentityid = $authnResponse->getIssuer(); $idpentityid = $authnResponse->getIssuer();
$idpmetadata = $metadata->getMetaData($idpentityid, 'saml20-idp-remote'); $idpmetadata = $metadata->getMetaData($idpentityid, 'saml20-idp-remote');
$spmetadata = $metadata->getMetaDataCurrent();
/* /*
......
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