diff --git a/include/lucidAuth.functions.php b/include/lucidAuth.functions.php index b589875..7297513 100644 --- a/include/lucidAuth.functions.php +++ b/include/lucidAuth.functions.php @@ -9,7 +9,11 @@ try { # switch ($settings->Database['Driver']) { # case 'sqlite': # $database = new PDO('sqlite:' . $settings->Database['Path']); - $pdoDB = new PDO('sqlite:' . $settings->Sqlite['Path']); + if (is_writable($settings->Sqlite['Path'])) { + $pdoDB = new PDO('sqlite:' . $settings->Sqlite['Path']); + } else { + throw new Exception(sprintf('Database file \'%1$s\' is not writable', $settings->Sqlite['Path'])); + } # } } catch (Exception $e) { @@ -41,18 +45,7 @@ function authenticateLDAP (string $username, string $password) { ]; $secureToken = JWT::encode($jwtPayload, base64_decode($settings->JWT['PrivateKey_base64'])); - // Store authentication token in database - $pdoQuery = $pdoDB->prepare(' - INSERT INTO SecureToken (UserId, Value) - SELECT User.Id, :securetoken - FROM User - WHERE User.Username = :qualifiedusername - '); - $pdoQuery->execute([ - 'securetoken' => $secureToken, - 'qualifiedusername' => $qualifiedUsername - ]); - + return ['status' => 'Success', 'token' => $secureToken]; } else { // LDAP authentication failed! @@ -75,7 +68,7 @@ function retrieveTokenFromDB (string $username, string $foo) { } function validateToken (string $secureToken) { - global $settings; + global $settings, $pdoDB; try { $jwtPayload = JWT::decode($secureToken, base64_decode($settings->JWT['PrivateKey_base64']), $settings->JWT['Algorithm']); @@ -84,6 +77,11 @@ function validateToken (string $secureToken) { return ['status' => 'Fail', 'reason' => '1']; } + if ((int)$jwtPayload->iat < (time() - (int)$settings->Session['Duration'])) { + // Expired token + return ['status' => 'Fail', 'reason' => '3']; + } + $pdoQuery = $pdoDB->prepare(' SELECT SecureToken.Value FROM SecureToken @@ -92,25 +90,25 @@ function validateToken (string $secureToken) { WHERE User.Username = :username '); $pdoQuery->execute([ - 'username' => $jwtPayload['sub'] + ':username' => (string)$jwtPayload->sub ]); foreach($pdoQuery->fetchAll(PDO::FETCH_ASSOC) as $row) { - $storedTokens[] = $row['Value']; + try { + $storedTokens[] = JWT::decode($row['Value'], base64_decode($settings->JWT['PrivateKey_base64']), $settings->JWT['Algorithm']); + } catch (Exception $e) { + continue; + } } - -print_r($storedTokens); -# if (!empty($storedTokens) && ) { -# } else { + if (!empty($storedTokens) && sizeof(array_filter($storedTokens, function ($value) use ($jwtPayload) { + return $value['iat'] === $jwtPayload['iat']; + })) === 1) { + // At least one of the database-stored tokens match + return ['status' => 'Success', 'token' => $jwtPayload]; + } else { // No matching token in database -# return ['status' => 'Fail', 'reason' => '2']; -# } - - If ($secureToken['iat'] < (time() - $settings->Session['Duration'])) { - // Expired token - return ['status' => 'Fail', 'reason' => '3']; + return ['status' => 'Fail', 'reason' => '2']; } - } ?> \ No newline at end of file diff --git a/lucidAuth.config.php.example b/lucidAuth.config.php.example index a4b42fd..51a7671 100644 --- a/lucidAuth.config.php.example +++ b/lucidAuth.config.php.example @@ -18,8 +18,6 @@ return (object) array( // Specify the NetBios name of the domain; to allow users to log on with just their usernames. ], - 'DomainNames' => ['*.subdomain.domain.{(tld1|tld2)}'], - 'Sqlite' => [ 'Path' => '../data/lucidAuth.sqlite.db' // Relative path to the location where the database should be stored @@ -30,7 +28,7 @@ return (object) array( 'JWT' => [ 'PrivateKey_base64' => '', - // A base64-encoded string of a random string (see https://www.base64encode.org/) + // A base64-encoded random (preferably long) string (see https://www.base64encode.org/) 'Algorithm' => [ 'HS256', ] @@ -39,7 +37,11 @@ return (object) array( 'Session' => [ 'Duration' => 2592000, // In seconds (2592000 is equivalent to 30 days) -# 'CookiePrefix' => 'lucidAuth_' + 'CookieDomains' => [ + 'domain1.tld' #, 'domain2.tld', 'subdomain.domain3.tld' + ] + // Domain(s) that will be used to set cookie-domains to + // (multiple domains are allowed; remove the '#' above) ], 'Debug' => [ diff --git a/public/lucidAuth.login.php b/public/lucidAuth.login.php index a2ce736..f51d157 100644 --- a/public/lucidAuth.login.php +++ b/public/lucidAuth.login.php @@ -3,11 +3,26 @@ include_once('../include/lucidAuth.functions.php'); - if ($_POST['do'] == 'login') { + if ($_POST['do'] === 'login') { $result = authenticateLDAP($_POST['username'], $_POST['password']); - if ($result['status'] == 'Success') { - // Save secure token in cookie - setcookie('JWT', $result['token'], (time() + $settings->Session['Duration'])); + if ($result['status'] === 'Success') { + // Save authentication token in database + $pdoQuery = $pdoDB->prepare(' + INSERT INTO SecureToken (UserId, Value) + SELECT User.Id, :securetoken + FROM User + WHERE User.Username = :qualifiedusername + '); + $pdoQuery->execute([ + ':securetoken' => $result['token'], + ':qualifiedusername' => $settings->LDAP['Domain'] . '\\' . $_POST['username'] + ]); + // Save authentication token in cookie + $httpHost = $_SERVER['HTTP_HOST']; + $cookieDomain = array_values(array_filter($settings->Session['CookieDomains'], function ($value) use ($httpHost) { + return (strlen($value) > strlen($httpHost)) ? false : (0 === substr_compare($httpHost, $value, -strlen($value))); + }))[0]; + setcookie('JWT', $result['token'], (time() + $settings->Session['Duration']), '/', '.' . $cookieDomain); // Convert base64 encoded string back from JSON; // forcing it into an associative array (instead of javascript's default StdClass object) diff --git a/public/lucidAuth.validateRequest.php b/public/lucidAuth.validateRequest.php index 3b289f1..e3ddb66 100644 --- a/public/lucidAuth.validateRequest.php +++ b/public/lucidAuth.validateRequest.php @@ -18,7 +18,6 @@ // For debugging purposes - enable it in ../lucidAuth.config.php if ($settings->Debug['LogToFile']) { file_put_contents('../requestHeaders.log', (new DateTime())->format('Y-m-d\TH:i:s.u') . ' --- ' . (json_encode($proxyHeaders, JSON_FORCE_OBJECT)) . PHP_EOL, FILE_APPEND); - file_put_contents('../requestHeaders.log', (new DateTime())->format('Y-m-d\TH:i:s.u') . ' --+ ' . (base64_encode(json_encode($proxyHeaders))) . PHP_EOL, FILE_APPEND); } # if (sizeof($proxyHeaders) == 0) { @@ -28,9 +27,7 @@ exit; } - if (!empty($_COOKIE['JWT']) && validateToken([ - 'JWT' => $_COOKIE['JWT'] - ])['status'] == "Success") { + if (!empty($_COOKIE['JWT']) && validateToken($_COOKIE['JWT'])['status'] == "Success") { // Valid authentication token found header("HTTP/1.1 202 Accepted"); exit;