Skip to content

Commit e7c587d

Browse files
authored
Merge pull request #1 from ctc-oss/debug-logging
Header Authentication working with Cookie Headers
2 parents 6e38258 + 0e1d3b5 commit e7c587d

File tree

1 file changed

+85
-26
lines changed

1 file changed

+85
-26
lines changed

backend/Services/Auth/Adapters/Header.php

Lines changed: 85 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,36 @@
22

33
/*
44
* This is a custom auth handler that will receive headers for the username and fullname
5-
* If the headers are missing, login will fail.
6-
* If the headers are present, login will succeed, and user will be added.
5+
* If the headers are missing, the user will be presented with the login
6+
* If the headers are present, login will be done automatically, and the user will be added to the system
77
*/
88
namespace Filegator\Services\Auth\Adapters;
99

1010
use Filegator\Services\Auth\Adapters\JsonFile;
1111
use Filegator\Services\Auth\User;
12+
use Filegator\Services\Logger\LoggerInterface;
13+
use Filegator\Services\Session\SessionStorageInterface as Session;
1214

1315
class Header extends JsonFile
1416
{
1517
protected $username_header_key;
1618
protected $fullname_header_key;
1719
protected $non_header_users;
1820
protected $user_defaults;
19-
21+
protected $cookie_key;
22+
23+
public function __construct(Session $session, LoggerInterface $logger)
24+
{
25+
parent::__construct($session);
26+
$this->logger = $logger;
27+
}
28+
2029
public function init(array $config = [])
2130
{
2231
parent::init($config);
23-
$this->username_header_key = strtolower($config["username_header_key"]);
24-
$this->fullname_header_key = strtolower($config["fullname_header_key"]);
32+
$this->username_header_key = $config["username_header_key"];
33+
$this->fullname_header_key = $config["fullname_header_key"];
34+
$this->cookie_key = $config["cookie_key"] ?? "Cookie";
2535
$this->ignore_users = $config["ignore_users"] ?? [];
2636
$this->user_defaults = $config["user_defaults"] ?? [];
2737
}
@@ -31,29 +41,55 @@ private function useNormalAuth($username): bool
3141
return in_array($username, $this->ignore_users);
3242
}
3343

34-
private function headerUser(): array
44+
private function cookieHeaders($headers) {
45+
$all_headers = $headers;
46+
if (!array_key_exists(strtolower($this->cookie_key), $all_headers)) {
47+
return [];
48+
}
49+
50+
$headers_from_cookie = explode('; ', $all_headers["cookie"]);
51+
$headers = [];
52+
53+
foreach ($headers_from_cookie as $cookie) {
54+
list($key, $value) = explode('=', $cookie, 2);
55+
$headers[$key] = $value;
56+
}
57+
58+
return $headers;
59+
}
60+
61+
private function trimQuotes($value): string
62+
{
63+
if (! isset($value)) return $value;
64+
return trim($value, '\'"');
65+
}
66+
67+
private function headerUser(): ?array
3568
{
3669
$headers = array_change_key_case(getallheaders(), CASE_LOWER);
37-
$header_username_exists = array_key_exists($this->username_header_key, $headers);
38-
$header_fullname_exists = array_key_exists($this->fullname_header_key, $headers);
70+
$cookie_headers = array_change_key_case($this->cookieHeaders($headers), CASE_LOWER);
71+
$username_header_key = strtolower($this->username_header_key);
72+
$fullname_header_key = strtolower($this->fullname_header_key);
73+
$header_username_exists = (array_key_exists($username_header_key, $headers) or array_key_exists($username_header_key, $cookie_headers));
74+
$header_fullname_exists = (array_key_exists($fullname_header_key, $headers) or array_key_exists($fullname_header_key, $cookie_headers));
3975

4076
if (!$header_username_exists) {
41-
error_log(print_r($this->username_header_key." header is not set", true));
77+
$this->logger->log($this->username_header_key." username header is not set");
78+
return null;
4279
}
4380
if (!$header_fullname_exists) {
44-
error_log(print_r($this->fullname_header_key." header is not set", true));
81+
$this->logger->log($this->fullname_header_key." full name header is not set, falling back to username header");
4582
}
46-
if (!$header_username_exists || !$header_fullname_exists) return null;
4783

48-
$username_header = $headers[$this->username_header_key];
49-
$fullname_header = $headers[$this->fullname_header_key];
84+
$username_header = $headers[$username_header_key] ?? $cookie_headers[$username_header_key];
85+
$fullname_header = $headers[$fullname_header_key] ?? $cookie_headers[$fullname_header_key] ?? $username_header;
5086

5187
if(!isset($username_header) || empty($username_header)) return null;
5288
if(!isset($fullname_header) || empty($fullname_header)) return null;
5389

5490
return [
55-
"username" => $username_header,
56-
"name" => $fullname_header,
91+
"username" => $this->trimQuotes($username_header),
92+
"name" => $this->trimQuotes($fullname_header),
5793
"role" => $this->user_defaults["role"] ?? "user",
5894
"homedir" => $this->user_defaults["homedir"] ?? "/share",
5995
"permissions" => $this->user_defaults["permissions"] ?? "read",
@@ -65,11 +101,22 @@ private function userHash($user): string
65101
return $user->getHomedir().$user->getRole().$user->getUsername();
66102
}
67103

104+
private function setSessionHash($user) {
105+
$this->session->set(self::SESSION_HASH, $this->userHash($user));
106+
}
107+
68108
public function authenticate($username, $password): bool
69109
{
70110
if ($this->useNormalAuth($username)) {
71-
error_log(print_r("** ".$username." user is configured to use normal authentication, skipping header auth", true));
72-
return parent::authenticate($username, $password);
111+
$this->logger->log("** [".$username."] user is configured to use normal authentication, skipping header auth");
112+
$authenticated = parent::authenticate($username, $password);
113+
if ($authenticated) {
114+
$authenticated_user = parent::user();
115+
if (isset($authenticated_user)) {
116+
$this->setSessionHash($authenticated_user);
117+
}
118+
}
119+
return $authenticated;
73120
}
74121

75122
$header_user = $this->headerUser();
@@ -82,23 +129,35 @@ public function authenticate($username, $password): bool
82129
}
83130

84131
$this->store($existing_user);
85-
$this->session->set(self::SESSION_HASH, $this->userHash($existing_user));
132+
$this->setSessionHash($existing_user);
86133
return true;
87134
}
88135

136+
protected function sessionUser() {
137+
return $this->session->get(self::SESSION_KEY, null);
138+
}
139+
89140
public function user(): ?User
90141
{
91142
if (! $this->session) return null;
92-
93-
$user = $this->session->get(self::SESSION_KEY, null);
94-
if (! $user) return null;
95143

96-
if ($this->useNormalAuth($user->getUsername())) return parent::user();
144+
$session_user = $this->sessionUser();
145+
if (isset($session_user)) {
146+
$hash = $this->session->get(self::SESSION_HASH, null);
147+
return ($hash == $this->userHash($session_user)) ? $session_user : null;
148+
}
97149

98-
$existing_user = $this->find($user->getUsername());
99-
if (! $existing_user) return null;
150+
$header_user = $this->headerUser();
151+
if (isset($header_user)) {
152+
$header_username = $header_user["username"];
153+
$authenticated = $this->authenticate($header_username, "");
154+
if ($authenticated) {
155+
$authenticated_user = $this->sessionUser();
156+
$this->logger->log("Authenticated user [".$authenticated_user->getUsername()."] with ".$this->username_header_key." header");
157+
return $authenticated_user;
158+
}
159+
}
100160

101-
$hash = $this->session->get(self::SESSION_HASH, null);
102-
return ($hash == $this->userHash($existing_user)) ? $user : null;
161+
return null;
103162
}
104163
}

0 commit comments

Comments
 (0)