create(); } /** Build the session structure with system fields. */ protected function fillSession() { S::bootstrap('user', null); S::bootstrap('auth', AUTH_PUBLIC); S::bootstrap('challenge', sha1(uniqid(rand(), true))); S::bootstrap('xsrf_token', rand_url_id()); S::bootstrap('perms', new PlFlagSet()); } /** Write current session and close it. */ public function close() { session_write_close(); } /** Create a new session */ private function create() { session_start(); $this->fillSession(); } /** Kill the current session. */ public function destroy() { session_destroy(); unset($_SESSION); $this->create(); } /** Check if the user has at least the given authentication level. */ public function checkAuth($level) { return S::i('auth') >= $level; } /** Check if the user has the given permissions. */ public function checkPerms($perms) { return S::v('perms')->hasFlagCombination($perms); } /** Run authentication procedure to reach at least the given level. */ public function start($level) { if ($this->checkAuth($level)) { return true; } $user = $this->doAuth($level); if (is_null($user)) { return false; } if (!$this->checkAuth($level)) { $this->destroy(); return false; } if ($this->startSessionAs($user, $level)) { if (is_null(S::v('user'))) { S::set('user', $user); } return true; } else { $this->destroy(); } return false; } /*** Abstract methods ***/ /** Function that check authentication at build time of the session object. * This is useful to perform authentication from a cookie or when coming * back from a authentication service. * * This function must NOT try to launch a new authenticatioin procedure. It * just tests if the environment contains sufficient information to start * a user session. * * This function return false if informations are available but lead to an * authentication failure (invalid cookie, invalid service return data...) */ abstract public function startAvailableAuth(); /** Run the effectively authentication procedure to reach the given user. * This method must return a user object (that will be used to fill the * $_SESSION['user'] field). * * If auth failed, the function MUST return null. If auth succeed, the * field $_SESSION['auth'] MUST be filled to the current effective level. */ abstract protected function doAuth($level); /** Set the session environment to the given user and authentication level. * This function MUST return false if a session is already started and the * user mismatch. * * On succes, this function MUST return true. * If $level is set to -1, this means you are building a new SUID session. */ abstract protected function startSessionAs($user, $level); /** Authenticate the request for the given (method, payload) pair. * * Implementations are expected to provide strong authentication. It is * suggested to use an HMAC-based scheme, where the signature validates the * method, url, and payload (to avoid replay of the signature against other * methods), and the timestamp (to avoid replay in time). * * @param method method of the request (GET, POST, PUT, DELETE) * @param resource URL path of the resource (eg. "/api/user") * @param payload binary payload sent with the request (before decoding) * @return a valid PlUser object if authentication is successfull, or null. */ public function apiAuth($method, $resource, $payload) { return null; // Default implementation does nothing } /** Check authentication with the given token. * * Token authentication is a light-weight authentication based on a user-specific token. * This can be used for protocols that requires a 'cookie'-free authentication, such as * RSS, iCal registration... * * This function returns a valid user object if authentication is successful, or null if * token mismatch. */ abstract public function tokenAuth($login, $token); /** Set the permissions to the given flagset. * * This function sets S::set('perms') with a flagset represeting the combination of * $perms and $is_admin. * * $perms is an abstract object representing the permissions. * $is_admin is a boolean, true if the current user has site-administration rights. */ abstract protected function makePerms($perms, $is_admin); /*** SUID management ***/ /** Start a new SUID session. */ public function startSUID($user, $perms = null) { if (S::suid()) { return false; } $backup = S::changeSession(array()); $this->fillSession(); S::set('suid', $backup); if (!$this->startSessionAs($user, AUTH_SUID)) { $this->stopSUID(); return false; } S::set('user', $user); if (!is_null($perms)) { $this->makePerms($perms, false); } return true; } /** Stop a SUID session */ public function stopSUID() { if (!S::suid()) { return false; } S::changeSession(S::v('suid')); return true; } /*** Thresholds ***/ /** Minimum level of authentication that is considered as logged. */ abstract public function loggedLevel(); /** Minimum level of authentication that is considered as sure. */ abstract public function sureLevel(); } // vim:set et sw=4 sts=4 sws=4 foldmethod=marker fenc=utf-8: ?>