1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* OAuth 2.0 Password grant |
4
|
|
|
* |
5
|
|
|
* @package league/oauth2-server |
6
|
|
|
* @author Alex Bilbie <[email protected]> |
7
|
|
|
* @copyright Copyright (c) Alex Bilbie |
8
|
|
|
* @license http://mit-license.org/ |
9
|
|
|
* @link https://github.com/thephpleague/oauth2-server |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace LucaDegasperi\OAuth2Server\Grant; |
13
|
|
|
|
14
|
|
|
use League\OAuth2\Server\Entity\AccessTokenEntity; |
15
|
|
|
use League\OAuth2\Server\Entity\ClientEntity; |
16
|
|
|
use League\OAuth2\Server\Entity\RefreshTokenEntity; |
17
|
|
|
use League\OAuth2\Server\Entity\SessionEntity; |
18
|
|
|
use League\OAuth2\Server\Event; |
19
|
|
|
use League\OAuth2\Server\Exception; |
20
|
|
|
use League\OAuth2\Server\Util\SecureKey; |
21
|
|
|
use League\OAuth2\Server\ResourceServer; |
22
|
|
|
use League\OAuth2\Server\Grant\AbstractGrant; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* Password grant class |
26
|
|
|
*/ |
27
|
|
|
class TokenGrant extends AbstractGrant |
28
|
|
|
{ |
29
|
|
|
/** |
30
|
|
|
* The access token |
31
|
|
|
* |
32
|
|
|
* @var \League\OAuth2\Server\Entity\AccessTokenEntity |
33
|
|
|
*/ |
34
|
|
|
protected $accessToken; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* The resource server (aka the checker). |
38
|
|
|
* |
39
|
|
|
* @var \League\OAuth2\Server\ResourceServer |
40
|
|
|
*/ |
41
|
|
|
protected $checker; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Grant identifier |
45
|
|
|
* |
46
|
|
|
* @var string |
47
|
|
|
*/ |
48
|
|
|
protected $identifier = 'password'; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Response type |
52
|
|
|
* |
53
|
|
|
* @var string |
54
|
|
|
*/ |
55
|
|
|
protected $responseType; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Callback to authenticate a user's name and password |
59
|
|
|
* |
60
|
|
|
* @var callable |
61
|
|
|
*/ |
62
|
|
|
protected $callback; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Access token expires in override |
66
|
|
|
* |
67
|
|
|
* @var int |
68
|
|
|
*/ |
69
|
|
|
protected $accessTokenTTL; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Set the callback to verify a user's username and password |
73
|
|
|
* |
74
|
|
|
* @param callable $callback The callback function |
75
|
|
|
* |
76
|
|
|
* @return void |
77
|
|
|
*/ |
78
|
|
|
public function setVerifyCredentialsCallback(callable $callback) |
79
|
|
|
{ |
80
|
|
|
$this->callback = $callback; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Return the callback function |
85
|
|
|
* |
86
|
|
|
* @return callable |
87
|
|
|
* |
88
|
|
|
* @throws |
89
|
|
|
*/ |
90
|
|
View Code Duplication |
protected function getVerifyCredentialsCallback() |
|
|
|
|
91
|
|
|
{ |
92
|
|
|
if (is_null($this->callback) || !is_callable($this->callback)) { |
93
|
|
|
throw new Exception\ServerErrorException('Null or non-callable callback set on Password grant'); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
return $this->callback; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* Complete the password grant |
101
|
|
|
* |
102
|
|
|
* @return array |
103
|
|
|
* |
104
|
|
|
* @throws |
105
|
|
|
*/ |
106
|
|
|
public function completeFlow() |
107
|
|
|
{ |
108
|
|
|
// Get the required params |
109
|
|
|
$clientId = $this->server->getRequest()->request->get('client_id', $this->server->getRequest()->getUser()); |
110
|
|
|
if (is_null($clientId)) { |
111
|
|
|
throw new Exception\InvalidRequestException('client_id'); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
$clientSecret = $this->server->getRequest()->request->get('client_secret', |
115
|
|
|
$this->server->getRequest()->getPassword()); |
116
|
|
|
if (is_null($clientSecret)) { |
117
|
|
|
throw new Exception\InvalidRequestException('client_secret'); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
// Validate client ID and client secret |
121
|
|
|
$client = $this->server->getClientStorage()->get( |
122
|
|
|
$clientId, |
123
|
|
|
$clientSecret, |
124
|
|
|
null, |
125
|
|
|
$this->getIdentifier() |
126
|
|
|
); |
127
|
|
|
|
128
|
|
View Code Duplication |
if (($client instanceof ClientEntity) === false) { |
|
|
|
|
129
|
|
|
$this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($this->server->getRequest())); |
|
|
|
|
130
|
|
|
throw new Exception\InvalidClientException(); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
$access_token = $this->server->getRequest()->headers->get('authorization',null); |
134
|
|
|
if ($access_token === null) { |
135
|
|
|
throw new Exception\AccessDeniedException(); |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
$bearerToken = str_replace( 'Bearer ','',$access_token ); |
139
|
|
|
|
140
|
|
|
// Set the access token |
141
|
|
|
$this->accessToken = $this->server->getAccessTokenStorage()->get($bearerToken); |
142
|
|
|
|
143
|
|
|
// Ensure the access token exists |
144
|
|
|
if (!$this->accessToken instanceof AccessTokenEntity) { |
145
|
|
|
throw new Exception\AccessDeniedException(); |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
// Check the access token hasn't expired |
149
|
|
|
// Ensure the auth code hasn't expired |
150
|
|
|
if ($this->accessToken->isExpired() === true) { |
151
|
|
|
throw new Exception\AccessDeniedException(); |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
// Get the scopes for the original session |
155
|
|
|
$session = $this->accessToken->getSession(); |
156
|
|
|
$scopes = $this->formatScopes($session->getScopes()); |
|
|
|
|
157
|
|
|
|
158
|
|
|
// Get and validate any requested scopes |
159
|
|
|
$requestedScopesString = $this->server->getRequest()->request->get('scope', ''); |
160
|
|
|
$requestedScopes = $this->validateScopes($requestedScopesString, $client); |
|
|
|
|
161
|
|
|
|
162
|
|
|
// Generate a new access token and assign it the correct sessions |
163
|
|
|
$newAccessToken = new AccessTokenEntity($this->server); |
164
|
|
|
$newAccessToken->setId(SecureKey::generate()); |
165
|
|
|
$newAccessToken->setExpireTime($this->getAccessTokenTTL() + time()); |
166
|
|
|
$newAccessToken->setSession($session); |
167
|
|
|
|
168
|
|
|
foreach ($scopes as $newScope) { |
169
|
|
|
$newAccessToken->associateScope($newScope); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
$newAccessToken->save(); |
173
|
|
|
|
174
|
|
|
$this->server->getTokenType()->setSession($session); |
175
|
|
|
$this->server->getTokenType()->setParam('access_token', $newAccessToken->getId()); |
176
|
|
|
$this->server->getTokenType()->setParam('expires_in', $this->getAccessTokenTTL()); |
177
|
|
|
|
178
|
|
|
return $this->server->getTokenType()->generateResponse(); |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.