diff --git a/classes/IdTokenBuilder.php b/classes/IdTokenBuilder.php index 1ea499de588ce879559ed0653029fbc4d0702f88..a198208ae65a44d5abd44645b20340b909f91ee0 100644 --- a/classes/IdTokenBuilder.php +++ b/classes/IdTokenBuilder.php @@ -12,16 +12,16 @@ class IdTokenBuilder { $this->locator = $locator; } - public function getIdToken(AccessToken $accessToken): string { + public function getIdToken(AccessToken $accessToken, $nonce = null): string { $keyPair = $this->locator->getJWKSDAO()->getNewestKeyPair(); - $payload = $this->createPayloadArray($accessToken); + $payload = $this->createPayloadArray($accessToken, $nonce); return JWT::encode($payload, $keyPair->privateKey, $keyPair->alg, $keyPair->keyId); } - private function createPayloadArray(AccessToken $accessToken) { + private function createPayloadArray(AccessToken $accessToken, $nonce = null) { $user = $this->locator->getUserDAO()->findUserById($accessToken->userId); @@ -30,9 +30,14 @@ class IdTokenBuilder { 'sub' => $user->id, 'iat' => time(), 'exp' => time() + 3600, - 'name' => $user->getCompleteName() + 'name' => $user->getCompleteName(), + 'aud' => $accessToken->clientId ); + if ($nonce !== null) { + $payloadArr['nonce'] = $nonce; + } + if (in_array("email", $accessToken->scope)) { $payloadArr['email'] = $user->getPrimaryEmail(); } diff --git a/classes/JWKSHandler.php b/classes/JWKSHandler.php index 48b58226fb14af6d4575dd1008245e279fa51f6d..4c2ca9b645ba17b53bc51f32c717a060adda1af0 100644 --- a/classes/JWKSHandler.php +++ b/classes/JWKSHandler.php @@ -21,7 +21,8 @@ class JWKSHandler { $rsa->setPrivateKeyFormat(RSA::PRIVATE_FORMAT_PKCS1); $rsa->setPublicKeyFormat(RSA::PUBLIC_FORMAT_PKCS8); - $result = $rsa->createKey(); + // Guacamole needs a key of at least 2048 + $result = $rsa->createKey(2048); $keyPair = new RSAKeyPair(); $keyPair->alg = 'RS256'; diff --git a/classes/OAuth2RequestHandler.php b/classes/OAuth2RequestHandler.php index 08c996768bbc436996a5b47dedcb0ff9c4bfb158..44175c438bf76b0347beb58d1773b1817348541f 100644 --- a/classes/OAuth2RequestHandler.php +++ b/classes/OAuth2RequestHandler.php @@ -36,8 +36,10 @@ class OAuth2RequestHandler { } $state = $params['state']; - if ($state === null) { - throw new BadRequestException("State is required"); + $nonce = $params['nonce']; + + if ($state === null && $nonce === null) { + throw new BadRequestException("State or nonce is required"); } // Storing OAuth2 data in session @@ -45,6 +47,7 @@ class OAuth2RequestHandler { $oauth2Data->clientId = $client->client; $oauth2Data->redirectUrl = $client->redirectUrl; $oauth2Data->state = $state; + $oauth2Data->nonce = $nonce; $scope = $params['scope']; if ($scope !== null) { @@ -55,7 +58,7 @@ class OAuth2RequestHandler { $session->setOAuth2Data($oauth2Data); } - public function getCodeResponseUrl(): string { + public function getRedirectResponseUrl(): string { $session = $this->locator->getSession(); @@ -70,9 +73,17 @@ class OAuth2RequestHandler { $this->locator->getAccessTokenDAO()->createAccessToken($accessToken); $state = $session->getOAuth2Data()->state; + $nonce = $session->getOAuth2Data()->nonce; - $redirectUrl = $session->getOAuth2Data()->redirectUrl - . '?code=' . $accessToken->code . '&scope=profile&state=' . $state; + if ($state !== null) { + // Authorization code grant flow + $redirectUrl = $session->getOAuth2Data()->redirectUrl + . '?code=' . $accessToken->code . '&scope=profile&state=' . $state; + } else { + // Implicit grant flow + $idToken = $this->locator->getIdTokenBuilder()->getIdToken($accessToken, $nonce); + $redirectUrl = $session->getOAuth2Data()->redirectUrl . "#id_token=" . $idToken; + } return $redirectUrl; } diff --git a/classes/login/LoginHandler.php b/classes/login/LoginHandler.php index 0bb85fd34be1f08db06f95c6c5bc0cef243089a3..198e140aa78b1cc55f8155097416ec6dd856a9a5 100644 --- a/classes/login/LoginHandler.php +++ b/classes/login/LoginHandler.php @@ -75,7 +75,7 @@ class LoginHandler { if ($session->getOAuth2Data() !== null) { $session->setUser($user); - $redirectUrl = $this->locator->getOAuth2RequestHandler()->getCodeResponseUrl(); + $redirectUrl = $this->locator->getOAuth2RequestHandler()->getRedirectResponseUrl(); session_destroy(); return $redirectUrl; } diff --git a/classes/model/OAuth2Data.php b/classes/model/OAuth2Data.php index f4ae310449345126fe8b1d98974cdbba75855e92..9716301cddf32d11ca4664d931e88056df1ce1d4 100644 --- a/classes/model/OAuth2Data.php +++ b/classes/model/OAuth2Data.php @@ -8,5 +8,6 @@ class OAuth2Data { public $redirectUrl; public $state; public $scope; + public $nonce; } diff --git a/include/front-controller.php b/include/front-controller.php index d47c05b809afe1192edc9368477559cce6c6e3b6..90a9da3af63c52dd2c07dae286e0b3a39bd8b779 100644 --- a/include/front-controller.php +++ b/include/front-controller.php @@ -79,7 +79,8 @@ Flight::route('GET /auth/oauth2/authorize', function() { "redirect_uri" => filter_input(INPUT_GET, 'redirect_uri', FILTER_SANITIZE_STRING), "alg" => filter_input(INPUT_GET, 'alg', FILTER_SANITIZE_STRING), "state" => filter_input(INPUT_GET, 'state', FILTER_SANITIZE_STRING), - "scope" => filter_input(INPUT_GET, 'scope', FILTER_SANITIZE_STRING) + "scope" => filter_input(INPUT_GET, 'scope', FILTER_SANITIZE_STRING), + "nonce" => filter_input(INPUT_GET, 'nonce', FILTER_SANITIZE_STRING) ]; $requestHandler = new \RAP\OAuth2RequestHandler($locator);