getCookieKey(), false); if ($value === false) return false; if (!preg_match('/^(cas|form|):(.*)$/', $value, $ms)) return false; $authType = $ms[1]; $username = $ms[2]; return true; } protected function setCookie(string $username, string $authType): void { cookie::setd($this->getCookieKey(), "$authType:$username", $this->getCookieDuration()); } protected function resetCookie(): void { cookie::set($this->getCookieKey(), false); } ############################################################################# # Session /** @var int */ private $status = self::STATUS_NONE; function getStatus(): int { return $this->status; } /** * Vérifier la session que la session est valide. * * comme raccourci, si la session est valide, initialiser $username avec le * nom d'utilisateur *du cookie* */ function checkSession(?string &$username=null, ?string &$authType=null): bool { if (!$this->checkCookie($username, $authType)) return false; session::start(); $this->status = session::get(self::SESSION_KEY_STATUS, self::STATUS_NONE); return session::get(self::SESSION_KEY_COOKIE) === "$authType:$username"; } function isNewSession(): bool { return session::get(self::SESSION_KEY_COOKIE) === null; } function initSession(int $status): void { $this->checkCookie($username, $authType); session::start(); session::set(self::SESSION_KEY_COOKIE, "$authType:$username"); $this->status = $status; session::set(self::SESSION_KEY_STATUS, $status); session::set(self::SESSION_KEY_USERNAME, null); session::set(self::SESSION_KEY_USER, null); } function resetSession(int $status=self::STATUS_DISCONNECTED): void { if ($this->checkCookie()) { session::start(); session::destroy(true); $this->initSession($status); } elseif (session::started()) { session::destroy(true); $this->initSession($status); } } /** @var string */ private $auth; /** tester si l'utilisateur est connecté */ function _isAuth(): bool { if (!$this->checkSession()) return false; return session::get(self::SESSION_KEY_USERNAME) !== null; } /** * obtenir le compte de l'utilisateur connecté * * @throws ValueException si aucun utilisateur n'est connecté */ function _getAuth(): string { if ($this->checkSession()) { $username = session::get(self::SESSION_KEY_USERNAME); if ($username !== null) return $username; } throw new ValueException("not authenticated"); } function isAuth(): bool { $auth = $this->auth; if ($auth !== null) return true; else return $this->_isAuth(); } function getAuth(): string { $auth = $this->auth; if ($auth !== null) return $auth; else return $this->_getAuth(); } ############################################################################# # Authz const USER_MANAGER_CLASS = SimpleUserManager::class; /** @var IUserManager */ private static $user_manager; protected function getUserManager(): IUserManager { if (self::$user_manager === null) { $class = static::USER_MANAGER_CLASS; self::$user_manager = new $class(); } return self::$user_manager; } function redirect(int $reason, string $destUrl, string $loginUrl): void { $params = ["d" => $destUrl]; switch ($reason) { case self::REASON_LOGIN: $params["a"] = 1; // autologin si possible break; case self::REASON_SESSION: $this->resetSession(self::STATUS_DISCONNECTED); break; case self::REASON_UNAUTHORIZED: session::set(self::SESSION_KEY_STATUS, self::STATUS_UNAUTHORIZED); break; default: throw IllegalAccessException::unexpected_state(); } page::redirect(page::bu($loginUrl, $params)); } function formLogin(string $username, string $password): bool { # l'utilisateur doit exister $user = $this->getUserManager()->getAuthzUser($username, null); if ($user !== null) { # ce doit être un utilisateur valide if ($user->isValid()) { $this->setCookie($username, "form"); # le cas échéant le mot de passe doit correspondre if (config::is_devel() && !$password) $password = null; if ($password === null || $user->validatePassword($password)) { # c'est bon $this->initSession(self::STATUS_INITIAL, null); session::set(self::SESSION_KEY_USERNAME, $username); $this->onAuthOk($username); session::set(self::SESSION_KEY_USER, $user); $this->onAuthzOk($user); return true; } } } return false; } function casLogin(string $username, ?array $overrides): bool { $this->setCookie($username, "cas"); $this->initSession(self::STATUS_INITIAL); session::set(self::SESSION_KEY_USERNAME, $username); $this->onAuthOk($username); # l'utilisateur doit exister $user = $this->getUserManager()->getAuthzUser($username, $overrides); if ($user !== null) { # ce doit être un utilisteur valide if ($user->isValid()) { # c'est bon session::set(self::SESSION_KEY_USER, $user); $this->onAuthzOk($user); return true; } } return false; } /** * après les avoir chargées le cas échéant, retourner les informations * d'autorisation de l'utilisateur spécifié ou une instance invalide s'il n'y * en a pas. mettre à jour la session le cas échéant * * prendre par défaut l'utilisateur connecté */ function _selectAuthz(?string $username=null): IAuthzUser { # ici, la session a peut-être déjà été fermée, mais si elle a été ouverte au # moins une fois, en tenir compte quand on accède aux informations if ($username === null) { if (!session::started_once() || !$this->isAuth()) return InvalidUser::with(); $username = $this->getAuth(); $user = session::get(self::SESSION_KEY_USER); } else if (session::started_once() && $this->isAuth()) { $user = session::get(self::SESSION_KEY_USER); } else { $user = null; } if ($user instanceof IAuthzUser && $user->getUsername() === $username) { return $user; } $user = $this->getUserManager()->getAuthzUser($username, null); if ($user === null) $user = InvalidUser::with($username); session::set(self::SESSION_KEY_USERNAME, $username); session::set(self::SESSION_KEY_USER, $user); return $user; } /** @var IAuthzUser */ private $authz; function setConnected(): void { $this->auth = $this->_getAuth(); $this->authz = $this->_selectAuthz(); } function selectAuthz(?string $username=null): IAuthzUser { $authz = null; if ($username === null) $authz = $this->authz; if ($authz === null) $authz = $this->_selectAuthz($username); return $authz; } /** obtenir les informations d'autorisation de l'utilisateur effectif */ function getUser(): IAuthzUser { #XXX le cas échéant, ajouter les informations de l'utilisateur effectif return $this->selectAuthz(); } function checkAuthz(?array $roles, ?array $perms): bool { $authz = $this->selectAuthz(); if ($roles !== null && !$authz->isRole($roles)) return false; if ($perms !== null && !$authz->isPerm($perms)) return false; # sinon, au moins un rôle ou une permission doivent être définis return $authz->isRole(IAuthzUser::ROLE_AUTHZ); } /** la connexion actuelle a-t-elle été forcée par un administrateur? */ function isSulogin(): bool { return boolval(session::get(self::SESSION_KEY_SULOGIN, false)); } /** marquer la connexion actuelle comme étant faite par un administrateur. */ function setSulogin(bool $sulogin=true): void { if ($sulogin) { $user = session::get(self::SESSION_KEY_SULOGIN, false); if ($user === false) $user = session::get(self::SESSION_KEY_USER); session::set(self::SESSION_KEY_SULOGIN, $user); } else { session::set(self::SESSION_KEY_SULOGIN, false); } } ############################################################################# # Méthodes surchargeables /** Traiter le cas où l'utilisateur s'est authentifié avec succès. */ function onAuthOk(string $username): void { } /** Traiter le cas où l'utilisateur a été autorisé avec succès. */ function onAuthzOk(IAuthzUser $authz): void { } }