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

AuthorizationServer::buildRefreshToken()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 29
rs 8.8571
cc 2
eloc 17
nc 2
nop 1
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