Quantcast
Channel: Auth class in PHP - Code Review Stack Exchange
Viewing all articles
Browse latest Browse all 4

Auth class in PHP

$
0
0

I have written an Auth class. It's not 100% finished, but it's fully working as expected (tested).

Now my questions are, do you suggest any improvements regarding the structure and are there any security concerns? Note that the script will be running over SSL.

<?phpnamespace Slimproject\Auth;use Slimproject\Models\User;use Slimproject\Models\Attempt;use Slimproject\Models\Authentication;/**   Notes:*   Minimum PHP version: 7.0.0 (Ternary operator '??' and 'random_bytes' are used)*   Cookies required. Without the system does'nt work (atm.)**   Definitions:*   Auth = Refers to the actual authentication with all of its aspects*   Authentication = Refers to the database table where the active user sessions are stored and tracked*/class Auth{    protected $user;    protected $attempt;    protected $authentication;    public function __construct(User $user, Attempt $attempt, Authentication $authentication)    {        $this->user = $user;        $this->attempt = $attempt;        $this->authentication = $authentication;    }    /**    * Logs a user in    * @return boolean    */    public function login(string $email, string $password)    {        $user = $this->getUser($email);        if (!$user || !$this->verifyPassword($user, $password)) {            $this->addAttempt(false, $email);            return false;        }        $this->addAttempt(true, $email);        return $this->createAuth($user->id);    }    /**    * Logs out the user and removes the remember me    * @return boolean    */    public function logout(string $auth_id)    {        $this->deleteAuth($auth_id);        return (!$this->isLoggedIn());    }    /**    * Verify user's password    * @return bool    */    public function verifyPassword(User $user, string $password)    {        return password_verify($password, $user->password);    }    /**    * Returns is user logged in    * @return boolean    */    public function isLoggedIn(bool $force_regenerate_auth = false)     {        $session = $this->getActiveSession();        if ($session && !$this->isExpiredDate($session['refresh_time']) && $this->checkIp($session['ip'])&& $this->checkAgent($session['agent']) && !$force_regenerate_auth) {            return true;        }        $auth_id = $this->getAuthIdFromCookie();        $auth_token = $this->getAuthTokenFromCookie();        if (!$auth_id || !$auth_token) {            $this->deleteAuth($auth_id);            return false;        }        $authentication = $this->getAuthentication($auth_id);        if (!$authentication) {            return false; // Invalid cookie ID or session is deleted        }        // Values must be true to pass        $a = (hash_equals($authentication->hash, sha1($auth_token)));        $b = (!$this->isExpiredDate($authentication->expiredate));        $c = ($this->checkIp($authentication->ip));        $d = ($this->checkAgent($authentication->agent));        if (!$a || !$b || !$c || !$d) {            $this->deleteAuth($auth_id);        }        $this->deleteAuth($auth_id); // Remove old session        $this->createAuth($authentication->user->id, 86400); // Reset session with new expiration time        return session_regenerate_id(true);    }    /**    * Adds an attempt to database    * @return object $attempt    */    public function addAttempt(bool $success, string $input = '')    {        return $this->attempt->create(['input' => $input,'user_id' => $this->user->where('email', $input)->first()->id ?: '','ip' => $this->getUserIp(),'agent' => $this->getUserAgent(),'success' => $success,        ]);    }    /**    * Sets all needed data to authenticate a user    * @return boolean true    */    public function createAuth(int $user_id, int $expire = 86400)    {        $token = $this->createToken();        $hash = sha1($token);        $expiredate = $this->createExpireDate($expire);        $this->deleteAuthenticationsByUserAndIp($user_id);        $this->deleteExpiredAuthentications();        $authentication = $this->authentication->create(['user_id' => $user_id,'hash' => $hash,'expiredate' => $expiredate,'ip' => $this->getUserIp(),'agent' => $this->getUserAgent(),        ]);        if (!$authentication) {            return false;        }        $a = $this->setAuthSession(['user_id' => $user_id,'ip' => $this->getUserIp(),'agent' => $this->getUserAgent(),'refresh_time' => $this->createExpireDate(300),        ]);        $b = $this->setCookie(getenv('COOKIENAME_AUTHID'), $authentication->id, $expire);        $c = $this->setCookie(getenv('COOKIENAME_AUTHTOKEN'), $token, $expire);        return ($a && $b && $c);    }    /**    * Retrieves all sessions for a user by it's user id    * @return object $authentication    */    public function getAuthentications(int $user_id)    {        return $this->authentication->where('user_id', $user_id) ?: false;    }    /**    * Retrieves the session associated with a given auth id    * @return object $authentication    */    public function getAuthentication(int $auth_id)    {        return $this->authentication->where('id', $auth_id)->first() ?: false;    }    /**    * Returns current session token    * @return string $auth_token    */    public function getAuthTokenFromCookie()    {        return $_COOKIE[getenv('COOKIENAME_AUTHTOKEN')] ?? false;    }    /**    * Returns current session id    * @return string $auth_id    */    public function getAuthIdFromCookie()    {        return $_COOKIE[getenv('COOKIENAME_AUTHID')] ?? false;    }    /**    * Returns current authentication session    * @return string $session    */    public function getActiveSession()    {        return $_SESSION['Slimproject']['auth'] ?? false;    }    /**    * Gets user data for a given UID and returns an array    * @return object $user    */    public function getUser($user)    {        $user = (is_int($user)) ? $this->user->where('id', $uid) : $this->user->where('email', trim(strtolower($user)));        return $user->first() ?: false;    }    /**    * Removes all session's components    * @return boolean    */    public function deleteAuth(int $auth_id = null)    {        $a = $this->deleteAuthSession();        $b = $this->unsetCookie(getenv('COOKIENAME_AUTHID'));        $c = $this->unsetCookie(getenv('COOKIENAME_AUTHTOKEN'));        $d = (isset($auth_id)) ? $this->authentication->where('id', $auth_id)->delete() : true;        return ($a && $b && $c && $d);    }    /**    * Removes all existing sessions for a given user_id    * @return int $affected_rows    */    protected function deleteAuthentications(int $user_id)    {        return $this->authentication->where('user_id', $user_id)->delete();    }    /**    * Removes all sessions for a user by its IP    * @return int $affected_rows    */    protected function deleteAuthenticationsByUserAndIp(int $user_id)    {        return $this->authentication->where('user_id', $user_id)->where('ip', $this->getUserIp())->delete();    }    /**    * Removes all expired sessions    * @return int $affected_rows    */    protected function deleteExpiredAuthentications()    {        return $this->authentication->where('expiredate', '<', date('Y-m-d H:i:s'))->delete();    }    /**    * Returns a random hash    * @return string $token    */    public function createToken()    {        return bin2hex(random_bytes(20));    }    /**    * Returns IP address    * @return string $ip    */    protected function getUserIp()    {        if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != '') {           return $_SERVER['HTTP_X_FORWARDED_FOR'];        }        return $_SERVER['REMOTE_ADDR'];    }    /**    * Returns User agent / browser    * @return string $agent    */    protected function getUserAgent()    {        return $_SERVER['HTTP_USER_AGENT'];    }    /**    * Creates a session    * @return boolean    */    public function setAuthSession(array $session_data)     {        $session = $_SESSION['Slimproject']['auth'] = $session_data;        session_regenerate_id(true);        return $session;    }    /**    * Deletes a session    * @return boolean    */    public function deleteAuthSession()     {        $_SESSION['Slimproject']['auth'] = [];        unset($_SESSION['Slimproject']['auth']);        return session_regenerate_id(true);    }    /**    * Creates a cookie    * @return boolean    */    public function setCookie($name, $value, $expire)     {        return setcookie($name, $value, time() + $expire, '/', NULL, false, true);    }    /**    * Removes a cookie    * @return boolean    */    public function unsetCookie($name)     {        return setcookie($name, '', time() - 1, '/', NULL, false, true);    }    /**    * Check if an IP matches the current user IP    * @return boolean    */    public function checkIp(string $ip)     {        return ($ip === $this->getUserIp());    }    /**    * Check if an browser agent matches the current user agent    * @return boolean    */    public function checkAgent(string $agent)     {        return ($agent === $this->getUserAgent());    }    /**    * Returns an new date with the expiration time added    * @return string $date    */    public function createExpireDate(int $expire = 86400)     {        return date('Y-m-d H:i:s', time() + $expire);    }    /**    * Returns true if an date has expired. Otherwise false is returned.    * @return boolean    */    public function isExpiredDate(string $date)     {        return (time() > strtotime($date));    }}

Viewing all articles
Browse latest Browse all 4

Latest Images

Trending Articles





Latest Images