Passed
Pull Request — master (#37)
by Thijs-jan
02:20
created

IdTokenResponse::getExtraParams()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 32
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 3
Bugs 0 Features 1
Metric Value
eloc 16
c 3
b 0
f 1
dl 0
loc 32
ccs 0
cts 16
cp 0
rs 9.4222
cc 5
nc 5
nop 1
crap 30
1
<?php
2
/**
3
 * @author Steve Rhoades <[email protected]>
4
 * @license http://opensource.org/licenses/MIT MIT
5
 */
6
namespace OpenIDConnectServer;
7
8
use Lcobucci\JWT\Signer\Key\LocalFileReference;
9
use OpenIDConnectServer\Repositories\IdentityProviderInterface;
10
use OpenIDConnectServer\Entities\ClaimSetInterface;
11
use League\OAuth2\Server\Entities\UserEntityInterface;
12
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
13
use League\OAuth2\Server\Entities\ScopeEntityInterface;
14
use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
15
use Lcobucci\JWT\Signer\Rsa\Sha256;
16
17
class IdTokenResponse extends BearerTokenResponse
18
{
19
    /**
20
     * @var IdentityProviderInterface
21
     */
22
    protected $identityProvider;
23
24
    /**
25
     * @var ClaimExtractor
26
     */
27
    protected $claimExtractor;
28
29 1
    public function __construct(
30
        IdentityProviderInterface $identityProvider,
31
        ClaimExtractor $claimExtractor
32
    ) {
33 1
        $this->identityProvider = $identityProvider;
34 1
        $this->claimExtractor   = $claimExtractor;
35 1
    }
36
37
    protected function getBuilder(AccessTokenEntityInterface $accessToken, UserEntityInterface $userEntity)
38
    {
39
        if (class_exists("Lcobucci\JWT\Token\Builder")) {
40
            $claimsFormatter = \Lcobucci\JWT\Encoding\ChainedFormatter::withUnixTimestampDates();
0 ignored issues
show
Bug introduced by
The type Lcobucci\JWT\Encoding\ChainedFormatter was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
41
            $builder = new \Lcobucci\JWT\Token\Builder(new \Lcobucci\JWT\Encoding\JoseEncoder(), $claimsFormatter);
0 ignored issues
show
Bug introduced by
The type Lcobucci\JWT\Encoding\JoseEncoder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
Bug introduced by
The type Lcobucci\JWT\Token\Builder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
42
        } else {
43
            $builder = new \Lcobucci\JWT\Builder();
44
        }
45
46
        // Since version 8.0 league/oauth2-server returns \DateTimeImmutable
47
        $expiresAt = $accessToken->getExpiryDateTime();
48
        if ($expiresAt instanceof \DateTime) {
0 ignored issues
show
introduced by
$expiresAt is never a sub-type of DateTime.
Loading history...
49
            $expiresAt = \DateTimeImmutable::createFromMutable($expiresAt);
50
        }
51
52
        // Add required id_token claims
53
        $builder
54
            ->permittedFor($accessToken->getClient()->getIdentifier())
0 ignored issues
show
Bug introduced by
$accessToken->getClient()->getIdentifier() of type string is incompatible with the type Lcobucci\JWT\list expected by parameter $audiences of Lcobucci\JWT\Builder::permittedFor(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

54
            ->permittedFor(/** @scrutinizer ignore-type */ $accessToken->getClient()->getIdentifier())
Loading history...
55
            ->issuedBy('https://' . $_SERVER['HTTP_HOST'])
56
            ->issuedAt(new \DateTimeImmutable())
57
            ->expiresAt($expiresAt)
58
            ->relatedTo($userEntity->getIdentifier());
59
60
        return $builder;
61
    }
62
63
    /**
64
     * @param AccessTokenEntityInterface $accessToken
65
     * @return array
66
     */
67
    protected function getExtraParams(AccessTokenEntityInterface $accessToken)
68
    {
69
        if (false === $this->isOpenIDRequest($accessToken->getScopes())) {
70
            return [];
71
        }
72
73
        /** @var UserEntityInterface $userEntity */
74
        $userEntity = $this->identityProvider->getUserEntityByIdentifier($accessToken->getUserIdentifier());
75
76
        if (false === is_a($userEntity, UserEntityInterface::class)) {
77
            throw new \RuntimeException('UserEntity must implement UserEntityInterface');
78
        } else if (false === is_a($userEntity, ClaimSetInterface::class)) {
79
            throw new \RuntimeException('UserEntity must implement ClaimSetInterface');
80
        }
81
82
        // Add required id_token claims
83
        $builder = $this->getBuilder($accessToken, $userEntity);
84
85
        // Need a claim factory here to reduce the number of claims by provided scope.
86
        $claims = $this->claimExtractor->extract($accessToken->getScopes(), $userEntity->getClaims());
87
88
        foreach ($claims as $claimName => $claimValue) {
89
            $builder = $builder->withClaim($claimName, $claimValue);
90
        }
91
92
        $token = $builder->getToken(
93
            new Sha256(),
94
            LocalFileReference::file($this->privateKey->getKeyPath(), (string) $this->privateKey->getPassPhrase())
95
        );
96
97
        return [
98
            'id_token' => $token->toString()
99
        ];
100
    }
101
102
    /**
103
     * @param ScopeEntityInterface[] $scopes
104
     * @return bool
105
     */
106
    private function isOpenIDRequest($scopes)
107
    {
108
        // Verify scope and make sure openid exists.
109
        $valid  = false;
110
111
        foreach ($scopes as $scope) {
112
            if ($scope->getIdentifier() === 'openid') {
113
                $valid = true;
114
                break;
115
            }
116
        }
117
118
        return $valid;
119
    }
120
121
}
122