From e9fedf3e5cd63aea4da7a71f6647ee427c62fa49 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sat, 5 Dec 2015 20:31:27 -0500 Subject: Rewrite of the authentication and authorization system --- app/Auth/DatabaseAuth.php | 125 ++++++++++ app/Auth/Github.php | 123 ---------- app/Auth/GithubAuth.php | 143 ++++++++++++ app/Auth/Gitlab.php | 123 ---------- app/Auth/GitlabAuth.php | 143 ++++++++++++ app/Auth/Google.php | 124 ---------- app/Auth/GoogleAuth.php | 143 ++++++++++++ app/Auth/Ldap.php | 521 ------------------------------------------ app/Auth/LdapAuth.php | 187 +++++++++++++++ app/Auth/RememberMe.php | 323 -------------------------- app/Auth/RememberMeAuth.php | 79 +++++++ app/Auth/ReverseProxy.php | 83 ------- app/Auth/ReverseProxyAuth.php | 76 ++++++ app/Auth/TotpAuth.php | 126 ++++++++++ 14 files changed, 1022 insertions(+), 1297 deletions(-) create mode 100644 app/Auth/DatabaseAuth.php delete mode 100644 app/Auth/Github.php create mode 100644 app/Auth/GithubAuth.php delete mode 100644 app/Auth/Gitlab.php create mode 100644 app/Auth/GitlabAuth.php delete mode 100644 app/Auth/Google.php create mode 100644 app/Auth/GoogleAuth.php delete mode 100644 app/Auth/Ldap.php create mode 100644 app/Auth/LdapAuth.php delete mode 100644 app/Auth/RememberMe.php create mode 100644 app/Auth/RememberMeAuth.php delete mode 100644 app/Auth/ReverseProxy.php create mode 100644 app/Auth/ReverseProxyAuth.php create mode 100644 app/Auth/TotpAuth.php (limited to 'app/Auth') diff --git a/app/Auth/DatabaseAuth.php b/app/Auth/DatabaseAuth.php new file mode 100644 index 00000000..727afaf3 --- /dev/null +++ b/app/Auth/DatabaseAuth.php @@ -0,0 +1,125 @@ +db + ->table(User::TABLE) + ->columns('id', 'password') + ->eq('username', $this->username) + ->eq('disable_login_form', 0) + ->eq('is_ldap_user', 0) + ->findOne(); + + if (! empty($user) && password_verify($this->password, $user['password'])) { + $this->userInfo = $user; + return true; + } + + return false; + } + + /** + * Check if the user session is valid + * + * @access public + * @return boolean + */ + public function isValidSession() + { + return $this->user->exists($this->userSession->getId()); + } + + /** + * Get user object + * + * @access public + * @return null|\Kanboard\User\DatabaseUserProvider + */ + public function getUser() + { + if (empty($this->userInfo)) { + return null; + } + + return new DatabaseUserProvider($this->userInfo); + } + + /** + * Set username + * + * @access public + * @param string $username + */ + public function setUsername($username) + { + $this->username = $username; + } + + /** + * Set password + * + * @access public + * @param string $password + */ + public function setPassword($password) + { + $this->password = $password; + } +} diff --git a/app/Auth/Github.php b/app/Auth/Github.php deleted file mode 100644 index 4777152a..00000000 --- a/app/Auth/Github.php +++ /dev/null @@ -1,123 +0,0 @@ -user->getByGithubId($github_id); - - if (! empty($user)) { - $this->userSession->initialize($user); - $this->container['dispatcher']->dispatch('auth.success', new AuthEvent(self::AUTH_NAME, $user['id'])); - return true; - } - - return false; - } - - /** - * Unlink a Github account for a given user - * - * @access public - * @param integer $user_id User id - * @return boolean - */ - public function unlink($user_id) - { - return $this->user->update(array( - 'id' => $user_id, - 'github_id' => '', - )); - } - - /** - * Update the user table based on the Github profile information - * - * @access public - * @param integer $user_id User id - * @param array $profile Github profile - * @return boolean - */ - public function updateUser($user_id, array $profile) - { - $user = $this->user->getById($user_id); - - return $this->user->update(array( - 'id' => $user_id, - 'github_id' => $profile['id'], - 'email' => empty($user['email']) ? $profile['email'] : $user['email'], - 'name' => empty($user['name']) ? $profile['name'] : $user['name'], - )); - } - - /** - * Get OAuth2 configured service - * - * @access public - * @return Kanboard\Core\OAuth2 - */ - public function getService() - { - if (empty($this->service)) { - $this->service = $this->oauth->createService( - GITHUB_CLIENT_ID, - GITHUB_CLIENT_SECRET, - $this->helper->url->to('oauth', 'github', array(), '', true), - GITHUB_OAUTH_AUTHORIZE_URL, - GITHUB_OAUTH_TOKEN_URL, - array() - ); - } - - return $this->service; - } - - /** - * Get Github profile - * - * @access public - * @param string $code - * @return array - */ - public function getProfile($code) - { - $this->getService()->getAccessToken($code); - - return $this->httpClient->getJson( - GITHUB_API_URL.'user', - array($this->getService()->getAuthorizationHeader()) - ); - } -} diff --git a/app/Auth/GithubAuth.php b/app/Auth/GithubAuth.php new file mode 100644 index 00000000..47da0413 --- /dev/null +++ b/app/Auth/GithubAuth.php @@ -0,0 +1,143 @@ +getProfile(); + + if (! empty($profile)) { + $this->userInfo = new GithubUserProvider($profile); + return true; + } + + return false; + } + + /** + * Set Code + * + * @access public + * @param string $code + * @return GithubAuth + */ + public function setCode($code) + { + $this->code = $code; + return $this; + } + + /** + * Get user object + * + * @access public + * @return null|GithubUserProvider + */ + public function getUser() + { + return $this->userInfo; + } + + /** + * Get configured OAuth2 service + * + * @access public + * @return \Kanboard\Core\Http\OAuth2 + */ + public function getService() + { + if (empty($this->service)) { + $this->service = $this->oauth->createService( + GITHUB_CLIENT_ID, + GITHUB_CLIENT_SECRET, + $this->helper->url->to('oauth', 'github', array(), '', true), + GITHUB_OAUTH_AUTHORIZE_URL, + GITHUB_OAUTH_TOKEN_URL, + array() + ); + } + + return $this->service; + } + + /** + * Get Github profile + * + * @access private + * @return array + */ + private function getProfile() + { + $this->getService()->getAccessToken($this->code); + + return $this->httpClient->getJson( + GITHUB_API_URL.'user', + array($this->getService()->getAuthorizationHeader()) + ); + } + + /** + * Unlink user + * + * @access public + * @param integer $userId + * @return bool + */ + public function unlink($userId) + { + return $this->user->update(array('id' => $userId, 'github_id' => '')); + } +} diff --git a/app/Auth/Gitlab.php b/app/Auth/Gitlab.php deleted file mode 100644 index 698b59c3..00000000 --- a/app/Auth/Gitlab.php +++ /dev/null @@ -1,123 +0,0 @@ -user->getByGitlabId($gitlab_id); - - if (! empty($user)) { - $this->userSession->initialize($user); - $this->container['dispatcher']->dispatch('auth.success', new AuthEvent(self::AUTH_NAME, $user['id'])); - return true; - } - - return false; - } - - /** - * Unlink a Gitlab account for a given user - * - * @access public - * @param integer $user_id User id - * @return boolean - */ - public function unlink($user_id) - { - return $this->user->update(array( - 'id' => $user_id, - 'gitlab_id' => '', - )); - } - - /** - * Update the user table based on the Gitlab profile information - * - * @access public - * @param integer $user_id User id - * @param array $profile Gitlab profile - * @return boolean - */ - public function updateUser($user_id, array $profile) - { - $user = $this->user->getById($user_id); - - return $this->user->update(array( - 'id' => $user_id, - 'gitlab_id' => $profile['id'], - 'email' => empty($user['email']) ? $profile['email'] : $user['email'], - 'name' => empty($user['name']) ? $profile['name'] : $user['name'], - )); - } - - /** - * Get OAuth2 configured service - * - * @access public - * @return Kanboard\Core\OAuth2 - */ - public function getService() - { - if (empty($this->service)) { - $this->service = $this->oauth->createService( - GITLAB_CLIENT_ID, - GITLAB_CLIENT_SECRET, - $this->helper->url->to('oauth', 'gitlab', array(), '', true), - GITLAB_OAUTH_AUTHORIZE_URL, - GITLAB_OAUTH_TOKEN_URL, - array() - ); - } - - return $this->service; - } - - /** - * Get Gitlab profile - * - * @access public - * @param string $code - * @return array - */ - public function getProfile($code) - { - $this->getService()->getAccessToken($code); - - return $this->httpClient->getJson( - GITLAB_API_URL.'user', - array($this->getService()->getAuthorizationHeader()) - ); - } -} diff --git a/app/Auth/GitlabAuth.php b/app/Auth/GitlabAuth.php new file mode 100644 index 00000000..df6e0176 --- /dev/null +++ b/app/Auth/GitlabAuth.php @@ -0,0 +1,143 @@ +getProfile(); + + if (! empty($profile)) { + $this->userInfo = new GitlabUserProvider($profile); + return true; + } + + return false; + } + + /** + * Set Code + * + * @access public + * @param string $code + * @return GitlabAuth + */ + public function setCode($code) + { + $this->code = $code; + return $this; + } + + /** + * Get user object + * + * @access public + * @return null|GitlabUserProvider + */ + public function getUser() + { + return $this->userInfo; + } + + /** + * Get configured OAuth2 service + * + * @access public + * @return \Kanboard\Core\Http\OAuth2 + */ + public function getService() + { + if (empty($this->service)) { + $this->service = $this->oauth->createService( + GITLAB_CLIENT_ID, + GITLAB_CLIENT_SECRET, + $this->helper->url->to('oauth', 'gitlab', array(), '', true), + GITLAB_OAUTH_AUTHORIZE_URL, + GITLAB_OAUTH_TOKEN_URL, + array() + ); + } + + return $this->service; + } + + /** + * Get Gitlab profile + * + * @access private + * @return array + */ + private function getProfile() + { + $this->getService()->getAccessToken($this->code); + + return $this->httpClient->getJson( + GITLAB_API_URL.'user', + array($this->getService()->getAuthorizationHeader()) + ); + } + + /** + * Unlink user + * + * @access public + * @param integer $userId + * @return bool + */ + public function unlink($userId) + { + return $this->user->update(array('id' => $userId, 'gitlab_id' => '')); + } +} diff --git a/app/Auth/Google.php b/app/Auth/Google.php deleted file mode 100644 index 6c1bc3cd..00000000 --- a/app/Auth/Google.php +++ /dev/null @@ -1,124 +0,0 @@ -user->getByGoogleId($google_id); - - if (! empty($user)) { - $this->userSession->initialize($user); - $this->container['dispatcher']->dispatch('auth.success', new AuthEvent(self::AUTH_NAME, $user['id'])); - return true; - } - - return false; - } - - /** - * Unlink a Google account for a given user - * - * @access public - * @param integer $user_id User id - * @return boolean - */ - public function unlink($user_id) - { - return $this->user->update(array( - 'id' => $user_id, - 'google_id' => '', - )); - } - - /** - * Update the user table based on the Google profile information - * - * @access public - * @param integer $user_id User id - * @param array $profile Google profile - * @return boolean - */ - public function updateUser($user_id, array $profile) - { - $user = $this->user->getById($user_id); - - return $this->user->update(array( - 'id' => $user_id, - 'google_id' => $profile['id'], - 'email' => empty($user['email']) ? $profile['email'] : $user['email'], - 'name' => empty($user['name']) ? $profile['name'] : $user['name'], - )); - } - - /** - * Get OAuth2 configured service - * - * @access public - * @return KanboardCore\OAuth2 - */ - public function getService() - { - if (empty($this->service)) { - $this->service = $this->oauth->createService( - GOOGLE_CLIENT_ID, - GOOGLE_CLIENT_SECRET, - $this->helper->url->to('oauth', 'google', array(), '', true), - 'https://accounts.google.com/o/oauth2/auth', - 'https://accounts.google.com/o/oauth2/token', - array('https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile') - ); - } - - return $this->service; - } - - /** - * Get Google profile - * - * @access public - * @param string $code - * @return array - */ - public function getProfile($code) - { - $this->getService()->getAccessToken($code); - - return $this->httpClient->getJson( - 'https://www.googleapis.com/oauth2/v1/userinfo', - array($this->getService()->getAuthorizationHeader()) - ); - } -} diff --git a/app/Auth/GoogleAuth.php b/app/Auth/GoogleAuth.php new file mode 100644 index 00000000..0dc1c62f --- /dev/null +++ b/app/Auth/GoogleAuth.php @@ -0,0 +1,143 @@ +getProfile(); + + if (! empty($profile)) { + $this->userInfo = new GoogleUserProvider($profile); + return true; + } + + return false; + } + + /** + * Set Code + * + * @access public + * @param string $code + * @return GoogleAuth + */ + public function setCode($code) + { + $this->code = $code; + return $this; + } + + /** + * Get user object + * + * @access public + * @return null|GoogleUserProvider + */ + public function getUser() + { + return $this->userInfo; + } + + /** + * Get configured OAuth2 service + * + * @access public + * @return \Kanboard\Core\Http\OAuth2 + */ + public function getService() + { + if (empty($this->service)) { + $this->service = $this->oauth->createService( + GOOGLE_CLIENT_ID, + GOOGLE_CLIENT_SECRET, + $this->helper->url->to('oauth', 'google', array(), '', true), + 'https://accounts.google.com/o/oauth2/auth', + 'https://accounts.google.com/o/oauth2/token', + array('https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile') + ); + } + + return $this->service; + } + + /** + * Get Google profile + * + * @access private + * @return array + */ + private function getProfile() + { + $this->getService()->getAccessToken($this->code); + + return $this->httpClient->getJson( + 'https://www.googleapis.com/oauth2/v1/userinfo', + array($this->getService()->getAuthorizationHeader()) + ); + } + + /** + * Unlink user + * + * @access public + * @param integer $userId + * @return bool + */ + public function unlink($userId) + { + return $this->user->update(array('id' => $userId, 'google_id' => '')); + } +} diff --git a/app/Auth/Ldap.php b/app/Auth/Ldap.php deleted file mode 100644 index 3d361aa7..00000000 --- a/app/Auth/Ldap.php +++ /dev/null @@ -1,521 +0,0 @@ -getLdapAccountId(), - $this->getLdapAccountName(), - $this->getLdapAccountEmail(), - $this->getLdapAccountMemberOf() - ))); - } - - /** - * Authenticate the user - * - * @access public - * @param string $username Username - * @param string $password Password - * @return boolean - */ - public function authenticate($username, $password) - { - $username = $this->isLdapAccountCaseSensitive() ? $username : strtolower($username); - $result = $this->findUser($username, $password); - - if (is_array($result)) { - $user = $this->user->getByUsername($username); - - if (! empty($user)) { - - // There is already a local user with that name - if ($user['is_ldap_user'] == 0) { - return false; - } - } else { - - // We create automatically a new user - if ($this->isLdapAccountCreationEnabled() && $this->user->create($result) !== false) { - $user = $this->user->getByUsername($username); - } else { - return false; - } - } - - // We open the session - $this->userSession->initialize($user); - $this->container['dispatcher']->dispatch('auth.success', new AuthEvent(self::AUTH_NAME, $user['id'])); - - return true; - } - - return false; - } - - /** - * Find the user from the LDAP server - * - * @access public - * @param string $username Username - * @param string $password Password - * @return boolean|array - */ - public function findUser($username, $password) - { - $ldap = $this->connect(); - - if ($ldap !== false && $this->bind($ldap, $username, $password)) { - return $this->getProfile($ldap, $username, $password); - } - - return false; - } - - /** - * LDAP connection - * - * @access public - * @return resource|boolean - */ - public function connect() - { - if (! function_exists('ldap_connect')) { - $this->logger->error('LDAP: The PHP LDAP extension is required'); - return false; - } - - // Skip SSL certificate verification - if (! LDAP_SSL_VERIFY) { - putenv('LDAPTLS_REQCERT=never'); - } - - $ldap = ldap_connect($this->getLdapServer(), $this->getLdapPort()); - - if ($ldap === false) { - $this->logger->error('LDAP: Unable to connect to the LDAP server'); - return false; - } - - ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); - ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0); - ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, 1); - ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, 1); - - if (LDAP_START_TLS && ! @ldap_start_tls($ldap)) { - $this->logger->error('LDAP: Unable to use ldap_start_tls()'); - return false; - } - - return $ldap; - } - - /** - * LDAP authentication - * - * @access public - * @param resource $ldap - * @param string $username - * @param string $password - * @return boolean - */ - public function bind($ldap, $username, $password) - { - if ($this->getLdapBindType() === 'user') { - $ldap_username = sprintf($this->getLdapUsername(), $username); - $ldap_password = $password; - } elseif ($this->getLdapBindType() === 'proxy') { - $ldap_username = $this->getLdapUsername(); - $ldap_password = $this->getLdapPassword(); - } else { - $ldap_username = null; - $ldap_password = null; - } - - if (! @ldap_bind($ldap, $ldap_username, $ldap_password)) { - $this->logger->error('LDAP: Unable to bind to server with: '.$ldap_username); - $this->logger->error('LDAP: bind type='.$this->getLdapBindType()); - return false; - } - - return true; - } - - /** - * Get LDAP user profile - * - * @access public - * @param resource $ldap - * @param string $username - * @param string $password - * @return boolean|array - */ - public function getProfile($ldap, $username, $password) - { - $user_pattern = $this->getLdapUserPattern($username); - $entries = $this->executeQuery($ldap, $user_pattern); - - if ($entries === false) { - $this->logger->error('LDAP: Unable to get user profile: '.$user_pattern); - return false; - } - - if (@ldap_bind($ldap, $entries[0]['dn'], $password)) { - return $this->prepareProfile($ldap, $entries, $username); - } - - if (DEBUG) { - $this->logger->debug('LDAP: wrong password for '.$entries[0]['dn']); - } - - return false; - } - - /** - * Build user profile from LDAP information - * - * @access public - * @param resource $ldap - * @param array $entries - * @param string $username - * @return boolean|array - */ - public function prepareProfile($ldap, array $entries, $username) - { - if ($this->getLdapAccountId() !== '') { - $username = $this->getEntry($entries, $this->getLdapAccountId(), $username); - } - - return array( - 'username' => $username, - 'name' => $this->getEntry($entries, $this->getLdapAccountName()), - 'email' => $this->getEntry($entries, $this->getLdapAccountEmail()), - 'is_admin' => (int) $this->isMemberOf($this->getEntries($entries, $this->getLdapAccountMemberOf()), $this->getLdapGroupAdmin()), - 'is_project_admin' => (int) $this->isMemberOf($this->getEntries($entries, $this->getLdapAccountMemberOf()), $this->getLdapGroupProjectAdmin()), - 'is_ldap_user' => 1, - ); - } - - /** - * Check group membership - * - * @access public - * @param array $group_entries - * @param string $group_dn - * @return boolean - */ - public function isMemberOf(array $group_entries, $group_dn) - { - if (! isset($group_entries['count']) || empty($group_dn)) { - return false; - } - - for ($i = 0; $i < $group_entries['count']; $i++) { - if ($group_entries[$i] === $group_dn) { - return true; - } - } - - return false; - } - - /** - * Retrieve info on LDAP user by username or email - * - * @access public - * @param string $username - * @param string $email - * @return boolean|array - */ - public function lookup($username = null, $email = null) - { - $query = $this->getLookupQuery($username, $email); - if ($query === '') { - return false; - } - - // Connect and attempt anonymous or proxy binding - $ldap = $this->connect(); - if ($ldap === false || ! $this->bind($ldap, null, null)) { - return false; - } - - // Try to find user - $entries = $this->executeQuery($ldap, $query); - if ($entries === false) { - return false; - } - - // User id not retrieved: LDAP_ACCOUNT_ID not properly configured - if (empty($username) && ! isset($entries[0][$this->getLdapAccountId()][0])) { - return false; - } - - return $this->prepareProfile($ldap, $entries, $username); - } - - /** - * Execute LDAP query - * - * @access private - * @param resource $ldap - * @param string $query - * @return boolean|array - */ - private function executeQuery($ldap, $query) - { - $sr = @ldap_search($ldap, $this->getLdapBaseDn(), $query, $this->getProfileAttributes()); - if ($sr === false) { - return false; - } - - $entries = ldap_get_entries($ldap, $sr); - if ($entries === false || count($entries) === 0 || $entries['count'] == 0) { - return false; - } - - return $entries; - } - - /** - * Get the LDAP query to find a user - * - * @access private - * @param string $username - * @param string $email - * @return string - */ - private function getLookupQuery($username, $email) - { - if (! empty($username) && ! empty($email)) { - return '(&('.$this->getLdapUserPattern($username).')('.$this->getLdapAccountEmail().'='.$email.'))'; - } elseif (! empty($username)) { - return $this->getLdapUserPattern($username); - } elseif (! empty($email)) { - return '('.$this->getLdapAccountEmail().'='.$email.')'; - } - - return ''; - } - - /** - * Return one entry from a list of entries - * - * @access private - * @param array $entries LDAP entries - * @param string $key Key - * @param string $default Default value if key not set in entry - * @return string - */ - private function getEntry(array $entries, $key, $default = '') - { - return isset($entries[0][$key][0]) ? $entries[0][$key][0] : $default; - } - - /** - * Return subset of entries - * - * @access private - * @param array $entries - * @param string $key - * @param array $default - * @return array - */ - private function getEntries(array $entries, $key, $default = array()) - { - return isset($entries[0][$key]) ? $entries[0][$key] : $default; - } -} diff --git a/app/Auth/LdapAuth.php b/app/Auth/LdapAuth.php new file mode 100644 index 00000000..eb66e54d --- /dev/null +++ b/app/Auth/LdapAuth.php @@ -0,0 +1,187 @@ +getLdapUsername(), $this->getLdapPassword()); + $user = LdapUser::getUser($ldap, $this->getLdapUserPattern()); + + if ($user === null) { + $this->logger->info('User not found in LDAP server'); + return false; + } + + if ($user->getUsername() === '') { + throw new LogicException('Username not found in LDAP profile, check the parameter LDAP_USER_ATTRIBUTE_USERNAME'); + } + + if ($ldap->authenticate($user->getDn(), $this->password)) { + $this->user = $user; + return true; + } + + } catch (LdapException $e) { + $this->logger->error($e->getMessage()); + } + + return false; + } + + /** + * Get user object + * + * @access public + * @return \Kanboard\User\LdapUserProvider + */ + public function getUser() + { + return $this->user; + } + + /** + * Set username + * + * @access public + * @param string $username + */ + public function setUsername($username) + { + $this->username = $username; + } + + /** + * Set password + * + * @access public + * @param string $password + */ + public function setPassword($password) + { + $this->password = $password; + } + + /** + * Get LDAP user pattern + * + * @access public + * @return string + */ + public function getLdapUserPattern() + { + if (! LDAP_USER_FILTER) { + throw new LogicException('LDAP user filter empty, check the parameter LDAP_USER_FILTER'); + } + + return sprintf(LDAP_USER_FILTER, $this->username); + } + + /** + * Get LDAP username (proxy auth) + * + * @access public + * @return string + */ + public function getLdapUsername() + { + switch ($this->getLdapBindType()) { + case 'proxy': + return LDAP_USERNAME; + case 'user': + return sprintf(LDAP_USERNAME, $this->username); + default: + return null; + } + } + + /** + * Get LDAP password (proxy auth) + * + * @access public + * @return string + */ + public function getLdapPassword() + { + switch ($this->getLdapBindType()) { + case 'proxy': + return LDAP_PASSWORD; + case 'user': + return $this->password; + default: + return null; + } + } + + /** + * Get LDAP bind type + * + * @access public + * @return integer + */ + public function getLdapBindType() + { + if (LDAP_BIND_TYPE !== 'user' && LDAP_BIND_TYPE !== 'proxy' && LDAP_BIND_TYPE !== 'anonymous') { + throw new LogicException('Wrong value for the parameter LDAP_BIND_TYPE'); + } + + return LDAP_BIND_TYPE; + } +} diff --git a/app/Auth/RememberMe.php b/app/Auth/RememberMe.php deleted file mode 100644 index 0a567cbe..00000000 --- a/app/Auth/RememberMe.php +++ /dev/null @@ -1,323 +0,0 @@ -db - ->table(self::TABLE) - ->eq('token', $token) - ->eq('sequence', $sequence) - ->gt('expiration', time()) - ->findOne(); - } - - /** - * Get all sessions for a given user - * - * @access public - * @param integer $user_id User id - * @return array - */ - public function getAll($user_id) - { - return $this->db - ->table(self::TABLE) - ->eq('user_id', $user_id) - ->desc('date_creation') - ->columns('id', 'ip', 'user_agent', 'date_creation', 'expiration') - ->findAll(); - } - - /** - * Authenticate the user with the cookie - * - * @access public - * @return bool - */ - public function authenticate() - { - $credentials = $this->readCookie(); - - if ($credentials !== false) { - $record = $this->find($credentials['token'], $credentials['sequence']); - - if ($record) { - - // Update the sequence - $this->writeCookie( - $record['token'], - $this->update($record['token']), - $record['expiration'] - ); - - // Create the session - $this->userSession->initialize($this->user->getById($record['user_id'])); - - // Do not ask 2FA for remember me session - $this->sessionStorage->postAuth['validated'] = true; - - $this->container['dispatcher']->dispatch( - 'auth.success', - new AuthEvent(self::AUTH_NAME, $this->userSession->getId()) - ); - - return true; - } - } - - return false; - } - - /** - * Remove a session record - * - * @access public - * @param integer $session_id Session id - * @return mixed - */ - public function remove($session_id) - { - return $this->db - ->table(self::TABLE) - ->eq('id', $session_id) - ->remove(); - } - - /** - * Remove the current RememberMe session and the cookie - * - * @access public - * @param integer $user_id User id - */ - public function destroy($user_id) - { - $credentials = $this->readCookie(); - - if ($credentials !== false) { - $this->deleteCookie(); - - $this->db - ->table(self::TABLE) - ->eq('user_id', $user_id) - ->eq('token', $credentials['token']) - ->remove(); - } - } - - /** - * Create a new RememberMe session - * - * @access public - * @param integer $user_id User id - * @param string $ip IP Address - * @param string $user_agent User Agent - * @return array - */ - public function create($user_id, $ip, $user_agent) - { - $token = hash('sha256', $user_id.$user_agent.$ip.Token::getToken()); - $sequence = Token::getToken(); - $expiration = time() + self::EXPIRATION; - - $this->cleanup($user_id); - - $this - ->db - ->table(self::TABLE) - ->insert(array( - 'user_id' => $user_id, - 'ip' => $ip, - 'user_agent' => $user_agent, - 'token' => $token, - 'sequence' => $sequence, - 'expiration' => $expiration, - 'date_creation' => time(), - )); - - return array( - 'token' => $token, - 'sequence' => $sequence, - 'expiration' => $expiration, - ); - } - - /** - * Remove old sessions for a given user - * - * @access public - * @param integer $user_id User id - * @return bool - */ - public function cleanup($user_id) - { - return $this->db - ->table(self::TABLE) - ->eq('user_id', $user_id) - ->lt('expiration', time()) - ->remove(); - } - - /** - * Return a new sequence token and update the database - * - * @access public - * @param string $token Session token - * @return string - */ - public function update($token) - { - $new_sequence = Token::getToken(); - - $this->db - ->table(self::TABLE) - ->eq('token', $token) - ->update(array('sequence' => $new_sequence)); - - return $new_sequence; - } - - /** - * Encode the cookie - * - * @access public - * @param string $token Session token - * @param string $sequence Sequence token - * @return string - */ - public function encodeCookie($token, $sequence) - { - return implode('|', array($token, $sequence)); - } - - /** - * Decode the value of a cookie - * - * @access public - * @param string $value Raw cookie data - * @return array - */ - public function decodeCookie($value) - { - list($token, $sequence) = explode('|', $value); - - return array( - 'token' => $token, - 'sequence' => $sequence, - ); - } - - /** - * Return true if the current user has a RememberMe cookie - * - * @access public - * @return bool - */ - public function hasCookie() - { - return ! empty($_COOKIE[self::COOKIE_NAME]); - } - - /** - * Write and encode the cookie - * - * @access public - * @param string $token Session token - * @param string $sequence Sequence token - * @param string $expiration Cookie expiration - */ - public function writeCookie($token, $sequence, $expiration) - { - setcookie( - self::COOKIE_NAME, - $this->encodeCookie($token, $sequence), - $expiration, - $this->helper->url->dir(), - null, - Request::isHTTPS(), - true - ); - } - - /** - * Read and decode the cookie - * - * @access public - * @return mixed - */ - public function readCookie() - { - if (empty($_COOKIE[self::COOKIE_NAME])) { - return false; - } - - return $this->decodeCookie($_COOKIE[self::COOKIE_NAME]); - } - - /** - * Remove the cookie - * - * @access public - */ - public function deleteCookie() - { - setcookie( - self::COOKIE_NAME, - '', - time() - 3600, - $this->helper->url->dir(), - null, - Request::isHTTPS(), - true - ); - } -} diff --git a/app/Auth/RememberMeAuth.php b/app/Auth/RememberMeAuth.php new file mode 100644 index 00000000..02b7b9f6 --- /dev/null +++ b/app/Auth/RememberMeAuth.php @@ -0,0 +1,79 @@ +rememberMeCookie->read(); + + if ($credentials !== false) { + $session = $this->rememberMeSession->find($credentials['token'], $credentials['sequence']); + + if (! empty($session)) { + $this->rememberMeCookie->write( + $session['token'], + $this->rememberMeSession->updateSequence($session['token']), + $session['expiration'] + ); + + $this->userInfo = $this->user->getById($session['user_id']); + + return true; + } + } + + return false; + } + + /** + * Get user object + * + * @access public + * @return null|DatabaseUserProvider + */ + public function getUser() + { + if (empty($this->userInfo)) { + return null; + } + + return new DatabaseUserProvider($this->userInfo); + } +} diff --git a/app/Auth/ReverseProxy.php b/app/Auth/ReverseProxy.php deleted file mode 100644 index d119ca98..00000000 --- a/app/Auth/ReverseProxy.php +++ /dev/null @@ -1,83 +0,0 @@ -user->getByUsername($login); - - if (empty($user)) { - $this->createUser($login); - $user = $this->user->getByUsername($login); - } - - $this->userSession->initialize($user); - $this->container['dispatcher']->dispatch('auth.success', new AuthEvent(self::AUTH_NAME, $user['id'])); - - return true; - } - - return false; - } - - /** - * Create automatically a new local user after the authentication - * - * @access private - * @param string $login Username - * @return bool - */ - private function createUser($login) - { - $email = strpos($login, '@') !== false ? $login : ''; - - if (REVERSE_PROXY_DEFAULT_DOMAIN !== '' && empty($email)) { - $email = $login.'@'.REVERSE_PROXY_DEFAULT_DOMAIN; - } - - return $this->user->create(array( - 'email' => $email, - 'username' => $login, - 'is_admin' => REVERSE_PROXY_DEFAULT_ADMIN === $login, - 'is_ldap_user' => 1, - 'disable_login_form' => 1, - )); - } -} diff --git a/app/Auth/ReverseProxyAuth.php b/app/Auth/ReverseProxyAuth.php new file mode 100644 index 00000000..8af7f0a2 --- /dev/null +++ b/app/Auth/ReverseProxyAuth.php @@ -0,0 +1,76 @@ +request->getRemoteUser(); + + if (! empty($username)) { + $this->user = new ReverseProxyUserProvider($username); + return true; + } + + return false; + } + + /** + * Check if the user session is valid + * + * @access public + * @return boolean + */ + public function isValidSession() + { + return $this->request->getRemoteUser() === $this->userSession->getUsername(); + } + + /** + * Get user object + * + * @access public + * @return null|ReverseProxyUserProvider + */ + public function getUser() + { + return $this->user; + } +} diff --git a/app/Auth/TotpAuth.php b/app/Auth/TotpAuth.php new file mode 100644 index 00000000..f41fabd8 --- /dev/null +++ b/app/Auth/TotpAuth.php @@ -0,0 +1,126 @@ +checkTotp(Base32::decode($this->secret), $this->code); + } + + /** + * Set validation code + * + * @access public + * @param string $code + */ + public function setCode($code) + { + $this->code = $code; + } + + /** + * Set secret token + * + * @access public + * @param string $secret + */ + public function setSecret($secret) + { + $this->secret = $secret; + } + + /** + * Get secret token + * + * @access public + * @return string + */ + public function getSecret() + { + if (empty($this->secret)) { + $this->secret = GoogleAuthenticator::generateRandom(); + } + + return $this->secret; + } + + /** + * Get QR code url + * + * @access public + * @param string $label + * @return string + */ + public function getQrCodeUrl($label) + { + if (empty($this->secret)) { + return ''; + } + + return GoogleAuthenticator::getQrCodeUrl('totp', $label, $this->secret); + } + + /** + * Get key url (empty if no url can be provided) + * + * @access public + * @param string $label + * @return string + */ + public function getKeyUrl($label) + { + if (empty($this->secret)) { + return ''; + } + + return GoogleAuthenticator::getKeyUri('totp', $label, $this->secret); + } +} -- cgit v1.2.3