Loading classes/IdTokenBuilder.php +1 −1 Original line number Diff line number Diff line Loading @@ -29,7 +29,7 @@ class IdTokenBuilder { 'iss' => $this->locator->config->jwtIssuer, 'sub' => $user->id, 'iat' => time(), 'exp' => time() + 120, 'exp' => time() + 3600, 'name' => $user->getCompleteName() ); Loading classes/OAuth2RequestHandler.php +29 −1 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ namespace RAP; use \Firebase\JWT\JWT; class OAuth2RequestHandler { private $locator; Loading Loading @@ -166,7 +168,33 @@ class OAuth2RequestHandler { } $accessToken = $this->locator->getAccessTokenDAO()->getAccessToken($bearer_token); if ($accessToken->expired) { if ($accessToken === null) { $this->attemptJWTTokenValidation($bearer_token); } else if ($accessToken->expired) { throw new UnauthorizedException("Access token is expired"); } } private function attemptJWTTokenValidation($jwt): void { $jwtParts = explode('.', $jwt); if (count($jwtParts) === 0) { throw new UnauthorizedException("Invalid token"); } $header = JWT::jsonDecode(JWT::urlsafeB64Decode($jwtParts[0])); if (!isset($header->kid)) { throw new UnauthorizedException("Invalid token: missing kid in header"); } $keyPair = $this->locator->getJWKSDAO()->getRSAKeyPairById($header->kid); if ($keyPair === null) { throw new UnauthorizedException("Invalid kid: no key found"); } try { JWT::decode($jwt, $keyPair->publicKey, [$keyPair->alg]); } catch (\Firebase\JWT\ExpiredException $ex) { throw new UnauthorizedException("Access token is expired"); } } Loading classes/datalayer/JWKSDAO.php +2 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,8 @@ interface JWKSDAO { public function getRSAKeyPairs(): array; public function getRSAKeyPairById(string $id): ?RSAKeyPair; public function insertRSAKeyPair(RSAKeyPair $keyPair): RSAKeyPair; public function getNewestKeyPair(): RSAKeyPair; Loading classes/datalayer/mysql/MySQLJWKSDAO.php +17 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,23 @@ class MySQLJWKSDAO extends BaseMySQLDAO implements JWKSDAO { return $keyPairs; } public function getRSAKeyPairById(string $id): ?RSAKeyPair { $dbh = $this->getDBHandler(); $query = "SELECT id, private_key, public_key, alg, creation_time FROM rsa_keypairs WHERE id = :id"; $stmt = $dbh->prepare($query); $stmt->bindParam(':id', $id); $stmt->execute(); foreach ($stmt->fetchAll() as $row) { return $this->getRSAKeyPairFromResultRow($row); } return null; } public function getNewestKeyPair(): RSAKeyPair { $dbh = $this->getDBHandler(); Loading index.php +2 −0 Original line number Diff line number Diff line Loading @@ -37,12 +37,14 @@ Flight::map('error', function($ex) { http_response_code(401); echo "Unauthorized: " . $ex->message; } else if ($ex instanceof \Exception) { http_response_code(500); if ($ex->getMessage() !== null) { echo $ex->getMessage(); } else { echo $ex->getTraceAsString(); } } else { http_response_code(500); throw $ex; } }); Loading Loading
classes/IdTokenBuilder.php +1 −1 Original line number Diff line number Diff line Loading @@ -29,7 +29,7 @@ class IdTokenBuilder { 'iss' => $this->locator->config->jwtIssuer, 'sub' => $user->id, 'iat' => time(), 'exp' => time() + 120, 'exp' => time() + 3600, 'name' => $user->getCompleteName() ); Loading
classes/OAuth2RequestHandler.php +29 −1 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ namespace RAP; use \Firebase\JWT\JWT; class OAuth2RequestHandler { private $locator; Loading Loading @@ -166,7 +168,33 @@ class OAuth2RequestHandler { } $accessToken = $this->locator->getAccessTokenDAO()->getAccessToken($bearer_token); if ($accessToken->expired) { if ($accessToken === null) { $this->attemptJWTTokenValidation($bearer_token); } else if ($accessToken->expired) { throw new UnauthorizedException("Access token is expired"); } } private function attemptJWTTokenValidation($jwt): void { $jwtParts = explode('.', $jwt); if (count($jwtParts) === 0) { throw new UnauthorizedException("Invalid token"); } $header = JWT::jsonDecode(JWT::urlsafeB64Decode($jwtParts[0])); if (!isset($header->kid)) { throw new UnauthorizedException("Invalid token: missing kid in header"); } $keyPair = $this->locator->getJWKSDAO()->getRSAKeyPairById($header->kid); if ($keyPair === null) { throw new UnauthorizedException("Invalid kid: no key found"); } try { JWT::decode($jwt, $keyPair->publicKey, [$keyPair->alg]); } catch (\Firebase\JWT\ExpiredException $ex) { throw new UnauthorizedException("Access token is expired"); } } Loading
classes/datalayer/JWKSDAO.php +2 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,8 @@ interface JWKSDAO { public function getRSAKeyPairs(): array; public function getRSAKeyPairById(string $id): ?RSAKeyPair; public function insertRSAKeyPair(RSAKeyPair $keyPair): RSAKeyPair; public function getNewestKeyPair(): RSAKeyPair; Loading
classes/datalayer/mysql/MySQLJWKSDAO.php +17 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,23 @@ class MySQLJWKSDAO extends BaseMySQLDAO implements JWKSDAO { return $keyPairs; } public function getRSAKeyPairById(string $id): ?RSAKeyPair { $dbh = $this->getDBHandler(); $query = "SELECT id, private_key, public_key, alg, creation_time FROM rsa_keypairs WHERE id = :id"; $stmt = $dbh->prepare($query); $stmt->bindParam(':id', $id); $stmt->execute(); foreach ($stmt->fetchAll() as $row) { return $this->getRSAKeyPairFromResultRow($row); } return null; } public function getNewestKeyPair(): RSAKeyPair { $dbh = $this->getDBHandler(); Loading
index.php +2 −0 Original line number Diff line number Diff line Loading @@ -37,12 +37,14 @@ Flight::map('error', function($ex) { http_response_code(401); echo "Unauthorized: " . $ex->message; } else if ($ex instanceof \Exception) { http_response_code(500); if ($ex->getMessage() !== null) { echo $ex->getMessage(); } else { echo $ex->getTraceAsString(); } } else { http_response_code(500); throw $ex; } }); Loading