From 126f7405433f06c279d7d5254118fc85b95aa1e2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20=C3=85kre=20Solberg?= <andreas.solberg@uninett.no>
Date: Fri, 6 Feb 2009 09:37:38 +0000
Subject: [PATCH] Add support for bootstrapping an unsolited Response when
 session is lost during login. The scenario this feature is targeted to solve
 is that end users is bookmarking the login page and returning to the login
 page after the session has timed out. Then the cache of the request is lost,
 and the SP is unlikely to be able to match the request with the response. The
 fallback that is implemented is that the response unsolited, meaning that the
 InResponseTo is dropped and the response does not need to be matched against
 a request.

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@1245 44740490-163a-0410-bde0-09ae8108e29a
---
 lib/SimpleSAML/Auth/Default.php          |  3 +++
 modules/core/lib/Auth/UserPassBase.php   | 21 ++++++++++++++++-----
 modules/core/templates/loginuserpass.php |  7 +++++++
 modules/core/www/loginuserpass.php       |  2 ++
 www/saml2/idp/SSOService.php             |  6 +++++-
 5 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/lib/SimpleSAML/Auth/Default.php b/lib/SimpleSAML/Auth/Default.php
index 2f35a96a3..0d7cc0d68 100644
--- a/lib/SimpleSAML/Auth/Default.php
+++ b/lib/SimpleSAML/Auth/Default.php
@@ -49,6 +49,9 @@ class SimpleSAML_Auth_Default {
 		if (array_key_exists('IdPMetadata', $hints)) {
 			$state['IdPMetadata'] = $hints['IdPMetadata'];
 		}
+		if (array_key_exists('SessionLostURL', $hints)) {
+			$state['SessionLostURL'] = $hints['SessionLostURL'];
+		}
 
 		$as = SimpleSAML_Auth_Source::getById($authId);
 		if ($as === NULL) {
diff --git a/modules/core/lib/Auth/UserPassBase.php b/modules/core/lib/Auth/UserPassBase.php
index 01a1b8f3a..33d2a940b 100644
--- a/modules/core/lib/Auth/UserPassBase.php
+++ b/modules/core/lib/Auth/UserPassBase.php
@@ -60,7 +60,10 @@ abstract class sspmod_core_Auth_UserPassBase extends SimpleSAML_Auth_Source {
 		$id = SimpleSAML_Auth_State::saveState($state, self::STAGEID);
 
 		$url = SimpleSAML_Module::getModuleURL('core/loginuserpass.php');
-		SimpleSAML_Utilities::redirect($url, array('AuthState' => $id));
+		$params = array('AuthState' => $id);
+		if (array_key_exists('SessionLostURL', $state))
+			$params['SessionLostURL'] = $state['SessionLostURL'];
+		SimpleSAML_Utilities::redirect($url, $params);
 	}
 
 
@@ -91,16 +94,24 @@ abstract class sspmod_core_Auth_UserPassBase extends SimpleSAML_Auth_Source {
 	 * @param string $authStateId  The identifier of the authentication state.
 	 * @param string $username  The username the user wrote.
 	 * @param string $password  The password the user wrote.
-	 * @return string  Error code in the case of an error.
+	 * @return string Error code in the case of an error.
 	 */
 	public static function handleLogin($authStateId, $username, $password) {
 		assert('is_string($authStateId)');
 		assert('is_string($username)');
 		assert('is_string($password)');
 
-		/* Retrieve the authentication state. */
-		$state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID);
-
+		try {
+			/* Retrieve the authentication state. */
+			$state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID);
+		} catch(Exception $e) {
+			if (array_key_exists('SessionLostURL', $_REQUEST)) {
+				SimpleSAML_Utilities::redirect($_REQUEST['SessionLostURL']);
+			} else {
+				throw $e;
+			}
+		}
+		
 		/* Find authentication source. */
 		assert('array_key_exists(self::AUTHID, $state)');
 		$source = SimpleSAML_Auth_Source::getById($state[self::AUTHID]);
diff --git a/modules/core/templates/loginuserpass.php b/modules/core/templates/loginuserpass.php
index 810abda1f..3a09ab2de 100644
--- a/modules/core/templates/loginuserpass.php
+++ b/modules/core/templates/loginuserpass.php
@@ -29,7 +29,14 @@ if ($this->data['errorcode'] !== NULL) {
 	<p><?php echo $this->t('{login:user_pass_text}'); ?></p>
 
 	<form action="?" method="post" name="f">
+<?php
+
+if (array_key_exists('SessionLostURL', $this->data)) {
+	echo('<input type="hidden" name="SessionLostURL" value="' . $this->data['SessionLostURL'] . '" />');
+}
 
+
+?>
 	<table>
 		<tr>
 			<td rowspan="2"><img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/pencil.png" alt="" /></td>
diff --git a/modules/core/www/loginuserpass.php b/modules/core/www/loginuserpass.php
index a7bfdb291..aa21292e6 100644
--- a/modules/core/www/loginuserpass.php
+++ b/modules/core/www/loginuserpass.php
@@ -39,6 +39,8 @@ $t = new SimpleSAML_XHTML_Template($globalConfig, 'core:loginuserpass.php');
 $t->data['stateparams'] = array('AuthState' => $authStateId);
 $t->data['username'] = $username;
 $t->data['errorcode'] = $errorCode;
+if (array_key_exists('SessionLostURL', $_REQUEST)) 
+	$t->data['SessionLostURL'] = $_REQUEST['SessionLostURL'];
 $t->show();
 exit();
 
diff --git a/www/saml2/idp/SSOService.php b/www/saml2/idp/SSOService.php
index e6865f882..ef6520c4c 100644
--- a/www/saml2/idp/SSOService.php
+++ b/www/saml2/idp/SSOService.php
@@ -216,7 +216,11 @@ if($needAuth && !$isPassive) {
 			'SPMetadata' => $metadata->getMetaData($requestcache['Issuer'], 'saml20-sp-remote'),
 			'IdPMetadata' => $idpmetadata,
 		);
-
+		$hints['SessionLostURL'] = SimpleSAML_Utilities::addURLparameter(
+			$metadata->getGenerated('SingleSignOnService', 'saml20-idp-hosted'), array(
+				'spentityid' => $requestcache['Issuer'],
+			)
+		);
 		SimpleSAML_Auth_Default::initLogin($idpmetadata['auth'], $redirectTo, NULL, $hints);
 	} else {
 		$authurl = '/' . $config->getBaseURL() . $idpmetadata['auth'];
-- 
GitLab