-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Add OpenID Response Type #1316
Open
marcriemer
wants to merge
57
commits into
thephpleague:master
Choose a base branch
from
marcriemer:openid-implementation
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Add OpenID Response Type #1316
Changes from all commits
Commits
Show all changes
57 commits
Select commit
Hold shift + click to select a range
6d95ac4
ID Token response for OIDC implementation
marcriemer 55e0d4e
Finalization of IdTokenResponce implementation
marcriemer d965e1a
Add IdTokenResponce related tests
marcriemer f588884
Fixed Coding Style
marcriemer a7a2c3e
Removed ServerRequestInterface
marcriemer 656d07e
Fixed code quality
marcriemer bbe4c20
Remove old ID token related const
marcriemer a8c58c9
Fixed CI issue
marcriemer dd55a7d
Fixed class name for id token events
marcriemer 4635e33
Apply fixes from StyleCI
marcriemer d2be736
Merge pull request #1 from marcriemer/analysis-ZnG0ON
marcriemer 8e00c4e
Fixed id token events and add ClaimExtractorIntercace
marcriemer 9afb766
Apply fixes from StyleCI
marcriemer 9249d96
Merge pull request #3 from marcriemer/analysis-g6LQJk
marcriemer e7c54f3
Add UserInfoResponse
marcriemer 35af257
Add ServerRequestInterface to getClaimSetEntry
marcriemer e9975a3
Revert "Add ServerRequestInterface to getClaimSetEntry"
marcriemer 5befb21
Fixed backwards compatibility
marcriemer d37193b
Fixed testGenerateHttpResponseWithIdToken test
marcriemer ffb4dc2
Apply fixes from StyleCI
marcriemer 65a14cb
Merge pull request #4 from marcriemer/analysis-g6LkZw
marcriemer a3856e6
lcobucci/jwt 3.4.6 compatibility
marcriemer a3cb121
Apply fixes from StyleCI
marcriemer 4e49f90
Merge pull request #5 from marcriemer/analysis-Ko3NmQ
marcriemer 68e1ca8
Add openid default claims
marcriemer f22eb58
Apply fixes from StyleCI
marcriemer f378d9e
Merge pull request #6 from marcriemer/analysis-o75ZmB
marcriemer 7fe78ac
Merge remote-tracking branch 'upstream/master' into openid-implementa…
Sephster 2503f38
Merge branch 'thephpleague:master' into openid-implementation
marcriemer 9fd5db9
Merge branch 'thephpleague:master' into openid-implementation
marcriemer ef616e4
Fixed interface name of ClaimExtractorInterface
marcriemer 5f1db1e
Renamed parameter
marcriemer 7bc34f7
Fixed ClaimExtractor
marcriemer 7c2141e
Merge branch 'thephpleague:master' into openid-implementation
marcriemer 4e25d35
Merge branch 'thephpleague:master' into openid-implementation
marcriemer 2e710f9
Changed ClaimSetInterface into ClaimSetEntryInterface
marcriemer f3e1990
solve conflicts
marcriemer 0170cf2
Apply fixes from StyleCI
marcriemer f50d749
Merge pull request #8 from marcriemer/analysis-PGEDro
marcriemer cdc66d3
Revert "Apply fixes from StyleCI"
marcriemer b3f2ca8
Merge pull request #9 from marcriemer/revert-8-analysis-PGEDro
marcriemer baaee9f
Merge branch 'thephpleague:master' into openid-implementation
marcriemer 4219c8c
Apply fixes from StyleCI
marcriemer 594b060
Merge pull request #12 from marcriemer/analysis-nebyG0
marcriemer 95f6ac3
Fix Lcobucci incompatibility and core quality
marcriemer 174c2b0
Fix unit test
marcriemer 58cbe2a
Fix code quality issues
marcriemer 9113224
Apply fixes from StyleCI
marcriemer c0d74c6
Merge pull request #14 from marcriemer/analysis-kYbjYy
marcriemer 1bdd17d
Merge branch 'thephpleague:master' into openid-implementation
marcriemer 4ab66a7
ClaimSetRepositoryInterface::getClaimSet returns a ClaimSetInterface
marcriemer 66e4dc6
Apply fixes from StyleCI
marcriemer d2447d8
Merge pull request #17 from marcriemer/analysis-4wLr71
marcriemer 799455d
fixed doc
marcriemer b1400a1
Fixed ClaimExtractor
marcriemer 9b30823
Apply fixes from StyleCI
marcriemer d4f5bf5
Merge pull request #18 from marcriemer/analysis-KoOamD
marcriemer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace League\OAuth2\Server\Repositories; | ||
|
||
use DateTimeImmutable; | ||
use Lcobucci\JWT\Encoding\ChainedFormatter; | ||
use Lcobucci\JWT\Encoding\JoseEncoder; | ||
use Lcobucci\JWT\Token\Builder; | ||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface; | ||
|
||
/** | ||
* Exmaple implemnation of IdTokenRepositoryInterface | ||
* | ||
* @author Marc Riemer <[email protected]> | ||
* @license http://opensource.org/licenses/MIT MIT | ||
*/ | ||
class IdTokenRepository implements IdTokenRepositoryInterface | ||
{ | ||
public function __construct(private string $issuedBy, private ?string $nonce = null) | ||
{ | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getBuilder(AccessTokenEntityInterface $accessToken): Builder | ||
{ | ||
$builder = (new Builder(new JoseEncoder(), ChainedFormatter::withUnixTimestampDates())) | ||
->permittedFor($accessToken->getClient()->getIdentifier()) | ||
->issuedBy($this->issuedBy) | ||
->issuedAt(new DateTimeImmutable()) | ||
->expiresAt($accessToken->getExpiryDateTime()) | ||
->relatedTo($accessToken->getUserIdentifier()); | ||
|
||
if ($this->nonce) { | ||
$builder->withClaim('nonce', $this->nonce); | ||
} | ||
|
||
return $builder; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace League\OAuth2\Server; | ||
|
||
use InvalidArgumentException; | ||
use League\OAuth2\Server\Entities\ClaimSetEntry; | ||
use League\OAuth2\Server\Entities\ClaimSetEntryInterface; | ||
use League\OAuth2\Server\Entities\ClaimSetInterface; | ||
use League\OAuth2\Server\Entities\ScopeEntityInterface; | ||
|
||
use function array_filter; | ||
use function array_intersect; | ||
use function array_keys; | ||
use function array_merge; | ||
use function in_array; | ||
use function sprintf; | ||
|
||
/** | ||
* ClaimExtractor | ||
* | ||
* @link https://github.com/steverhoades/oauth2-openid-connect-server | ||
* | ||
* @author Steve Rhoades <[email protected]> | ||
* @author Marc Riemer <[email protected]> | ||
*/ | ||
class ClaimExtractor implements ClaimExtractorInterface | ||
{ | ||
/** | ||
* claimSetEntries | ||
* | ||
* @var ClaimSetEntryInterface[] | ||
*/ | ||
protected array $claimSetEntries = []; | ||
|
||
/** | ||
* Protected claims | ||
* | ||
* @var string[] | ||
*/ | ||
protected array $protectedClaims = ['profile', 'email', 'address', 'phone']; | ||
|
||
/** | ||
* ClaimExtractor constructor | ||
* | ||
* @param array<int, ClaimSetEntryInterface> $claimSetEntries | ||
*/ | ||
public function __construct(array $claimSetEntries = []) | ||
{ | ||
$this->claimSetEntries = self::getDefaultClaimSetEnties(); | ||
foreach ($claimSetEntries as $claimSetEntry) { | ||
$this->addClaimSetEntry($claimSetEntry); | ||
} | ||
} | ||
|
||
/** | ||
* @return $this | ||
* | ||
* @throws \InvalidArgumentException | ||
*/ | ||
public function addClaimSetEntry(ClaimSetEntryInterface $claimSetEntry): ClaimExtractor | ||
{ | ||
if (in_array($claimSetEntry->getScope(), $this->protectedClaims) && !$this->getClaimSetEntry($claimSetEntry->getScope())) { | ||
throw new InvalidArgumentException( | ||
sprintf('%s is a protected scope and is pre-defined by the OpenID Connect specification.', $claimSetEntry->getScope()) | ||
); | ||
} | ||
|
||
$this->claimSetEntries[] = $claimSetEntry; | ||
|
||
return $this; | ||
} | ||
|
||
public function getClaimSetEntry(string $scope): ?ClaimSetEntryInterface | ||
{ | ||
foreach ($this->claimSetEntries as $entry) { | ||
if ($entry->getScope() === $scope) { | ||
return $entry; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/** | ||
* Get claimSetEntries | ||
* | ||
* @return array<ClaimSetInterface> | ||
*/ | ||
public function getClaimSetEntries(): array | ||
{ | ||
return $this->claimSetEntries; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function extract(array $scopes, array $claims): array | ||
{ | ||
$claimData = []; | ||
$keys = array_keys($claims); | ||
|
||
foreach ($scopes as $scope) { | ||
$scopeName = ($scope instanceof ScopeEntityInterface) ? $scope->getIdentifier() : $scope; | ||
|
||
$claimSet = $this->getClaimSetEntry($scopeName); | ||
if (null === $claimSet) { | ||
continue; | ||
} | ||
|
||
$intersected = array_intersect($claimSet->getClaims(), $keys); | ||
|
||
if (empty($intersected)) { | ||
continue; | ||
} | ||
|
||
$data = array_filter( | ||
$claims, | ||
function ($key) use ($intersected) { | ||
return in_array($key, $intersected); | ||
}, | ||
ARRAY_FILTER_USE_KEY | ||
); | ||
|
||
$claimData = array_merge($claimData, $data); | ||
} | ||
|
||
return $claimData; | ||
} | ||
|
||
/** | ||
* Create a array default openID connect claims | ||
* | ||
* @see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims | ||
* | ||
* @return ClaimSetEntry[] | ||
*/ | ||
public static function getDefaultClaimSetEnties(): array | ||
{ | ||
return [ | ||
new ClaimSetEntry('profile', [ | ||
'name', | ||
'family_name', | ||
'given_name', | ||
'middle_name', | ||
'nickname', | ||
'preferred_username', | ||
'profile', | ||
'picture', | ||
'website', | ||
'gender', | ||
'birthdate', | ||
'zoneinfo', | ||
'locale', | ||
'updated_at', | ||
]), | ||
new ClaimSetEntry('email', [ | ||
'email', | ||
'email_verified', | ||
]), | ||
new ClaimSetEntry('address', [ | ||
'address', | ||
]), | ||
new ClaimSetEntry('phone', [ | ||
'phone_number', | ||
'phone_number_verified', | ||
]), | ||
new ClaimSetEntry('openid', [ | ||
'nonce', | ||
'auth_time', | ||
'acr', | ||
'amr', | ||
'azp', | ||
]), | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace League\OAuth2\Server; | ||
|
||
use League\OAuth2\Server\Entities\ScopeEntityInterface; | ||
|
||
interface ClaimExtractorInterface | ||
{ | ||
/** | ||
* For given scopes and aggregated claims get all claims that have been configured on the extractor. | ||
* | ||
* @param array<int, ScopeEntityInterface> $scopes | ||
* @param array<string, string> $claims | ||
* | ||
* @return array<string, string> | ||
*/ | ||
public function extract(array $scopes, array $claims): array; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace League\OAuth2\Server\Entities; | ||
|
||
/** | ||
* ClaimSetEntry | ||
* | ||
* @author Steve Rhoades <[email protected]> | ||
* @author Marc Riemer <[email protected]> | ||
* @license http://opensource.org/licenses/MIT MIT | ||
*/ | ||
class ClaimSetEntry implements ClaimSetEntryInterface | ||
{ | ||
/** | ||
* Summary of __construct | ||
* | ||
* @param string $scope Scope of the claimset | ||
* @param string[] $claims The claims | ||
*/ | ||
public function __construct( | ||
protected string $scope, | ||
protected array $claims | ||
) { | ||
} | ||
|
||
/** | ||
* Get scope | ||
*/ | ||
public function getScope(): string | ||
{ | ||
return $this->scope; | ||
} | ||
|
||
/** | ||
* Get claims | ||
* | ||
* @return array<string, string> | ||
*/ | ||
public function getClaims(): array | ||
{ | ||
return $this->claims; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace League\OAuth2\Server\Entities; | ||
|
||
/** | ||
* ClaimSetEntryInterface | ||
* | ||
* @author Steve Rhoades <[email protected]> | ||
* @author Marc Riemer <[email protected]> | ||
* @license http://opensource.org/licenses/MIT MIT | ||
*/ | ||
interface ClaimSetEntryInterface extends ClaimSetInterface | ||
{ | ||
public function getScope(): string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace League\OAuth2\Server\Entities; | ||
|
||
/** | ||
* ClaimSetEntryInterface | ||
* | ||
* @author Steve Rhoades <[email protected]> | ||
* @author Marc Riemer <[email protected]> | ||
* @license http://opensource.org/licenses/MIT MIT | ||
*/ | ||
interface ClaimSetInterface | ||
{ | ||
/** | ||
* Get Claims | ||
* | ||
* @return array<string, string> | ||
*/ | ||
public function getClaims(): array; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace League\OAuth2\Server; | ||
|
||
use Lcobucci\JWT\Builder; | ||
|
||
/** | ||
* IdTokenClaimsCreatedEvent Event helps to extend claims of the id_token | ||
* | ||
* A usecase is to add nonce If requested by the client | ||
* | ||
* @author Marc Riemer <[email protected]> | ||
*/ | ||
final class IdTokenClaimsCreatedEvent extends IdTokenEvent | ||
{ | ||
/** | ||
* Builder | ||
*/ | ||
private Builder $builder; | ||
|
||
public function __construct(string $name, Builder $builder) | ||
{ | ||
parent::__construct($name); | ||
$this->builder = $builder; | ||
} | ||
|
||
public function getBuilder(): Builder | ||
{ | ||
return $this->builder; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace League\OAuth2\Server; | ||
|
||
use League\OAuth2\Server\EventEmitting\AbstractEvent; | ||
|
||
/** | ||
* IdTokenEvent | ||
* | ||
* @author Marc Riemer <[email protected]> | ||
*/ | ||
class IdTokenEvent extends AbstractEvent | ||
{ | ||
public const ID_TOKEN_ISSUED = 'id_token.issued'; | ||
|
||
// This event can be used to extent claims of the id_token | ||
public const ID_TOKEN_CLAIMS_CREATED = 'id_token.claims.created'; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't the nonce come from the authorization request ? Configuring as a constructor argument of the repository is probably not usable. It would be great to have an actual example of the openid setup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, the example is far from being perfect. The nonce must be part of the AuthCodeEntityInterface and used by ClaimSetRepositoryInterface to create ClaimSetInterface with the nonce claim.