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/Core/User/GroupSync.php | 32 +++++ app/Core/User/UserProfile.php | 62 ++++++++++ app/Core/User/UserProperty.php | 70 +++++++++++ app/Core/User/UserProviderInterface.php | 103 ++++++++++++++++ app/Core/User/UserSession.php | 204 ++++++++++++++++++++++++++++++++ app/Core/User/UserSync.php | 76 ++++++++++++ 6 files changed, 547 insertions(+) create mode 100644 app/Core/User/GroupSync.php create mode 100644 app/Core/User/UserProfile.php create mode 100644 app/Core/User/UserProperty.php create mode 100644 app/Core/User/UserProviderInterface.php create mode 100644 app/Core/User/UserSession.php create mode 100644 app/Core/User/UserSync.php (limited to 'app/Core/User') diff --git a/app/Core/User/GroupSync.php b/app/Core/User/GroupSync.php new file mode 100644 index 00000000..573acd47 --- /dev/null +++ b/app/Core/User/GroupSync.php @@ -0,0 +1,32 @@ +group->getByExternalId($groupId); + + if (! empty($group) && ! $this->groupMember->isMember($group['id'], $userId)) { + $this->groupMember->addUser($group['id'], $userId); + } + } + } +} diff --git a/app/Core/User/UserProfile.php b/app/Core/User/UserProfile.php new file mode 100644 index 00000000..ccbc7f06 --- /dev/null +++ b/app/Core/User/UserProfile.php @@ -0,0 +1,62 @@ +user->getById($userId); + + $values = UserProperty::filterProperties($profile, UserProperty::getProperties($user)); + $values['id'] = $userId; + + if ($this->user->update($values)) { + $profile = array_merge($profile, $values); + $this->userSession->initialize($profile); + return true; + } + + return false; + } + + /** + * Synchronize user properties with the local database and create the user session + * + * @access public + * @param UserProviderInterface $user + * @return boolean + */ + public function initialize(UserProviderInterface $user) + { + if ($user->getInternalId()) { + $profile = $this->user->getById($user->getInternalId()); + } elseif ($user->getExternalIdColumn() && $user->getExternalId()) { + $profile = $this->userSync->synchronize($user); + $this->groupSync->synchronize($profile['id'], $user->getExternalGroupIds()); + } + + if (! empty($profile)) { + $this->userSession->initialize($profile); + return true; + } + + return false; + } +} diff --git a/app/Core/User/UserProperty.php b/app/Core/User/UserProperty.php new file mode 100644 index 00000000..f8b08a3d --- /dev/null +++ b/app/Core/User/UserProperty.php @@ -0,0 +1,70 @@ + $user->getUsername(), + 'name' => $user->getName(), + 'email' => $user->getEmail(), + 'role' => $user->getRole(), + $user->getExternalIdColumn() => $user->getExternalId(), + ); + + $properties = array_merge($properties, $user->getExtraAttributes()); + + return array_filter($properties, array(__NAMESPACE__.'\UserProperty', 'isNotEmptyValue')); + } + + /** + * Filter user properties compared to existing user profile + * + * @static + * @access public + * @param array $profile + * @param array $properties + * @return array + */ + public static function filterProperties(array $profile, array $properties) + { + $values = array(); + + foreach ($properties as $property => $value) { + if (array_key_exists($property, $profile) && ! self::isNotEmptyValue($profile[$property])) { + $values[$property] = $value; + } + } + + return $values; + } + + /** + * Check if a value is not empty + * + * @static + * @access public + * @param string $value + * @return boolean + */ + public static function isNotEmptyValue($value) + { + return $value !== null && $value !== ''; + } +} diff --git a/app/Core/User/UserProviderInterface.php b/app/Core/User/UserProviderInterface.php new file mode 100644 index 00000000..07e01f42 --- /dev/null +++ b/app/Core/User/UserProviderInterface.php @@ -0,0 +1,103 @@ +sessionStorage->user = $user; + $this->sessionStorage->postAuthenticationValidated = false; + } + + /** + * Get user application role + * + * @access public + * @return string + */ + public function getRole() + { + return $this->sessionStorage->user['role']; + } + + /** + * Return true if the user has validated the 2FA key + * + * @access public + * @return bool + */ + public function isPostAuthenticationValidated() + { + return isset($this->sessionStorage->postAuthenticationValidated) && $this->sessionStorage->postAuthenticationValidated === true; + } + + /** + * Validate 2FA for the current session + * + * @access public + */ + public function validatePostAuthentication() + { + $this->sessionStorage->postAuthenticationValidated = true; + } + + /** + * Return true if the user has 2FA enabled + * + * @access public + * @return bool + */ + public function hasPostAuthentication() + { + return isset($this->sessionStorage->user['twofactor_activated']) && $this->sessionStorage->user['twofactor_activated'] === true; + } + + /** + * Disable 2FA for the current session + * + * @access public + */ + public function disablePostAuthentication() + { + $this->sessionStorage->user['twofactor_activated'] = false; + } + + /** + * Return true if the logged user is admin + * + * @access public + * @return bool + */ + public function isAdmin() + { + return isset($this->sessionStorage->user['role']) && $this->sessionStorage->user['role'] === Role::APP_ADMIN; + } + + /** + * Get the connected user id + * + * @access public + * @return integer + */ + public function getId() + { + return isset($this->sessionStorage->user['id']) ? (int) $this->sessionStorage->user['id'] : 0; + } + + /** + * Get username + * + * @access public + * @return integer + */ + public function getUsername() + { + return isset($this->sessionStorage->user['username']) ? $this->sessionStorage->user['username'] : ''; + } + + /** + * Check is the user is connected + * + * @access public + * @return bool + */ + public function isLogged() + { + return isset($this->sessionStorage->user) && ! empty($this->sessionStorage->user); + } + + /** + * Get project filters from the session + * + * @access public + * @param integer $project_id + * @return string + */ + public function getFilters($project_id) + { + return ! empty($this->sessionStorage->filters[$project_id]) ? $this->sessionStorage->filters[$project_id] : 'status:open'; + } + + /** + * Save project filters in the session + * + * @access public + * @param integer $project_id + * @param string $filters + */ + public function setFilters($project_id, $filters) + { + $this->sessionStorage->filters[$project_id] = $filters; + } + + /** + * Is board collapsed or expanded + * + * @access public + * @param integer $project_id + * @return boolean + */ + public function isBoardCollapsed($project_id) + { + return ! empty($this->sessionStorage->boardCollapsed[$project_id]) ? $this->sessionStorage->boardCollapsed[$project_id] : false; + } + + /** + * Set board display mode + * + * @access public + * @param integer $project_id + * @param boolean $is_collapsed + */ + public function setBoardDisplayMode($project_id, $is_collapsed) + { + $this->sessionStorage->boardCollapsed[$project_id] = $is_collapsed; + } + + /** + * Set comments sorting + * + * @access public + * @param string $order + */ + public function setCommentSorting($order) + { + $this->sessionStorage->commentSorting = $order; + } + + /** + * Get comments sorting direction + * + * @access public + * @return string + */ + public function getCommentSorting() + { + return empty($this->sessionStorage->commentSorting) ? 'ASC' : $this->sessionStorage->commentSorting; + } +} diff --git a/app/Core/User/UserSync.php b/app/Core/User/UserSync.php new file mode 100644 index 00000000..d450a0bd --- /dev/null +++ b/app/Core/User/UserSync.php @@ -0,0 +1,76 @@ +user->getByExternalId($user->getExternalIdColumn(), $user->getExternalId()); + $properties = UserProperty::getProperties($user); + + if (! empty($profile)) { + $profile = $this->updateUser($profile, $properties); + } elseif ($user->isUserCreationAllowed()) { + $profile = $this->createUser($user, $properties); + } + + return $profile; + } + + /** + * Update user profile + * + * @access public + * @param array $profile + * @param array $properties + * @return array + */ + private function updateUser(array $profile, array $properties) + { + $values = UserProperty::filterProperties($profile, $properties); + + if (! empty($values)) { + $values['id'] = $profile['id']; + $result = $this->user->update($values); + return $result ? array_merge($profile, $properties) : $profile; + } + + return $profile; + } + + /** + * Create user + * + * @access public + * @param UserProviderInterface $user + * @param array $properties + * @return array + */ + private function createUser(UserProviderInterface $user, array $properties) + { + $id = $this->user->create($properties); + + if ($id === false) { + $this->logger->error('Unable to create user profile: '.$user->getExternalId()); + return array(); + } + + return $this->user->getById($id); + } +} -- cgit v1.2.3