From 3354d45762bbe0db33e3d26d8997e6f6624f24d7 Mon Sep 17 00:00:00 2001 From: winter Sparkles Date: Sun, 9 Aug 2026 02:26:33 +0100 Subject: implement sessions and also log in/out session data is stored in sqlite, not using php sessions --- Psso/AuthInterface/UserExists.php | 6 +++ Psso/AuthProvider/ConfigFile.php | 9 +++- Psso/Challenge/Username.php | 12 ++++- Psso/Context.php | 8 +++ Psso/Identity.php | 12 +++++ Psso/Session.php | 101 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 Psso/AuthInterface/UserExists.php create mode 100644 Psso/Identity.php create mode 100644 Psso/Session.php (limited to 'Psso') diff --git a/Psso/AuthInterface/UserExists.php b/Psso/AuthInterface/UserExists.php new file mode 100644 index 0000000..a75d5c6 --- /dev/null +++ b/Psso/AuthInterface/UserExists.php @@ -0,0 +1,6 @@ +config['users']["$username.password-hash"] ?? null; + $hash = $this->config['users'][$username]['password-hash'] ?? null; if (!isset($hash)) { return false; } return password_verify($password, $hash); } + + public function userExists(string $username): bool { + return isset($this->config['users'][$username]); + } } diff --git a/Psso/Challenge/Username.php b/Psso/Challenge/Username.php index 43de085..c8fa762 100644 --- a/Psso/Challenge/Username.php +++ b/Psso/Challenge/Username.php @@ -1,6 +1,6 @@ userExists($inputData['user']); + if (!$success) $message = 'challenge.message.wrong-username'; + } + return new ChallengeResult( + self::class, $success, $inputData['user'], $message + ); } } diff --git a/Psso/Context.php b/Psso/Context.php index 4a2cd82..5af2102 100644 --- a/Psso/Context.php +++ b/Psso/Context.php @@ -10,4 +10,12 @@ class Context { public function addResult(ChallengeResult $result): void { $this->results[] = $result; } + + public function setTag(string $tag): void { + if (!$this->hasTag($tag)) $this->tags[] = $tag; + } + + public function hasTag(string $tag): bool { + return in_array($tag, $this->tags); + } } diff --git a/Psso/Identity.php b/Psso/Identity.php new file mode 100644 index 0000000..68272d4 --- /dev/null +++ b/Psso/Identity.php @@ -0,0 +1,12 @@ +user = $user; + $this->groups = $groups; + } +} diff --git a/Psso/Session.php b/Psso/Session.php new file mode 100644 index 0000000..35a6228 --- /dev/null +++ b/Psso/Session.php @@ -0,0 +1,101 @@ + true]; + $this->db = new \PDO(...$args); + $this->setup(); + } + + public static function get(): self { + if (!isset(self::$instance)) { + self::$instance = new self(); + } + self::$instance->setCookie(); + return self::$instance; + } + + protected function setup(): void { + $this->db->exec( + <<<'END' + create table if not exists session ( + token text primary key not null, + identity text not null default 'N;', + challenges text not null default 'N;' + ); + END + ); + } + + protected function domain(): string { + return explode('.', $_SERVER['HTTP_HOST'], 2)[1]; + } + + protected function setCookie(): void { + if (isset($_COOKIE['PSSO_session'])) return; + header( + 'Set-Cookie: PSSO_session=' . $this->currentToken() + . '; Domain=' . $this->domain() + . '; HttpOnly' + . '; Max-Age=' . static::$config['auth']['lifetime'] + . '; Path=/' + . '; SameSite=Lax' + . '; Secure' + ); + } + + protected function currentToken(): string { + return $this->token = $this->token ?? + $_COOKIE['PSSO_session'] ?? + base64_encode(random_bytes(129)); + } + + protected function setColumn(string $column, mixed $data): void { + $stmt = $this->db->prepare( + "insert into session(token, $column) values (?, ?) " + . "on conflict do update set $column=excluded.$column" + ); + $stmt->execute([$this->currentToken(), serialize($data)]); + } + + public function getColumn(string $column): mixed { + $stmt = $this->db->prepare("select $column from session where token=?"); + $stmt->execute([$this->currentToken()]); + return unserialize($stmt->fetchColumn(0)); + } + + public function setIdentity(mixed $identity): void { + $this->setColumn('identity', $identity); + } + + public function getIdentity(): mixed { + return $this->getColumn('identity'); + } + + public function setChallenges(mixed $challenges): void { + $this->setColumn('challenges', $challenges); + } + + public function getChallenges(): mixed { + return $this->getColumn('challenges'); + } +} -- cgit v1.3