summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaime Perez Crespo <jaime.perez@uninett.no>2016-04-15 11:12:51 +0200
committerJaime Perez Crespo <jaime.perez@uninett.no>2016-04-15 11:12:51 +0200
commit8de8f3571d87ca1d6813c0ad5e76cf58b657cb0d (patch)
tree30e8e7cd70b4303fd309a4f1b3ff22645a226223
parentf0d848d7883f1bcaf26bf0124a493563dfbe7b83 (diff)
downloadsimplesamlphp-8de8f3571d87ca1d6813c0ad5e76cf58b657cb0d.zip
simplesamlphp-8de8f3571d87ca1d6813c0ad5e76cf58b657cb0d.tar.gz
simplesamlphp-8de8f3571d87ca1d6813c0ad5e76cf58b657cb0d.tar.bz2
Reformat the SimpleSAML_Auth_State class.
-rw-r--r--lib/SimpleSAML/Auth/State.php751
1 files changed, 386 insertions, 365 deletions
diff --git a/lib/SimpleSAML/Auth/State.php b/lib/SimpleSAML/Auth/State.php
index b08b5a1..447f961 100644
--- a/lib/SimpleSAML/Auth/State.php
+++ b/lib/SimpleSAML/Auth/State.php
@@ -1,5 +1,6 @@
<?php
+
/**
* This is a helper class for saving and loading state information.
*
@@ -27,374 +28,394 @@
* @author Olav Morken, UNINETT AS.
* @package SimpleSAMLphp
*/
-class SimpleSAML_Auth_State {
-
-
- /**
- * The index in the state array which contains the identifier.
- */
- const ID = 'SimpleSAML_Auth_State.id';
-
-
- /**
- * The index in the cloned state array which contains the identifier of the
- * original state.
- */
- const CLONE_ORIGINAL_ID = 'SimpleSAML_Auth_State.cloneOriginalId';
-
-
- /**
- * The index in the state array which contains the current stage.
- */
- const STAGE = 'SimpleSAML_Auth_State.stage';
-
-
- /**
- * The index in the state array which contains the restart URL.
- */
- const RESTART = 'SimpleSAML_Auth_State.restartURL';
+class SimpleSAML_Auth_State
+{
- /**
- * The index in the state array which contains the exception handler URL.
- */
- const EXCEPTION_HANDLER_URL = 'SimpleSAML_Auth_State.exceptionURL';
-
-
- /**
- * The index in the state array which contains the exception handler function.
- */
- const EXCEPTION_HANDLER_FUNC = 'SimpleSAML_Auth_State.exceptionFunc';
-
-
- /**
- * The index in the state array which contains the exception data.
- */
- const EXCEPTION_DATA = 'SimpleSAML_Auth_State.exceptionData';
+ /**
+ * The index in the state array which contains the identifier.
+ */
+ const ID = 'SimpleSAML_Auth_State.id';
- /**
- * The stage of a state with an exception.
- */
- const EXCEPTION_STAGE = 'SimpleSAML_Auth_State.exceptionStage';
-
-
- /**
- * The URL parameter which contains the exception state id.
- */
- const EXCEPTION_PARAM = 'SimpleSAML_Auth_State_exceptionId';
-
-
- /**
- * State timeout.
- */
- private static $stateTimeout = NULL;
-
-
- /**
- * Get the persistent authentication state from the state array.
- *
- * @param array $state The state array to analyze.
- * @return array The persistent authentication state.
- */
- public static function getPersistentAuthData(array $state)
- {
- // save persistent authentication data
- $persistent = array();
-
- if (array_key_exists('PersistentAuthData', $state)) {
- foreach ($state['PersistentAuthData'] as $key) {
- if (isset($state[$key])) {
- $persistent[$key] = $state[$key];
- }
- }
- }
-
- // add those that should always be included
- $mandatory = array(
- 'Attributes',
- 'Expire',
- 'LogoutState',
- 'AuthInstant',
- 'RememberMe',
- 'saml:sp:NameID'
- );
- foreach ($mandatory as $key) {
- if (isset($state[$key])) {
- $persistent[$key] = $state[$key];
- }
- }
-
- return $persistent;
- }
-
-
- /**
- * Retrieve the ID of a state array.
- *
- * Note that this function will not save the state.
- *
- * @param array &$state The state array.
- * @param bool $rawId Return a raw ID, without a restart URL. Defaults to FALSE.
- * @return string Identifier which can be used to retrieve the state later.
- */
- public static function getStateId(&$state, $rawId = FALSE) {
- assert('is_array($state)');
- assert('is_bool($rawId)');
-
- if (!array_key_exists(self::ID, $state)) {
- $state[self::ID] = SimpleSAML\Utils\Random::generateID();
- }
-
- $id = $state[self::ID];
-
- if ($rawId || !array_key_exists(self::RESTART, $state)) {
- // Either raw ID or no restart URL. In any case, return the raw ID.
- return $id;
- }
-
- // We have a restart URL. Return the ID with that URL.
- return $id . ':' . $state[self::RESTART];
- }
-
-
- /**
- * Retrieve state timeout.
- *
- * @return integer State timeout.
- */
- private static function getStateTimeout() {
- if (self::$stateTimeout === NULL) {
- $globalConfig = SimpleSAML_Configuration::getInstance();
- self::$stateTimeout = $globalConfig->getInteger('session.state.timeout', 60*60);
- }
-
- return self::$stateTimeout;
- }
-
-
- /**
- * Save the state.
- *
- * This function saves the state, and returns an id which can be used to
- * retrieve it later. It will also update the $state array with the identifier.
- *
- * @param array &$state The login request state.
- * @param string $stage The current stage in the login process.
- * @param bool $rawId Return a raw ID, without a restart URL.
- * @return string Identifier which can be used to retrieve the state later.
- */
- public static function saveState(&$state, $stage, $rawId = FALSE) {
- assert('is_array($state)');
- assert('is_string($stage)');
- assert('is_bool($rawId)');
-
- $return = self::getStateId($state, $rawId);
- $id = $state[self::ID];
-
- // Save stage
- $state[self::STAGE] = $stage;
-
- // Save state
- $serializedState = serialize($state);
- $session = SimpleSAML_Session::getSessionFromRequest();
- $session->setData('SimpleSAML_Auth_State', $id, $serializedState, self::getStateTimeout());
-
- SimpleSAML\Logger::debug('Saved state: ' . var_export($return, TRUE));
-
- return $return;
- }
-
-
- /**
- * Clone the state.
- *
- * This function clones and returns the new cloned state.
- *
- * @param array $state The original request state.
- * @return array Cloned state data.
- */
- public static function cloneState(array $state) {
- $clonedState = $state;
-
- if (array_key_exists(self::ID, $state)) {
- $clonedState[self::CLONE_ORIGINAL_ID] = $state[self::ID];
- unset($clonedState[self::ID]);
-
- SimpleSAML\Logger::debug('Cloned state: ' . var_export($state[self::ID], TRUE));
- } else {
- SimpleSAML\Logger::debug('Cloned state with undefined id.');
- }
-
- return $clonedState;
- }
-
-
- /**
- * Retrieve saved state.
- *
- * This function retrieves saved state information. If the state information has been lost,
- * it will attempt to restart the request by calling the restart URL which is embedded in the
- * state information. If there is no restart information available, an exception will be thrown.
- *
- * @param string $id State identifier (with embedded restart information).
- * @param string $stage The stage the state should have been saved in.
- * @param bool $allowMissing Whether to allow the state to be missing.
- * @return array|NULL State information, or NULL if the state is missing and $allowMissing is TRUE.
- */
- public static function loadState($id, $stage, $allowMissing = FALSE) {
- assert('is_string($id)');
- assert('is_string($stage)');
- assert('is_bool($allowMissing)');
- SimpleSAML\Logger::debug('Loading state: ' . var_export($id, TRUE));
-
- $sid = self::parseStateID($id);
-
- $session = SimpleSAML_Session::getSessionFromRequest();
- $state = $session->getData('SimpleSAML_Auth_State', $sid['id']);
-
- if ($state === NULL) {
- // Could not find saved data
- if ($allowMissing) {
- return NULL;
- }
-
- if ($sid['url'] === NULL) {
- throw new SimpleSAML_Error_NoState();
- }
-
- \SimpleSAML\Utils\HTTP::redirectUntrustedURL($sid['url']);
- }
-
- $state = unserialize($state);
- assert('is_array($state)');
- assert('array_key_exists(self::ID, $state)');
- assert('array_key_exists(self::STAGE, $state)');
-
- // Verify stage
- if ($state[self::STAGE] !== $stage) {
- /* This could be a user trying to bypass security, but most likely it is just
- * someone using the back-button in the browser. We try to restart the
- * request if that is possible. If not, show an error.
- */
-
- $msg = 'Wrong stage in state. Was \'' . $state[self::STAGE] .
- '\', should be \'' . $stage . '\'.';
-
- SimpleSAML\Logger::warning($msg);
-
- if ($sid['url'] === NULL) {
- throw new Exception($msg);
- }
-
- \SimpleSAML\Utils\HTTP::redirectUntrustedURL($sid['url']);
- }
-
- return $state;
- }
-
-
- /**
- * Delete state.
- *
- * This function deletes the given state to prevent the user from reusing it later.
- *
- * @param array &$state The state which should be deleted.
- */
- public static function deleteState(&$state) {
- assert('is_array($state)');
-
- if (!array_key_exists(self::ID, $state)) {
- // This state hasn't been saved
- return;
- }
-
- SimpleSAML\Logger::debug('Deleting state: ' . var_export($state[self::ID], TRUE));
-
- $session = SimpleSAML_Session::getSessionFromRequest();
- $session->deleteData('SimpleSAML_Auth_State', $state[self::ID]);
- }
-
-
- /**
- * Throw exception to the state exception handler.
- *
- * @param array $state The state array.
- * @param SimpleSAML_Error_Exception $exception The exception.
- */
- public static function throwException($state, SimpleSAML_Error_Exception $exception) {
- assert('is_array($state)');
-
- if (array_key_exists(self::EXCEPTION_HANDLER_URL, $state)) {
-
- // Save the exception
- $state[self::EXCEPTION_DATA] = $exception;
- $id = self::saveState($state, self::EXCEPTION_STAGE);
-
- // Redirect to the exception handler
- \SimpleSAML\Utils\HTTP::redirectTrustedURL($state[self::EXCEPTION_HANDLER_URL], array(self::EXCEPTION_PARAM => $id));
-
- } elseif (array_key_exists(self::EXCEPTION_HANDLER_FUNC, $state)) {
- // Call the exception handler
- $func = $state[self::EXCEPTION_HANDLER_FUNC];
- assert('is_callable($func)');
-
- call_user_func($func, $exception, $state);
- assert(FALSE);
-
- } else {
- /*
- * No exception handler is defined for the current state.
- */
- throw $exception;
- }
-
- }
-
-
- /**
- * Retrieve an exception state.
- *
- * @param string|NULL $id The exception id. Can be NULL, in which case it will be retrieved from the request.
- * @return array|NULL The state array with the exception, or NULL if no exception was thrown.
- */
- public static function loadExceptionState($id = NULL) {
- assert('is_string($id) || is_null($id)');
-
- if ($id === NULL) {
- if (!array_key_exists(self::EXCEPTION_PARAM, $_REQUEST)) {
- // No exception
- return NULL;
- }
- $id = $_REQUEST[self::EXCEPTION_PARAM];
- }
-
- $state = self::loadState($id, self::EXCEPTION_STAGE);
- assert('array_key_exists(self::EXCEPTION_DATA, $state)');
-
- return $state;
- }
-
-
- /**
- * Get the ID and (optionally) a URL embedded in a StateID, in the form 'id:url'.
- *
- * @param string $stateId The state ID to use.
- *
- * @return array A hashed array with the ID and the URL (if any), in the 'id' and 'url' keys, respectively. If
- * there's no URL in the input parameter, NULL will be returned as the value for the 'url' key.
- *
- * @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no>
- * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
- */
- public static function parseStateID($stateId) {
- $tmp = explode(':', $stateId, 2);
- $id = $tmp[0];
- $url = null;
- if (count($tmp) === 2) {
- $url = $tmp[1];
- }
- return array('id' => $id, 'url' => $url);
- }
+ /**
+ * The index in the cloned state array which contains the identifier of the
+ * original state.
+ */
+ const CLONE_ORIGINAL_ID = 'SimpleSAML_Auth_State.cloneOriginalId';
+
+
+ /**
+ * The index in the state array which contains the current stage.
+ */
+ const STAGE = 'SimpleSAML_Auth_State.stage';
+
+
+ /**
+ * The index in the state array which contains the restart URL.
+ */
+ const RESTART = 'SimpleSAML_Auth_State.restartURL';
+
+
+ /**
+ * The index in the state array which contains the exception handler URL.
+ */
+ const EXCEPTION_HANDLER_URL = 'SimpleSAML_Auth_State.exceptionURL';
+
+ /**
+ * The index in the state array which contains the exception handler function.
+ */
+ const EXCEPTION_HANDLER_FUNC = 'SimpleSAML_Auth_State.exceptionFunc';
+
+
+ /**
+ * The index in the state array which contains the exception data.
+ */
+ const EXCEPTION_DATA = 'SimpleSAML_Auth_State.exceptionData';
+
+
+ /**
+ * The stage of a state with an exception.
+ */
+ const EXCEPTION_STAGE = 'SimpleSAML_Auth_State.exceptionStage';
+
+
+ /**
+ * The URL parameter which contains the exception state id.
+ */
+ const EXCEPTION_PARAM = 'SimpleSAML_Auth_State_exceptionId';
+
+
+ /**
+ * State timeout.
+ */
+ private static $stateTimeout = null;
+
+
+ /**
+ * Get the persistent authentication state from the state array.
+ *
+ * @param array $state The state array to analyze.
+ *
+ * @return array The persistent authentication state.
+ */
+ public static function getPersistentAuthData(array $state)
+ {
+ // save persistent authentication data
+ $persistent = array();
+
+ if (array_key_exists('PersistentAuthData', $state)) {
+ foreach ($state['PersistentAuthData'] as $key) {
+ if (isset($state[$key])) {
+ $persistent[$key] = $state[$key];
+ }
+ }
+ }
+
+ // add those that should always be included
+ $mandatory = array(
+ 'Attributes',
+ 'Expire',
+ 'LogoutState',
+ 'AuthInstant',
+ 'RememberMe',
+ 'saml:sp:NameID'
+ );
+ foreach ($mandatory as $key) {
+ if (isset($state[$key])) {
+ $persistent[$key] = $state[$key];
+ }
+ }
+
+ return $persistent;
+ }
+
+
+ /**
+ * Retrieve the ID of a state array.
+ *
+ * Note that this function will not save the state.
+ *
+ * @param array &$state The state array.
+ * @param bool $rawId Return a raw ID, without a restart URL. Defaults to FALSE.
+ *
+ * @return string Identifier which can be used to retrieve the state later.
+ */
+ public static function getStateId(&$state, $rawId = false)
+ {
+ assert('is_array($state)');
+ assert('is_bool($rawId)');
+
+ if (!array_key_exists(self::ID, $state)) {
+ $state[self::ID] = SimpleSAML\Utils\Random::generateID();
+ }
+
+ $id = $state[self::ID];
+
+ if ($rawId || !array_key_exists(self::RESTART, $state)) {
+ // Either raw ID or no restart URL. In any case, return the raw ID.
+ return $id;
+ }
+
+ // We have a restart URL. Return the ID with that URL.
+ return $id.':'.$state[self::RESTART];
+ }
+
+
+ /**
+ * Retrieve state timeout.
+ *
+ * @return integer State timeout.
+ */
+ private static function getStateTimeout()
+ {
+ if (self::$stateTimeout === null) {
+ $globalConfig = SimpleSAML_Configuration::getInstance();
+ self::$stateTimeout = $globalConfig->getInteger('session.state.timeout', 60 * 60);
+ }
+
+ return self::$stateTimeout;
+ }
+
+
+ /**
+ * Save the state.
+ *
+ * This function saves the state, and returns an id which can be used to
+ * retrieve it later. It will also update the $state array with the identifier.
+ *
+ * @param array &$state The login request state.
+ * @param string $stage The current stage in the login process.
+ * @param bool $rawId Return a raw ID, without a restart URL.
+ *
+ * @return string Identifier which can be used to retrieve the state later.
+ */
+ public static function saveState(&$state, $stage, $rawId = false)
+ {
+ assert('is_array($state)');
+ assert('is_string($stage)');
+ assert('is_bool($rawId)');
+
+ $return = self::getStateId($state, $rawId);
+ $id = $state[self::ID];
+
+ // Save stage
+ $state[self::STAGE] = $stage;
+
+ // Save state
+ $serializedState = serialize($state);
+ $session = SimpleSAML_Session::getSessionFromRequest();
+ $session->setData('SimpleSAML_Auth_State', $id, $serializedState, self::getStateTimeout());
+
+ SimpleSAML\Logger::debug('Saved state: '.var_export($return, true));
+
+ return $return;
+ }
+
+
+ /**
+ * Clone the state.
+ *
+ * This function clones and returns the new cloned state.
+ *
+ * @param array $state The original request state.
+ *
+ * @return array Cloned state data.
+ */
+ public static function cloneState(array $state)
+ {
+ $clonedState = $state;
+
+ if (array_key_exists(self::ID, $state)) {
+ $clonedState[self::CLONE_ORIGINAL_ID] = $state[self::ID];
+ unset($clonedState[self::ID]);
+
+ SimpleSAML\Logger::debug('Cloned state: '.var_export($state[self::ID], true));
+ } else {
+ SimpleSAML\Logger::debug('Cloned state with undefined id.');
+ }
+
+ return $clonedState;
+ }
+
+
+ /**
+ * Retrieve saved state.
+ *
+ * This function retrieves saved state information. If the state information has been lost,
+ * it will attempt to restart the request by calling the restart URL which is embedded in the
+ * state information. If there is no restart information available, an exception will be thrown.
+ *
+ * @param string $id State identifier (with embedded restart information).
+ * @param string $stage The stage the state should have been saved in.
+ * @param bool $allowMissing Whether to allow the state to be missing.
+ *
+ * @throws SimpleSAML_Error_NoState If we couldn't find the state and there's no URL defined to redirect to.
+ * @throws Exception If the stage of the state is invalid and there's no URL defined to redirect to.
+ *
+ * @return array|NULL State information, or null if the state is missing and $allowMissing is true.
+ */
+ public static function loadState($id, $stage, $allowMissing = false)
+ {
+ assert('is_string($id)');
+ assert('is_string($stage)');
+ assert('is_bool($allowMissing)');
+ SimpleSAML\Logger::debug('Loading state: '.var_export($id, true));
+
+ $sid = self::parseStateID($id);
+
+ $session = SimpleSAML_Session::getSessionFromRequest();
+ $state = $session->getData('SimpleSAML_Auth_State', $sid['id']);
+
+ if ($state === null) {
+ // Could not find saved data
+ if ($allowMissing) {
+ return null;
+ }
+
+ if ($sid['url'] === null) {
+ throw new SimpleSAML_Error_NoState();
+ }
+
+ \SimpleSAML\Utils\HTTP::redirectUntrustedURL($sid['url']);
+ }
+
+ $state = unserialize($state);
+ assert('is_array($state)');
+ assert('array_key_exists(self::ID, $state)');
+ assert('array_key_exists(self::STAGE, $state)');
+
+ // Verify stage
+ if ($state[self::STAGE] !== $stage) {
+ /* This could be a user trying to bypass security, but most likely it is just
+ * someone using the back-button in the browser. We try to restart the
+ * request if that is possible. If not, show an error.
+ */
+
+ $msg = 'Wrong stage in state. Was \''.$state[self::STAGE].
+ '\', should be \''.$stage.'\'.';
+
+ SimpleSAML\Logger::warning($msg);
+
+ if ($sid['url'] === null) {
+ throw new Exception($msg);
+ }
+
+ \SimpleSAML\Utils\HTTP::redirectUntrustedURL($sid['url']);
+ }
+
+ return $state;
+ }
+
+
+ /**
+ * Delete state.
+ *
+ * This function deletes the given state to prevent the user from reusing it later.
+ *
+ * @param array &$state The state which should be deleted.
+ */
+ public static function deleteState(&$state)
+ {
+ assert('is_array($state)');
+
+ if (!array_key_exists(self::ID, $state)) {
+ // This state hasn't been saved
+ return;
+ }
+
+ SimpleSAML\Logger::debug('Deleting state: '.var_export($state[self::ID], true));
+
+ $session = SimpleSAML_Session::getSessionFromRequest();
+ $session->deleteData('SimpleSAML_Auth_State', $state[self::ID]);
+ }
+
+
+ /**
+ * Throw exception to the state exception handler.
+ *
+ * @param array $state The state array.
+ * @param SimpleSAML_Error_Exception $exception The exception.
+ *
+ * @throws SimpleSAML_Error_Exception If there is no exception handler defined, it will just throw the $exception.
+ */
+ public static function throwException($state, SimpleSAML_Error_Exception $exception)
+ {
+ assert('is_array($state)');
+
+ if (array_key_exists(self::EXCEPTION_HANDLER_URL, $state)) {
+
+ // Save the exception
+ $state[self::EXCEPTION_DATA] = $exception;
+ $id = self::saveState($state, self::EXCEPTION_STAGE);
+
+ // Redirect to the exception handler
+ \SimpleSAML\Utils\HTTP::redirectTrustedURL(
+ $state[self::EXCEPTION_HANDLER_URL],
+ array(self::EXCEPTION_PARAM => $id)
+ );
+ } elseif (array_key_exists(self::EXCEPTION_HANDLER_FUNC, $state)) {
+ // Call the exception handler
+ $func = $state[self::EXCEPTION_HANDLER_FUNC];
+ assert('is_callable($func)');
+
+ call_user_func($func, $exception, $state);
+ assert(false);
+ } else {
+ /*
+ * No exception handler is defined for the current state.
+ */
+ throw $exception;
+ }
+ }
+
+
+ /**
+ * Retrieve an exception state.
+ *
+ * @param string|NULL $id The exception id. Can be NULL, in which case it will be retrieved from the request.
+ *
+ * @return array|NULL The state array with the exception, or NULL if no exception was thrown.
+ */
+ public static function loadExceptionState($id = null)
+ {
+ assert('is_string($id) || is_null($id)');
+
+ if ($id === null) {
+ if (!array_key_exists(self::EXCEPTION_PARAM, $_REQUEST)) {
+ // No exception
+ return null;
+ }
+ $id = $_REQUEST[self::EXCEPTION_PARAM];
+ }
+
+ $state = self::loadState($id, self::EXCEPTION_STAGE);
+ assert('array_key_exists(self::EXCEPTION_DATA, $state)');
+
+ return $state;
+ }
+
+
+ /**
+ * Get the ID and (optionally) a URL embedded in a StateID, in the form 'id:url'.
+ *
+ * @param string $stateId The state ID to use.
+ *
+ * @return array A hashed array with the ID and the URL (if any), in the 'id' and 'url' keys, respectively. If
+ * there's no URL in the input parameter, NULL will be returned as the value for the 'url' key.
+ *
+ * @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no>
+ * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
+ */
+ public static function parseStateID($stateId)
+ {
+ $tmp = explode(':', $stateId, 2);
+ $id = $tmp[0];
+ $url = null;
+ if (count($tmp) === 2) {
+ $url = $tmp[1];
+ }
+ return array('id' => $id, 'url' => $url);
+ }
}