From 2705296048ae3c102f77c9f772e3ee2d2fd8489e Mon Sep 17 00:00:00 2001 From: Mike van der Zijden Date: Tue, 5 Nov 2024 08:39:53 +0100 Subject: [PATCH 1/3] feature - add non-default claims to request automatically --- src/Oauth2Module.php | 64 +++++++++++++++++++ .../web/server/Oauth2RevokeAction.php | 23 +------ 2 files changed, 65 insertions(+), 22 deletions(-) diff --git a/src/Oauth2Module.php b/src/Oauth2Module.php index 7bd335f..52e1b71 100644 --- a/src/Oauth2Module.php +++ b/src/Oauth2Module.php @@ -13,6 +13,11 @@ use Defuse\Crypto\Exception\EnvironmentIsBrokenException; use GuzzleHttp\Psr7\Response as Psr7Response; use GuzzleHttp\Psr7\ServerRequest as Psr7ServerRequest; +use Lcobucci\JWT\Configuration; +use Lcobucci\JWT\Signer\Key\InMemory; +use Lcobucci\JWT\Signer\Rsa\Sha256; +use Lcobucci\JWT\Token; +use Lcobucci\JWT\Validation\Constraint\SignedWith; use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Grant\GrantTypeInterface; use rhertogh\Yii2Oauth2Server\base\Oauth2BaseModule; @@ -1390,6 +1395,13 @@ public function validateAuthenticatedRequest() $psr7Request = $this->getResourceServer()->validateAuthenticatedRequest($psr7Request); + $claims = $this->getAccessTokenClaims(Yii::$app->request->getBodyParam('token')); + foreach ($claims->all() as $claimKey => $claimValue) { + if (!$this->isDefaultClaimKey($claimKey)) { + $psr7Request = $psr7Request->withAttribute($claimKey, $claimValue); + } + } + $this->_oauthClaims = $psr7Request->getAttributes(); $this->_oauthClaimsAuthorizationHeader = Yii::$app->request->getHeaders()->get('Authorization'); } @@ -1572,4 +1584,56 @@ public function getElaboratedHttpClientErrorsLogLevel() return $this->httpClientErrorsLogLevel; } + + + public function getJwtConfiguration(): Configuration + { + // Based on \League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator::initJwtConfiguration(). + $jwtConfiguration = Configuration::forSymmetricSigner( + new Sha256(), + InMemory::plainText('empty', 'empty') + ); + + $publicKey = $this->getPublicKey(); + $jwtConfiguration->setValidationConstraints( + new SignedWith( + new Sha256(), + InMemory::plainText($publicKey->getKeyContents(), $publicKey->getPassPhrase() ?? '') + ) + ); + + return $jwtConfiguration; + } + + public function getAccessToken(string $token): Token + { + $jwtConfiguration = $this->getJwtConfiguration(); + $accessToken = $jwtConfiguration->parser()->parse($token); + $jwtConfiguration->validator()->assert($accessToken, ...$jwtConfiguration->validationConstraints()); + Yii::debug('Found access token: ' . $token, __METHOD__); + + return $accessToken; + } + + public function getAccessTokenClaims(string $token): Token\DataSet + { + return $this->getAccessToken($token)->claims(); + } + + private function isDefaultClaimKey(string $claimKey): bool + { + return in_array( + $claimKey, + [ + 'aud', + 'jti', + 'iat', + 'nbf', + 'exp', + 'sub', + 'scopes', + 'client_id', + ] + ); + } } diff --git a/src/controllers/web/server/Oauth2RevokeAction.php b/src/controllers/web/server/Oauth2RevokeAction.php index f38e786..5163bac 100644 --- a/src/controllers/web/server/Oauth2RevokeAction.php +++ b/src/controllers/web/server/Oauth2RevokeAction.php @@ -4,10 +4,6 @@ use Defuse\Crypto\Crypto; use Defuse\Crypto\Key; -use Lcobucci\JWT\Configuration; -use Lcobucci\JWT\Signer\Key\InMemory; -use Lcobucci\JWT\Signer\Rsa\Sha256; -use Lcobucci\JWT\Validation\Constraint\SignedWith; use rhertogh\Yii2Oauth2Server\controllers\web\Oauth2ServerController; use rhertogh\Yii2Oauth2Server\controllers\web\server\base\Oauth2BaseServerAction; use rhertogh\Yii2Oauth2Server\helpers\Oauth2RequestHelper; @@ -156,24 +152,7 @@ protected function parseTokenAsRefreshToken(Oauth2Module $module, string $token, protected function parseTokenAsAccessToken(Oauth2Module $module, string $token, string $tokenTypeHint) { try { - // Based on \League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator::initJwtConfiguration(). - $jwtConfiguration = Configuration::forSymmetricSigner( - new Sha256(), - InMemory::plainText('empty', 'empty') - ); - - $publicKey = $module->getPublicKey(); - $jwtConfiguration->setValidationConstraints( - new SignedWith( - new Sha256(), - InMemory::plainText($publicKey->getKeyContents(), $publicKey->getPassPhrase() ?? '') - ) - ); - - $accessToken = $jwtConfiguration->parser()->parse($token); - $jwtConfiguration->validator()->assert($accessToken, ...$jwtConfiguration->validationConstraints()); - Yii::debug('Found access token: ' . $token, __METHOD__); - $accessTokenClaims = $accessToken->claims(); + $accessTokenClaims = $module->getAccessTokenClaims($token); $accessTokenIdentifier = $accessTokenClaims->get('jti'); $clientIdentifier = $accessTokenClaims->get('client_id'); From b6693ffab3886c6533bf3017f06cdad9e41d8d56 Mon Sep 17 00:00:00 2001 From: Mike van der Zijden Date: Tue, 5 Nov 2024 11:47:07 +0100 Subject: [PATCH 2/3] bugfix - Actually get token instead to get claims, make private function protected --- src/Oauth2Module.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Oauth2Module.php b/src/Oauth2Module.php index 52e1b71..eff98ee 100644 --- a/src/Oauth2Module.php +++ b/src/Oauth2Module.php @@ -1395,10 +1395,15 @@ public function validateAuthenticatedRequest() $psr7Request = $this->getResourceServer()->validateAuthenticatedRequest($psr7Request); - $claims = $this->getAccessTokenClaims(Yii::$app->request->getBodyParam('token')); - foreach ($claims->all() as $claimKey => $claimValue) { - if (!$this->isDefaultClaimKey($claimKey)) { - $psr7Request = $psr7Request->withAttribute($claimKey, $claimValue); + $token = substr(Yii::$app->request->headers->get('Authorization'), 7); + + if ($token) { + $claims = $this->getAccessTokenClaims($token); + + foreach ($claims->all() as $claimKey => $claimValue) { + if (!$this->isDefaultClaimKey($claimKey)) { + $psr7Request = $psr7Request->withAttribute($claimKey, $claimValue); + } } } @@ -1620,7 +1625,7 @@ public function getAccessTokenClaims(string $token): Token\DataSet return $this->getAccessToken($token)->claims(); } - private function isDefaultClaimKey(string $claimKey): bool + protected function isDefaultClaimKey(string $claimKey): bool { return in_array( $claimKey, From b5d1f2e4140d020775f7c547e503e479856a9bac Mon Sep 17 00:00:00 2001 From: Mike van der Zijden Date: Tue, 5 Nov 2024 12:04:08 +0100 Subject: [PATCH 3/3] bugfix - Removed unnecessary function, set getRequestOauthClaim scope to public --- CHANGELOG.md | 3 +++ src/Oauth2Module.php | 16 ++++++++-------- .../web/server/Oauth2RevokeAction.php | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5337a32..ef1bcd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,11 @@ Please check the [Upgrading Instructions](UPGRADE.md) when upgrading to a newer ### Added - Initiating User Registration via OpenID Connect. (rhertogh) +- Addition of all extra claims in access token to request. (m.vanderzijden) ### Changed +- Altered scope of getRequestOauthClaim function to public. (m.vanderzijden) +- Centralized JWTConfiguration to Oauth2Module. (m.vanderzijden) ### Deprecated diff --git a/src/Oauth2Module.php b/src/Oauth2Module.php index eff98ee..3f25389 100644 --- a/src/Oauth2Module.php +++ b/src/Oauth2Module.php @@ -222,6 +222,11 @@ class Oauth2Module extends Oauth2BaseModule implements BootstrapInterface, Defau ] ]; + /** + * Offset of Bearer: in Authorization header + */ + protected const BEARER_TOKEN_OFFSET = 7; + /** * @inheritdoc */ @@ -1395,10 +1400,10 @@ public function validateAuthenticatedRequest() $psr7Request = $this->getResourceServer()->validateAuthenticatedRequest($psr7Request); - $token = substr(Yii::$app->request->headers->get('Authorization'), 7); + $token = substr(Yii::$app->request->headers->get('Authorization'), self::BEARER_TOKEN_OFFSET); if ($token) { - $claims = $this->getAccessTokenClaims($token); + $claims = $this->getAccessToken($token)->claims(); foreach ($claims->all() as $claimKey => $claimValue) { if (!$this->isDefaultClaimKey($claimKey)) { @@ -1510,7 +1515,7 @@ public function generatePersonalAccessToken($clientIdentifier, $userIdentifier, /** * @inheritDoc */ - protected function getRequestOauthClaim($attribute, $default = null) + public function getRequestOauthClaim($attribute, $default = null) { if (empty($this->_oauthClaimsAuthorizationHeader)) { // User authorization was not processed by Oauth2Module. @@ -1620,11 +1625,6 @@ public function getAccessToken(string $token): Token return $accessToken; } - public function getAccessTokenClaims(string $token): Token\DataSet - { - return $this->getAccessToken($token)->claims(); - } - protected function isDefaultClaimKey(string $claimKey): bool { return in_array( diff --git a/src/controllers/web/server/Oauth2RevokeAction.php b/src/controllers/web/server/Oauth2RevokeAction.php index 5163bac..75e01da 100644 --- a/src/controllers/web/server/Oauth2RevokeAction.php +++ b/src/controllers/web/server/Oauth2RevokeAction.php @@ -152,7 +152,7 @@ protected function parseTokenAsRefreshToken(Oauth2Module $module, string $token, protected function parseTokenAsAccessToken(Oauth2Module $module, string $token, string $tokenTypeHint) { try { - $accessTokenClaims = $module->getAccessTokenClaims($token); + $accessTokenClaims = $module->getAccessToken($token)->claims(); $accessTokenIdentifier = $accessTokenClaims->get('jti'); $clientIdentifier = $accessTokenClaims->get('client_id');