Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Private claims implementation #1122

Open
wants to merge 40 commits into
base: 9.0.0-WIP
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
517403b
Basic implementation of private claims
skroczek Jun 3, 2020
aefdde5
Adds private claims to the grant types
skroczek Jun 4, 2020
f6d5ed0
Fixes styles
skroczek Jun 4, 2020
962506e
Makes ClaimRepository optional in AuthorizationServer constructor.
skroczek Jun 4, 2020
d2888f1
Fixes styles II
skroczek Jun 4, 2020
3630fc7
Adds testing for claims
skroczek Jun 5, 2020
108b1ee
Fixes style of claim entity stub
skroczek Jun 5, 2020
8dd31f5
Fixes phpstan errors
skroczek Jun 5, 2020
12d8643
Removes unused JsonSerializable interface
skroczek Jul 16, 2020
d6d45d9
Adds ClaimEntityTrait
skroczek Jul 16, 2020
ba02f3b
Removes useless claim parameter
skroczek Jul 16, 2020
7ac954b
Removes confusing ClaimEntity argument
skroczek Jul 16, 2020
c659a19
Asserts that the claim has been set
skroczek Jul 16, 2020
8e1473c
Fixes cs
skroczek Jul 16, 2020
7256a3c
Fixes phpstan error
skroczek Jul 16, 2020
f0a3e97
Adds and uses TokenInterface::addClaim() method and removes $claims p…
skroczek Jul 23, 2020
381e415
Revert formatting change
Sephster Jul 27, 2020
1db5e24
Fix formatting issue
Sephster Jul 27, 2020
9891fdb
Add blank line above block
Sephster Jul 27, 2020
e8b1942
Fix formatting and make if check more explicit
Sephster Jul 27, 2020
970ef40
Fix formatting and make if check more explicit
Sephster Jul 27, 2020
5bd8127
Fix formatting and make if check more explicit
Sephster Jul 27, 2020
162a02e
Fix formatting and make if check more explicit
Sephster Jul 27, 2020
88b5705
Fix formatting and make if check more explicit
Sephster Jul 27, 2020
1842975
Fix formatting and make if check more explicit
Sephster Jul 27, 2020
74a934e
Revert docblock hint change as not required for this PR
Sephster Jul 27, 2020
40fed67
Revert formatting change
Sephster Jul 27, 2020
d240052
Changes copyright
skroczek Jul 27, 2020
b8141f9
Merge remote-tracking branch 'upstream/master' into wip/private-claims
Sephster Sep 30, 2020
6bcff56
StyleCI fix
Sephster Sep 30, 2020
73f49e5
Merge in 9.0.0 branch
Sephster Sep 30, 2020
568c787
Apply StyleCI change
Sephster Sep 30, 2020
0aef818
Fix test
Sephster Oct 1, 2020
d43c63c
StyleCI fixes
Sephster Oct 1, 2020
5a71aaf
Update changelog
Sephster Oct 1, 2020
1d79e35
Remove getClaims and addClaim from TokenInterface
Sephster Oct 1, 2020
6710412
Add method exists for addClaim on token
Sephster Oct 1, 2020
0302141
StyleCI fixes
Sephster Oct 1, 2020
dc2f7ac
Merge remote-tracking branch 'upstream/9.0.0-WIP' into wip/private-cl…
JRogaishio Aug 8, 2023
2ea4450
Merge pull request #1 from JRogaishio/wip/private-claims
skroczek Sep 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- A CryptKeyInterface to allow developers to change the CryptKey implementation with greater ease (PR #1044)
- The authorization server can now finalize scopes when a client uses a refresh token (PR #1094)
- An AuthorizationRequestInterface to make it easier to extend the AuthorizationRequest (PR #1110)
- Ability to set custom claims on a JWT (PR #1122)

### Fixed
- If a refresh token has expired, been revoked, cannot be decrypted, or does not belong to the correct client, the server will now issue an `invalid_grant` error and a HTTP 400 response. In previous versions the server incorrectly issued an `invalid_request` and HTTP 401 response (PR #1042) (PR #1082)
Expand Down
12 changes: 11 additions & 1 deletion src/AuthorizationServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\Grant\GrantTypeInterface;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ClaimRepositoryInterface;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
use League\OAuth2\Server\RequestTypes\AuthorizationRequestInterface;
Expand Down Expand Up @@ -69,6 +70,11 @@ class AuthorizationServer implements EmitterAwareInterface
*/
private $scopeRepository;

/**
* @var null|ClaimRepositoryInterface
*/
private $claimRepository;

/**
* @var string|Key
*/
Expand All @@ -93,18 +99,21 @@ class AuthorizationServer implements EmitterAwareInterface
* @param CryptKeyInterface|string $privateKey
* @param string|Key $encryptionKey
* @param null|ResponseTypeInterface $responseType
* @param null|ClaimRepositoryInterface $claimRepository
*/
public function __construct(
ClientRepositoryInterface $clientRepository,
AccessTokenRepositoryInterface $accessTokenRepository,
ScopeRepositoryInterface $scopeRepository,
$privateKey,
$encryptionKey,
ResponseTypeInterface $responseType = null
ResponseTypeInterface $responseType = null,
ClaimRepositoryInterface $claimRepository = null
) {
$this->clientRepository = $clientRepository;
$this->accessTokenRepository = $accessTokenRepository;
$this->scopeRepository = $scopeRepository;
$this->claimRepository = $claimRepository;

if ($privateKey instanceof CryptKeyInterface === false) {
$privateKey = new CryptKey($privateKey);
Expand Down Expand Up @@ -137,6 +146,7 @@ public function enableGrantType(GrantTypeInterface $grantType, DateInterval $acc
$grantType->setAccessTokenRepository($this->accessTokenRepository);
$grantType->setClientRepository($this->clientRepository);
$grantType->setScopeRepository($this->scopeRepository);
$grantType->setClaimRepository($this->claimRepository);
$grantType->setDefaultScope($this->defaultScope);
$grantType->setPrivateKey($this->privateKey);
$grantType->setEmitter($this->getEmitter());
Expand Down
27 changes: 27 additions & 0 deletions src/Entities/ClaimEntityInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
/**
* @author Sebastian Kroczek <[email protected]>
* @copyright Copyright (c) Alex Bilbie
* @license http://mit-license.org/
*
* @link https://github.com/thephpleague/oauth2-server
*/

namespace League\OAuth2\Server\Entities;

interface ClaimEntityInterface
{
/**
* Get the claim's name.
*
* @return string
*/
public function getName();

/**
* Get the claim's value
*
* @return mixed
*/
public function getValue();
}
20 changes: 16 additions & 4 deletions src/Entities/Traits/AccessTokenTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Lcobucci\JWT\Signer\Rsa\Sha256;
use Lcobucci\JWT\Token;
use League\OAuth2\Server\CryptKeyInterface;
use League\OAuth2\Server\Entities\ClaimEntityInterface;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\ScopeEntityInterface;

Expand Down Expand Up @@ -59,14 +60,20 @@ private function convertToJWT()
{
$this->initJwtConfiguration();

return $this->jwtConfiguration->builder()
->permittedFor($this->getClient()->getIdentifier())
$builder = $this->jwtConfiguration->builder();

$builder->permittedFor($this->getClient()->getIdentifier())
->identifiedBy($this->getIdentifier())
->issuedAt(new DateTimeImmutable())
->canOnlyBeUsedAfter(new DateTimeImmutable())
->expiresAt($this->getExpiryDateTime())
->relatedTo((string) $this->getUserIdentifier())
->withClaim('scopes', $this->getScopes())
->relatedTo((string) $this->getUserIdentifier());

foreach ($this->getClaims() as $claim) {
$builder->withClaim($claim->getName(), $claim->getValue());
}

return $builder->withClaim('scopes', $this->getScopes())
->getToken($this->jwtConfiguration->signer(), $this->jwtConfiguration->signingKey());
}

Expand Down Expand Up @@ -98,6 +105,11 @@ abstract public function getUserIdentifier();
*/
abstract public function getScopes();

/**
* @return ClaimEntityInterface[]
*/
abstract public function getClaims();

/**
* @return string
*/
Expand Down
43 changes: 43 additions & 0 deletions src/Entities/Traits/ClaimEntityTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
/**
* @author Sebastian Kroczek <[email protected]>
* @copyright Copyright (c) Alex Bilbie
* @license http://mit-license.org/
*
* @link https://github.com/thephpleague/oauth2-server
*/

namespace League\OAuth2\Server\Entities\Traits;

trait ClaimEntityTrait
{
/**
* @var string
*/
protected $name;

/**
* @var mixed
*/
protected $value;

/**
* Returns the name of the claim
*
* @return string
*/
public function getName()
{
return $this->name;
}

/**
* Returns the claims value
*
* @return mixed
*/
public function getValue()
{
return $this->value;
}
}
26 changes: 26 additions & 0 deletions src/Entities/Traits/TokenEntityTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
namespace League\OAuth2\Server\Entities\Traits;

use DateTimeImmutable;
use League\OAuth2\Server\Entities\ClaimEntityInterface;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\ScopeEntityInterface;

Expand All @@ -20,6 +21,11 @@ trait TokenEntityTrait
*/
protected $scopes = [];

/**
* @var ClaimEntityInterface[]
*/
protected $claims = [];

/**
* @var DateTimeImmutable
*/
Expand Down Expand Up @@ -55,6 +61,26 @@ public function getScopes()
return \array_values($this->scopes);
}

/**
* Associate a claim with the token.
*
* @param ClaimEntityInterface $claim
*/
public function addClaim(ClaimEntityInterface $claim)
{
$this->claims[] = $claim;
}

/**
* Return an array of claims associated with the token.
*
* @return ClaimEntityInterface[]
*/
public function getClaims()
{
return $this->claims;
}

/**
* Get the token's expiry date time.
*
Expand Down
26 changes: 25 additions & 1 deletion src/Grant/AbstractGrant.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use League\OAuth2\Server\CryptTrait;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
use League\OAuth2\Server\Entities\ClaimEntityInterface;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
use League\OAuth2\Server\Entities\ScopeEntityInterface;
Expand All @@ -27,6 +28,7 @@
use League\OAuth2\Server\RedirectUriValidators\RedirectUriValidator;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
use League\OAuth2\Server\Repositories\ClaimRepositoryInterface;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
Expand Down Expand Up @@ -63,6 +65,12 @@ abstract class AbstractGrant implements GrantTypeInterface
*/
protected $scopeRepository;

/**
* @var null|ClaimRepositoryInterface
*/
protected $claimRepository;


/**
* @var AuthCodeRepositoryInterface
*/
Expand Down Expand Up @@ -122,6 +130,14 @@ public function setScopeRepository(ScopeRepositoryInterface $scopeRepository)
$this->scopeRepository = $scopeRepository;
}

/**
* @param ClaimRepositoryInterface $claimRepository
*/
public function setClaimRepository(?ClaimRepositoryInterface $claimRepository)
{
$this->claimRepository = $claimRepository;
}

/**
* @param RefreshTokenRepositoryInterface $refreshTokenRepository
*/
Expand Down Expand Up @@ -440,6 +456,7 @@ protected function getServerParameter($parameter, ServerRequestInterface $reques
* @param ClientEntityInterface $client
* @param string|null $userIdentifier
* @param ScopeEntityInterface[] $scopes
* @param ClaimEntityInterface[] $claims
*
* @throws OAuthServerException
* @throws UniqueTokenIdentifierConstraintViolationException
Expand All @@ -450,14 +467,21 @@ protected function issueAccessToken(
DateInterval $accessTokenTTL,
ClientEntityInterface $client,
$userIdentifier,
array $scopes = []
array $scopes = [],
array $claims = []
) {
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;

$accessToken = $this->accessTokenRepository->getNewToken($client, $scopes, $userIdentifier);
$accessToken->setExpiryDateTime((new DateTimeImmutable())->add($accessTokenTTL));
$accessToken->setPrivateKey($this->privateKey);

if (\method_exists($accessToken, 'addClaim')) {
foreach ($claims as $claim) {
$accessToken->addClaim($claim);
}
}

while ($maxGenerationAttempts-- > 0) {
$accessToken->setIdentifier($this->generateUniqueIdentifier());
try {
Expand Down
12 changes: 11 additions & 1 deletion src/Grant/AuthCodeGrant.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,18 @@ public function respondToAccessTokenRequest(
}
}

$privateClaims = [];

if ($this->claimRepository !== null) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First of all, sorry for the (very) late comment. But just got an email that people are interested again.
Maybe just personal preference, but checking if something is not null is not actually checking anything (because it can be ANYTHING at this point).
I'd rather check if it is what I want it to be, e.g. an instanceof check.

$privateClaims = $this->claimRepository->getClaims(
$this->getIdentifier(),
$client,
$authCodePayload->user_id
);
}

// Issue and persist new access token
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes);
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes, $privateClaims);
$this->getEmitter()->emit(new RequestAccessTokenEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request, $accessToken));
$responseType->setAccessToken($accessToken);

Expand Down
8 changes: 7 additions & 1 deletion src/Grant/ClientCredentialsGrant.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,14 @@ public function respondToAccessTokenRequest(
// Finalize the requested scopes
$finalizedScopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client);

$privateClaims = [];

if ($this->claimRepository !== null) {
$privateClaims = $this->claimRepository->getClaims($this->getIdentifier(), $client);
}

// Issue and persist access token
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, null, $finalizedScopes);
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, null, $finalizedScopes, $privateClaims);

// Send event to emitter
$this->getEmitter()->emit(new RequestAccessTokenEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request, $accessToken));
Expand Down
8 changes: 8 additions & 0 deletions src/Grant/GrantTypeInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use League\Event\EmitterAwareInterface;
use League\OAuth2\Server\CryptKeyInterface;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ClaimRepositoryInterface;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
use League\OAuth2\Server\RequestTypes\AuthorizationRequestInterface;
Expand Down Expand Up @@ -121,6 +122,13 @@ public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessT
*/
public function setScopeRepository(ScopeRepositoryInterface $scopeRepository);

/**
* Set the claim repository.
*
* @param ClaimRepositoryInterface $claimRepository
*/
public function setClaimRepository(?ClaimRepositoryInterface $claimRepository);

/**
* Set the default scope.
*
Expand Down
13 changes: 12 additions & 1 deletion src/Grant/ImplicitGrant.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,22 @@ public function completeAuthorizationRequest(AuthorizationRequestInterface $auth
$authorizationRequest->getUser()->getIdentifier()
);

$privateClaims = [];

if ($this->claimRepository !== null) {
$privateClaims = $this->claimRepository->getClaims(
$this->getIdentifier(),
$authorizationRequest->getClient(),
$authorizationRequest->getUser()->getIdentifier()
);
}

$accessToken = $this->issueAccessToken(
$this->accessTokenTTL,
$authorizationRequest->getClient(),
$authorizationRequest->getUser()->getIdentifier(),
$finalizedScopes
$finalizedScopes,
$privateClaims
);

$response = new RedirectResponse();
Expand Down
Loading