Completed
Push — master ( 8a47a1...8e8d07 )
by Boris
14:37
created

AuthorizationServer   B

Complexity

Total Complexity 20

Size/Duplication

Total Lines 180
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 16

Importance

Changes 4
Bugs 1 Features 2
Metric Value
wmc 20
c 4
b 1
f 2
lcom 1
cbo 16
dl 0
loc 180
rs 8.4614

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
C requestAccessToken() 0 48 7
A checkGrantType() 0 4 1
A checkIfAClientIsAlwaysRequired() 0 5 1
A checkIfAClientIsProvided() 0 4 1
A checkIfTheProvidedClientIsValid() 0 7 1
A checkIfClientSupportsRequestedGrantType() 0 8 1
B buildAccessToken() 0 34 2
B buildRefreshToken() 0 29 2
A getGrantTypeByIdentifier() 0 11 3
1
<?php
2
/**
3
 * @author Boris Guéry <[email protected]>
4
 */
5
6
namespace Bgy\OAuth2;
7
8
use Bgy\OAuth2\GrantType\GrantDecision;
9
use Bgy\OAuth2\GrantType\GrantError;
10
use Bgy\OAuth2\GrantType\GrantType;
11
12
class AuthorizationServer
13
{
14
    private $configuration;
15
    private $clientAuthenticator;
16
17
    public function __construct(AuthorizationServerConfiguration $configuration)
18
    {
19
        $this->configuration       = $configuration;
20
        $this->clientAuthenticator = new ClientAuthenticator(
21
            $this->configuration->getClientStorage()
22
        );
23
    }
24
25
    /**
26
     * @param TokenRequestAttempt $tokenRequestAttempt
27
     * @return FailedTokenRequestAttemptResult|SuccessfulTokenRequestAttemptResult
28
     */
29
    public function requestAccessToken(TokenRequestAttempt $tokenRequestAttempt)
30
    {
31
        if (!$this->checkGrantType($tokenRequestAttempt)) {
32
33
            return new FailedTokenRequestAttemptResult(GrantDecision::denied(GrantError::invalidGrant('Unknown grant type')));
34
        }
35
36
        if ($this->checkIfAClientIsAlwaysRequired()) {
37
38
            if (!$this->checkIfAClientIsProvided($tokenRequestAttempt)) {
39
40
                return new FailedTokenRequestAttemptResult(GrantDecision::denied(GrantError::invalidGrant('Missing client_id')));
41
            }
42
43
            if (!$this->checkIfTheProvidedClientIsValid($tokenRequestAttempt)) {
44
45
                return new FailedTokenRequestAttemptResult(GrantDecision::denied(GrantError::accessDenied('Invalid client credentials')));
46
            }
47
48
            if (!$this->checkIfClientSupportsRequestedGrantType($tokenRequestAttempt)) {
49
50
                return new FailedTokenRequestAttemptResult(
51
                    GrantDecision::denied(
52
                        GrantError::invalidGrant(
53
                            sprintf(
54
                                'This client doesn\'t support the following grant type: "%s"',
55
                                $tokenRequestAttempt->getGrantType()
56
                            )
57
                        )
58
                    )
59
                );
60
            }
61
        }
62
63
        $grantDecision = $this->getGrantTypeByIdentifier($tokenRequestAttempt->getGrantType())
64
            ->grant($tokenRequestAttempt)
65
        ;
66
67
        if ($grantDecision->equals(GrantDecision::allowed())) {
68
69
            $accessToken = $this->buildAccessToken($tokenRequestAttempt, $grantDecision);
70
            $refreshToken = $this->buildRefreshToken($accessToken);
71
72
            return new SuccessfulTokenRequestAttemptResult($grantDecision, $accessToken, $refreshToken);
73
        }
74
75
        return new FailedTokenRequestAttemptResult($grantDecision);
76
    }
77
78
    private function checkGrantType(TokenRequestAttempt $tokenRequestAttempt)
79
    {
80
        return (null !== $this->getGrantTypeByIdentifier($tokenRequestAttempt->getGrantType()));
81
    }
82
83
    private function checkIfAClientIsAlwaysRequired()
84
    {
85
86
        return $this->configuration->alwaysRequireAClient();
87
    }
88
89
    private function checkIfAClientIsProvided(TokenRequestAttempt $tokenRequestAttempt)
90
    {
91
        return (false === $tokenRequestAttempt->getInputData()->getClientId());
92
    }
93
94
    private function checkIfTheProvidedClientIsValid(TokenRequestAttempt $tokenRequestAttempt)
95
    {
96
        return $this->clientAuthenticator->isClientValid(
97
            $tokenRequestAttempt->getInputData()->getClientId(),
98
            $tokenRequestAttempt->getInputData()->getClientSecret()
99
        );
100
    }
101
102
    private function checkIfClientSupportsRequestedGrantType(TokenRequestAttempt $tokenRequestAttempt)
103
    {
104
        $client = $this->configuration->getClientStorage()
105
            ->findById($tokenRequestAttempt->getInputData()->getClientId())
106
        ;
107
108
        return in_array($tokenRequestAttempt->getGrantType(), $client->getAllowedGrantTypes());
109
    }
110
111
    private function buildAccessToken(TokenRequestAttempt $tokenRequestAttempt, GrantDecision $grantDecision)
112
    {
113
        if ($grantDecision->isDenied()) {
114
115
            throw new \LogicException('Unable to build an access token with a denied decision');
116
        }
117
118
        $token = $this->configuration->getTokenGenerator()->generate(
119
            ['length' => $this->configuration->getAccessTokenLength()]
120
        )
121
        ;
122
123
        $expiresAt = new \DateTime('now', new \DateTimeZone('UTC'));
124
        $expiresAt->add(
125
            \DateInterval::createFromDateString(
126
                sprintf(
127
                    "%d seconds",
128
                    $this->configuration->getAccessTokenTTL()
129
                )
130
            )
131
        );
132
133
        $accessToken = new AccessToken(
134
            $token,
135
            \DateTimeImmutable::createFromMutable($expiresAt),
136
            $tokenRequestAttempt->getInputData()->getClientId(),
137
            $grantDecision->getResourceOwner(),
138
            []
139
        );
140
141
        $this->configuration->getAccessTokenStorage()->save($accessToken);
142
143
        return $accessToken;
144
    }
145
146
    private function buildRefreshToken(AccessToken $accessToken)
147
    {
148
        $refreshToken = null;
149
        if ($this->configuration->alwaysGenerateARefreshToken()) {
150
            $token = $this->configuration->getTokenGenerator()->generate(
151
                ['length' => $this->configuration->getAccessTokenLength()]
152
            )
153
            ;
154
            $expiresAt = new \DateTime('now', new \DateTimeZone('UTC'));
155
            $expiresAt->add(
156
                \DateInterval::createFromDateString(
157
                    sprintf(
158
                        "%d seconds",
159
                        $this->configuration->getRefreshTokenTTL()
160
                    )
161
                )
162
            );
163
164
            $refreshToken = new RefreshToken(
165
                $token,
166
                $accessToken,
167
                \DateTimeImmutable::createFromMutable($expiresAt)
168
            );
169
170
            $this->configuration->getRefreshTokenStorage()->save($refreshToken);
171
        }
172
173
        return $refreshToken;
174
    }
175
176
    /**
177
     * @param $identifier
178
     * @return GrantType
179
     */
180
    private function getGrantTypeByIdentifier($identifier)
181
    {
182
        foreach ($this->configuration->getGrantTypeExtensions() as $grantTypeExtension) {
183
            if (strtolower($identifier) === strtolower($grantTypeExtension->getIdentifier())) {
184
185
                return $grantTypeExtension;
186
            }
187
        }
188
189
        return null;
190
    }
191
}
192