namespace Ice\Auth; use Ice\Di; /** * User authorization library. Handles user login and logout, as well as secure password hashing. * * @package Ice/Auth * @category Library * @author Ice Team * @copyright (c) 2014-2023 Ice Team * @license http://iceframework.org/license */ abstract class Driver { protected session; protected cookies; protected request; protected user; protected options = [ // algorithms are currently supported: PASSWORD_DEFAULT, PASSWORD_BCRYPT and PASSWORD_ARGON2I "hash_method": PASSWORD_BCRYPT, "hash_option": [], // DEPRECATED in 2.0 "hash_key": "", "session_key": "auth_user", "session_roles": "auth_user_roles", "lifetime": 1209600 ]; /** * Loads services and configuration options. * * @param array options Config options * @return void */ public function __construct(array options = []) { var di; let di = Di::$fetch(), this->options = array_merge(this->options, options), this->session = di->get("session"), this->cookies = di->get("cookies"), this->request = di->get("request"); } /** * Checks a plain text password and its hash version to check if the password matches. * * @param string password Password plain text * @param string hash Hash version of password * @return boolean */ public function checkHash(string password, string hash) -> boolean { if typeof this->options["hash_method"] == "string" { return hash_equals(this->hash(password), hash); } else { return password_verify(password, hash); } } /** * Complete the login for a user by setting session data and eg. incrementing the logins. * * @param string user Complete the login for this user * @param array roles User's roles * @return void */ protected function completeLogin(string user, array roles = []) { var sessionRoles; // Regenerate session_id this->session->regenerate(); // Store user in session this->session->set(this->getOption("session_key", "auth_user"), user); // Check in session can improve performance let sessionRoles = this->getOption("session_roles"); // Store user's roles in session if sessionRoles { this->session->set(sessionRoles, roles); } } /** * Get option value with key. * * @param string key The option key * @param mixed defaultValue The value to return if option key does not exist * @return mixed */ public function getOption(string! key, var defaultValue = null) { var value; if fetch value, this->options[key] { return value; } return defaultValue; } /** * Assigns a value to the specified options. * * @param string key The option key * @param mixed value * @return object self */ public function setOption(string key, var value) { let this->options[key] = value; return this; } /** * Gets the currently logged in user from the session. Returns NULL if no user is currently logged in. * * @param mixed defaultValue Default value to return if the user is currently not logged in. * @return mixed */ public function getUser(var defaultValue = null) { return this->session->get(this->getOption("session_key"), defaultValue); } /** * Perform a hmac hash, using the configured method. * * @param string password String to hash * @return string */ public function hash(string password) { if typeof this->options["hash_method"] == "string" { return hash_hmac(this->options["hash_method"], password, this->options["hash_key"]); } else { return password_hash(password, this->options["hash_method"], this->options["hash_option"]); } } /** * Check if there is an active session. Optionally allows checking for a specific role. * * @param string role Role name * @return mixed */ public function loggedIn(string role = null) { var user, sessionRoles, roles; // Get the user from the session let user = this->getUser(); if !user { // User doesn't exists in the session return false; } else { // If we don't have a role no further checking is needed if !role { return true; } // Check if user has the role let sessionRoles = this->getOption("session_roles"); if sessionRoles { let roles = this->session->get(sessionRoles); return in_array(role, roles); } else { return this->{"hasRole"}(user, role); } } } /** * Log out a user by removing the related session variables. * * @param boolean destroy Completely destroy the session * @param boolean logoutAll Remove all tokens for user * @return boolean */ public function logout(boolean destroy = false, boolean logoutAll = false) -> boolean { var sessionRoles; if destroy === true { // Destroy the session completely this->session->destroy(); } else { // Remove the user from the session this->session->remove(this->getOption("session_key")); let sessionRoles = this->getOption("session_roles"); if sessionRoles { this->session->remove(sessionRoles); } // Regenerate session_id this->session->regenerate(); } // Double check return !this->loggedIn(); } }