|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* Created by PhpStorm. |
|
4
|
|
|
* User: GCC-MED |
|
5
|
|
|
* Date: 12/03/2018 |
|
6
|
|
|
* Time: 15:41 |
|
7
|
|
|
*/ |
|
8
|
|
|
|
|
9
|
|
|
namespace OAuth2\AuthorizationGrantTypes\Flows; |
|
10
|
|
|
|
|
11
|
|
|
|
|
12
|
|
|
use OAuth2\Endpoints\Authorization\AuthorizationRequest; |
|
13
|
|
|
use OAuth2\Endpoints\Authorization\AuthorizationRequestInterface; |
|
14
|
|
|
use OAuth2\Endpoints\TokenEndpoint; |
|
15
|
|
|
use OAuth2\Exceptions\OAuthException; |
|
16
|
|
|
use OAuth2\AuthorizationGrantTypes\AbstractGrantType; |
|
17
|
|
|
use OAuth2\Helper; |
|
18
|
|
|
use OAuth2\Roles\ClientTypes\ConfidentialClientInterface; |
|
19
|
|
|
use OAuth2\ScopePolicy\ScopePolicyManager; |
|
20
|
|
|
use OAuth2\Storages\AccessTokenStorageInterface; |
|
21
|
|
|
use OAuth2\Storages\RefreshTokenStorageInterface; |
|
22
|
|
|
|
|
23
|
|
|
/** |
|
24
|
|
|
* Class ClientCredentialsFlow |
|
25
|
|
|
* @package OAuth2\AuthorizationGrantTypes\Flows |
|
26
|
|
|
* |
|
27
|
|
|
* @see https://tools.ietf.org/html/rfc6749#section-1.3.4 |
|
28
|
|
|
* The client credentials (or other forms of client authentication) can |
|
29
|
|
|
* be used as an authorization grant when the authorization scope is |
|
30
|
|
|
* limited to the protected resources under the control of the client, |
|
31
|
|
|
* or to protected resources previously arranged with the authorization |
|
32
|
|
|
* server. Client credentials are used as an authorization grant |
|
33
|
|
|
* typically when the client is acting on its own behalf (the client is |
|
34
|
|
|
* also the resource owner) or is requesting access to protected |
|
35
|
|
|
* resources based on an authorization previously arranged with the |
|
36
|
|
|
* authorization server. |
|
37
|
|
|
* |
|
38
|
|
|
* @see https://tools.ietf.org/html/rfc6749#section-4.4 |
|
39
|
|
|
* The client can request an access token using only its client |
|
40
|
|
|
* credentials (or other supported means of authentication) when the |
|
41
|
|
|
* client is requesting access to the protected resources under its |
|
42
|
|
|
* control, or those of another resource owner that have been previously |
|
43
|
|
|
* arranged with the authorization server (the method of which is beyond |
|
44
|
|
|
* the scope of this specification). |
|
45
|
|
|
* |
|
46
|
|
|
* The client credentials grant type MUST only be used by confidential |
|
47
|
|
|
* clients. |
|
48
|
|
|
*/ |
|
49
|
|
|
class ClientCredentialsFlow extends AbstractGrantType implements FlowInterface |
|
50
|
|
|
{ |
|
51
|
|
|
/** |
|
52
|
|
|
* @var ScopePolicyManager |
|
53
|
|
|
*/ |
|
54
|
|
|
private $scopePolicyManager; |
|
55
|
|
|
|
|
56
|
|
|
public function __construct(ScopePolicyManager $scopePolicyManager, |
|
57
|
|
|
AccessTokenStorageInterface $accessTokenStorage, |
|
58
|
|
|
RefreshTokenStorageInterface $refreshTokenStorage) |
|
59
|
|
|
{ |
|
60
|
|
|
parent::__construct($accessTokenStorage, $refreshTokenStorage); |
|
61
|
|
|
$this->scopePolicyManager = $scopePolicyManager; |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* @return array |
|
66
|
|
|
* |
|
67
|
|
|
* @see https://tools.ietf.org/html/rfc6749#section-4.4.1 |
|
68
|
|
|
* Since the client authentication is used as the authorization grant, |
|
69
|
|
|
* no additional authorization request is needed. |
|
70
|
|
|
*/ |
|
71
|
|
|
public function getResponseTypes(): array |
|
72
|
|
|
{ |
|
73
|
|
|
return []; |
|
74
|
|
|
} |
|
75
|
|
|
|
|
76
|
|
|
public function getGrantTypes(): array |
|
77
|
|
|
{ |
|
78
|
|
|
return ['client_credentials']; |
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
|
|
/** |
|
82
|
|
|
* @param TokenEndpoint $tokenEndpoint |
|
83
|
|
|
* @param array $requestData |
|
84
|
|
|
* @return array |
|
85
|
|
|
* @throws OAuthException |
|
86
|
|
|
* |
|
87
|
|
|
* @see https://tools.ietf.org/html/rfc6749#section-4.4.2 |
|
88
|
|
|
* The client makes a request to the token endpoint by adding the |
|
89
|
|
|
* following parameters using the "application/x-www-form-urlencoded" |
|
90
|
|
|
* format per Appendix B with a character encoding of UTF-8 in the HTTP |
|
91
|
|
|
* request entity-body: |
|
92
|
|
|
* |
|
93
|
|
|
* grant_type |
|
94
|
|
|
* REQUIRED. Value MUST be set to "client_credentials". |
|
95
|
|
|
* |
|
96
|
|
|
* scope |
|
97
|
|
|
* OPTIONAL. The scope of the access request as described by |
|
98
|
|
|
* Section 3.3. |
|
99
|
|
|
* |
|
100
|
|
|
* The client MUST authenticate with the authorization server as |
|
101
|
|
|
* described in Section 3.2.1. |
|
102
|
|
|
* |
|
103
|
|
|
* For example, the client makes the following HTTP request using |
|
104
|
|
|
* transport-layer security (with extra line breaks for display purposes |
|
105
|
|
|
* only): |
|
106
|
|
|
* |
|
107
|
|
|
* POST /token HTTP/1.1 |
|
108
|
|
|
* Host: server.example.com |
|
109
|
|
|
* Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW |
|
110
|
|
|
* Content-Type: application/x-www-form-urlencoded |
|
111
|
|
|
* |
|
112
|
|
|
* grant_type=client_credentials |
|
113
|
|
|
* |
|
114
|
|
|
* The authorization server MUST authenticate the client. |
|
115
|
|
|
* |
|
116
|
|
|
* @see https://tools.ietf.org/html/rfc6749#section-4.4.3 |
|
117
|
|
|
* If the access token request is valid and authorized, the |
|
118
|
|
|
* authorization server issues an access token as described in |
|
119
|
|
|
* Section 5.1. A refresh token SHOULD NOT be included. If the request |
|
120
|
|
|
* failed client authentication or is invalid, the authorization server |
|
121
|
|
|
* returns an error response as described in Section 5.2. |
|
122
|
|
|
*/ |
|
123
|
|
|
public function handleAccessTokenRequest(TokenEndpoint $tokenEndpoint, array $requestData): array |
|
124
|
|
|
{ |
|
125
|
|
|
if (!$tokenEndpoint->getClient() instanceof ConfidentialClientInterface) { |
|
126
|
|
|
throw new OAuthException('unauthorized_client', |
|
127
|
|
|
'The authenticated client is not authorized to use this authorization grant type. |
|
128
|
|
|
The client credentials grant type MUST only be used by confidential clients.', |
|
129
|
|
|
'https://tools.ietf.org/html/rfc6749#section-4.4'); |
|
130
|
|
|
} |
|
131
|
|
|
|
|
132
|
|
|
|
|
133
|
|
|
$requestedScopes = $this->scopePolicyManager->scopeStringToArray($requestData['scope'] ?? null); |
|
134
|
|
|
$scopes = $this->scopePolicyManager->getScopes($tokenEndpoint->getClient(), $requestedScopes); |
|
135
|
|
|
|
|
136
|
|
|
$responseData = $this->issueAccessToken($scopes, $tokenEndpoint->getClient()->getIdentifier(), null); |
|
137
|
|
|
|
|
138
|
|
|
/** |
|
139
|
|
|
* @see https://tools.ietf.org/html/rfc6749#section-3.3 |
|
140
|
|
|
* The authorization and token endpoints allow the client to specify the |
|
141
|
|
|
* scope of the access request using the "scope" request parameter. In |
|
142
|
|
|
* turn, the authorization server uses the "scope" response parameter to |
|
143
|
|
|
* inform the client of the scope of the access token issued. |
|
144
|
|
|
*/ |
|
145
|
|
|
if (Helper::array_equals($requestedScopes, $scopes)) { |
|
146
|
|
|
$responseData['scope'] = implode(' ', $scopes); |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
return $responseData; |
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
|
public function handleAuthorizationRequest(AuthorizationRequestInterface $authorizationRequest): array |
|
153
|
|
|
{ |
|
154
|
|
|
throw new \BadMethodCallException(); |
|
155
|
|
|
} |
|
156
|
|
|
|
|
157
|
|
|
// public function verifyAuthorizationRequest(AuthorizationEndpoint $authorizationEndpoint, array $requestData) |
|
|
|
|
|
|
158
|
|
|
// { |
|
159
|
|
|
// throw new \BadMethodCallException(); |
|
160
|
|
|
// } |
|
161
|
|
|
|
|
162
|
|
|
public function getDefaultResponseMode(): string |
|
163
|
|
|
{ |
|
164
|
|
|
throw new \BadMethodCallException(); |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
public function getUnsupportedResponseModes(): array |
|
168
|
|
|
{ |
|
169
|
|
|
throw new \BadMethodCallException(); |
|
170
|
|
|
} |
|
171
|
|
|
|
|
172
|
|
|
public function isRegistrationOfRedirectUriRequired(): bool |
|
173
|
|
|
{ |
|
174
|
|
|
throw new \BadMethodCallException(); |
|
175
|
|
|
} |
|
176
|
|
|
} |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.