summaryrefslogtreecommitdiffstats
path: root/lib/SimpleSAML
diff options
context:
space:
mode:
Diffstat (limited to 'lib/SimpleSAML')
-rw-r--r--lib/SimpleSAML/Auth/Default.php114
-rw-r--r--lib/SimpleSAML/Auth/Source.php140
-rw-r--r--lib/SimpleSAML/Auth/State.php171
3 files changed, 425 insertions, 0 deletions
diff --git a/lib/SimpleSAML/Auth/Default.php b/lib/SimpleSAML/Auth/Default.php
new file mode 100644
index 0000000..1013658
--- /dev/null
+++ b/lib/SimpleSAML/Auth/Default.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * Implements the default behaviour for authentication.
+ *
+ * This class contains an implementation for default behaviour when authenticating. It will
+ * save the session information it got from the authentication client in the users session.
+ *
+ * @author Olav Morken, UNINETT AS.
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SimpleSAML_Auth_Default {
+
+
+ /**
+ * Start authentication.
+ *
+ * This function never returns.
+ *
+ * @param string $authId The identifier of the authentication source.
+ * @param string $returnURL The URL we should direct the user to after authentication.
+ * @param string|NULL $errorURL The URL we should direct the user to after failed authentication.
+ * Can be NULL, in which case a standard error page will be shown.
+ * @param array $hints Extra information about the login. Different authentication requestors may
+ * provide different information. Optional, will default to an empty array.
+ */
+ public static function initLogin($authId, $returnURL, $errorURL = NULL, $hints = array()) {
+ assert('is_string($authId)');
+ assert('is_string($returnURL)');
+ assert('is_string($errorURL) || is_null($errorURL)');
+ assert('is_array($hints)');
+
+ $state = array(
+ 'SimpleSAML_Auth_Default.id' => $authId,
+ 'SimpleSAML_Auth_Default.ReturnURL' => $returnURL,
+ 'SimpleSAML_Auth_Default.ErrorURL' => $errorURL,
+ 'LoginCompletedHandler' => array(get_class(), 'loginCompleted'),
+ 'LoginFailedHandler' => array(get_class(), 'loginFailed'),
+ );
+
+ if (array_key_exists('SPMetadata', $hints)) {
+ $state['SPMetadata'] = $hints['SPMetadata'];
+ }
+ if (array_key_exists('IdPMetadata', $hints)) {
+ $state['IdPMetadata'] = $hints['IdPMetadata'];
+ }
+
+ $as = SimpleSAML_Auth_Source::getById($authId);
+ if ($as === NULL) {
+ throw new Exception('Invalid authentication source: ' . $authId);
+ }
+
+ $as->authenticate($state);
+ self::loginCompleted($state);
+ }
+
+
+ /**
+ * Called when a login operation has finished.
+ *
+ * @param array $state The state after the login.
+ */
+ public static function loginCompleted($state) {
+ assert('is_array($state)');
+ assert('array_key_exists("SimpleSAML_Auth_Default.ReturnURL", $state)');
+ assert('array_key_exists("SimpleSAML_Auth_Default.id", $state)');
+ assert('array_key_exists("Attributes", $state)');
+
+ $returnURL = $state['SimpleSAML_Auth_Default.ReturnURL'];
+
+ /* Save session state. */
+ $session = SimpleSAML_Session::getInstance();
+ $session->doLogin($state['SimpleSAML_Auth_Default.id']);
+ $session->setAttributes($state['Attributes']);
+ if(array_key_exists('Expires', $state)) {
+ $session->setSessionDuration($state['Expires'] - time());
+ }
+
+ /* Redirect... */
+ SimpleSAML_Utilities::redirect($returnURL);
+ }
+
+
+ /**
+ * Called when a login operation fails.
+ *
+ * @param array $state The state array.
+ * @param string $statusCode A status code, in the form of an URI, which indicates why the login failed.
+ * @param string $statusMessage A text which describes why the login failed.
+ */
+ public static function loginFailed($state, $statusCode, $statusMessage) {
+ assert('is_array($state)');
+ assert('array_key_exists("SimpleSAML_Auth_Default.ErrorURL", $state)');
+ assert('is_string($statusCode)');
+ assert('is_string($statusMessage)');
+
+ $url = $state['SimpleSAML_Auth_Default.ErrorURL'];
+ if ($url === NULL) {
+ /* We don't have an error handler. Show an error page. */
+ SimpleSAML_Utilities::fatalError($session->getTrackID(), 'RESPONSESTATUSNOSUCCESS',
+ new Exception('StatusCode = \'' . $statusCode . '\'; StatusMessage = \'' .
+ $statusMessage . '\';'));
+ }
+
+ $info = array('StatusCode' => $statusCode, 'StatusMessage' => $statusMessage);
+
+ /* Redirect... */
+ SimpleSAML_Utilities::redirect($url, $info);
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/lib/SimpleSAML/Auth/Source.php b/lib/SimpleSAML/Auth/Source.php
new file mode 100644
index 0000000..2c2f825
--- /dev/null
+++ b/lib/SimpleSAML/Auth/Source.php
@@ -0,0 +1,140 @@
+<?php
+
+/**
+ * This class defines a base class for authentication source.
+ *
+ * An authentication source is any system which somehow authenticate the user.
+ *
+ * @author Olav Morken, UNINETT AS.
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+abstract class SimpleSAML_Auth_Source {
+
+
+ /**
+ * The authentication source identifier.
+ *
+ * This identifier can be used to look up this object, for example when returning from a login form.
+ */
+ protected $authId;
+
+
+ /**
+ * Constructor for an authentication source.
+ *
+ * Any authentication source which implements its own constructor must call this
+ * constructor first.
+ *
+ * @param array $info Information about this authentication source.
+ * @param array &$config Configuration for this authentication source.
+ */
+ public function __construct($info, &$config) {
+ assert('is_array($info)');
+ assert('is_array($config)');
+
+ assert('array_key_exists("AuthId", $info)');
+ $this->authId = $info['AuthId'];
+ }
+
+
+ /**
+ * Process a request.
+ *
+ * If an authentication source returns from this function, it is assumed to have
+ * authenticated the user, and should have set elements in $state with the attributes
+ * of the user.
+ *
+ * If the authentication process requires additional steps which make it impossible to
+ * complete before returning from this function, the authentication source should
+ * save the state, and at a later stage, load the state, update it with the authentication
+ * information about the user, and call completeAuth with the state array.
+ *
+ * @param array &$state Information about the current authentication.
+ */
+ abstract public function authenticate(&$state);
+
+
+ /**
+ * Complete authentication.
+ *
+ * This function should be called if authentication has completed. It will never return,
+ * except in the case of exceptions. Exceptions thrown from this page should not be caught,
+ * but should instead be passed to the top-level exception handler.
+ *
+ * @param array &$state Information about the current authentication.
+ */
+ public static function completeAuth(&$state) {
+ assert('is_array($state)');
+ assert('array_key_exists("LoginCompletedHandler", $state)');
+
+ SimpleSAML_Auth_State::deleteState($state);
+
+ $func = $state['LoginCompletedHandler'];
+ assert('is_callable($func)');
+
+ call_user_func($func, $state);
+ assert(FALSE);
+ }
+
+
+ /**
+ * Create authentication source object from configuration array.
+ *
+ * This function takes an array with the configuration for an authentication source object,
+ * and returns the object.
+ *
+ * @param string $authId The authentication source identifier.
+ * @param array $config The configuration.
+ * @return SimpleSAML_Auth_Source The parsed authentication source.
+ */
+ private static function parseAuthSource($authId, $config) {
+ assert('is_string($authId)');
+ assert('is_array($config)');
+
+ if (!array_key_exists(0, $config) || !is_string($config[0])) {
+ throw new Exception('Invalid authentication source \'' . $authId .
+ '\': First element must be a string which identifies the authentication source.');
+ }
+
+ $className = SimpleSAML_Module::resolveClass($config[0], 'Auth_Source',
+ 'SimpleSAML_Auth_Source');
+
+ $info = array('AuthId' => $authId);
+ unset($config[0]);
+ return new $className($info, $config);
+ }
+
+
+ /**
+ * Retrieve authentication source.
+ *
+ * This function takes an id of an authentication source, and returns the
+ * AuthSource object.
+ *
+ * @param string $authId The authentication source identifier.
+ * @return SimpleSAML_Auth_Source|NULL The AuthSource object, or NULL if no authentication
+ * source with the given identifier is found.
+ */
+ public static function getById($authId) {
+ assert('is_string($authId)');
+
+ /* For now - load and parse config file. */
+ $globalConfig = SimpleSAML_Configuration::getInstance();
+ $config = $globalConfig->copyFromBase('authsources', 'authsources.php');
+
+ $authConfig = $config->getValue($authId, NULL);
+ if ($authConfig === NULL) {
+ return NULL;
+ }
+
+ if (!is_array($authConfig)) {
+ throw new Exception('Invalid configuration for authentication source \'' . $authId . '\'.');
+ }
+
+ return self::parseAuthSource($authId, $authConfig);
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/lib/SimpleSAML/Auth/State.php b/lib/SimpleSAML/Auth/State.php
new file mode 100644
index 0000000..8c16bc5
--- /dev/null
+++ b/lib/SimpleSAML/Auth/State.php
@@ -0,0 +1,171 @@
+<?php
+
+/**
+ * This is a helper class for saving and loading state information.
+ *
+ * The state must be an associative array. This class will add additional keys to this
+ * array. These keys will always start with 'SimpleSAML_Auth_State.'.
+ *
+ * It is also possible to add a restart URL to the state. If state information is lost, for
+ * example because it timed out, or the user loaded a bookmarked page, the loadState function
+ * will redirect to this URL. To use this, set $state[SimpleSAML_Auth_State::RESTART] to this
+ * URL.
+ *
+ * Both the saveState and the loadState function takes in a $stage parameter. This parameter is
+ * a security feature, and is used to prevent the user from taking a state saved one place and
+ * using it as input a different place.
+ *
+ * The $stage parameter must be a unique string. To maintain uniqueness, it must be on the form
+ * "<classname>.<identifier>" or "<module>:<identifier>".
+ *
+ * @author Olav Morken, UNINETT AS.
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SimpleSAML_Auth_State {
+
+
+ /**
+ * The index in the state array which contains the identifier.
+ */
+ const ID = 'SimpleSAML_Auth_State.id';
+
+
+ /**
+ * 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';
+
+
+ /**
+ * 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.
+ * @return string Identifier which can be used to retrieve the state later.
+ */
+ public static function saveState(&$state, $stage) {
+ assert('is_array($state)');
+ assert('is_string($stage)');
+
+ /* Save stage. */
+ $state[self::STAGE] = $stage;
+
+ if (!array_key_exists(self::ID, $state)) {
+ $state[self::ID] = SimpleSAML_Utilities::generateID();
+ }
+
+ $id = $state[self::ID];
+
+ /* Embed the restart URL in the state identifier, if it is available. */
+ if (array_key_exists(self::RESTART, $state)) {
+ assert('is_string($state[self::RESTART])');
+ $return = $id . ':' . $state[self::RESTART];
+ } else {
+ $return = $id;
+ }
+
+ $serializedState = serialize($state);
+
+ $session = SimpleSAML_Session::getInstance();
+ $session->setData('SimpleSAML_Auth_State', $id, $serializedState, 60*60);
+
+ return $return;
+ }
+
+
+ /**
+ * 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.
+ * @return array State information.
+ */
+ public static function loadState($id, $stage) {
+ assert('is_string($id)');
+ assert('is_string($stage)');
+
+ $tmp = explode(':', $id, 2);
+ $id = $tmp[0];
+ if (count($tmp) === 2) {
+ $restartURL = $tmp[1];
+ } else {
+ $restartURL = NULL;
+ }
+
+ $session = SimpleSAML_Session::getInstance();
+ $state = $session->getData('SimpleSAML_Auth_State', $id);
+
+ if ($state === NULL) {
+ /* Could not find saved data. Attempt to restart. */
+
+ if ($restartURL === NULL) {
+ throw new Exception('State information lost, and no way to restart the request.');
+ }
+
+ SimpleSAML_Utilities::redirect($restartURL);
+ }
+
+ $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] .
+ '\', shoud be \'' . $stage . '\'.';
+
+ SimpleSAML_Logger::warning($msg);
+
+ if ($restartURL === NULL) {
+ throw new Exception($msg);
+ }
+
+ SimpleSAML_Utilities::redirect($restartURL);
+ }
+
+ 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;
+ }
+
+ $session = SimpleSAML_Session::getInstance();
+ $session->deleteData('SimpleSAML_Auth_State', $state[self::ID]);
+ }
+
+}
+
+?> \ No newline at end of file