1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Official OAuth2 Client Provider for Preview Technologies |
4
|
|
|
* |
5
|
|
|
* @author Shaharia Azam <[email protected]> |
6
|
|
|
* @url https://www.previewtechs.com |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace Previewtechs\Oauth2\Client; |
10
|
|
|
|
11
|
|
|
use InvalidArgumentException; |
12
|
|
|
use League\OAuth2\Client\Provider\AbstractProvider; |
13
|
|
|
use League\OAuth2\Client\Provider\Exception\IdentityProviderException; |
14
|
|
|
use League\OAuth2\Client\Token\AccessToken; |
15
|
|
|
use League\OAuth2\Client\Tool\BearerAuthorizationTrait; |
16
|
|
|
use Psr\Http\Message\ResponseInterface; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Class Provider |
20
|
|
|
* @package Previewtechs\Oauth2\Client |
21
|
|
|
*/ |
22
|
|
|
class Provider extends AbstractProvider |
23
|
|
|
{ |
24
|
|
|
use BearerAuthorizationTrait; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* @var string |
28
|
|
|
*/ |
29
|
|
|
private $urlAuthorize = "https://myaccount.previewtechs.com/oauth/authorize"; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @var string |
33
|
|
|
*/ |
34
|
|
|
private $urlAccessToken = "https://myaccount.previewtechs.com/oauth/access_token"; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @var string |
38
|
|
|
*/ |
39
|
|
|
private $urlResourceOwnerDetails = "https://user-info.previewtechsapis.com/v1/me"; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @var string |
43
|
|
|
*/ |
44
|
|
|
private $accessTokenMethod = "POST"; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @var string |
48
|
|
|
*/ |
49
|
|
|
private $accessTokenResourceOwnerId; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @var array|null |
53
|
|
|
*/ |
54
|
|
|
public $scopes = []; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* @var array |
58
|
|
|
*/ |
59
|
|
|
private $defaultScopes = ['basic', 'email']; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* @var string |
63
|
|
|
*/ |
64
|
|
|
private $scopeSeparator = ' '; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @var string |
68
|
|
|
*/ |
69
|
|
|
private $responseError = 'error'; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* @var string |
73
|
|
|
*/ |
74
|
|
|
private $responseCode; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* @var string |
78
|
|
|
*/ |
79
|
|
|
private $responseResourceOwnerId = 'id'; |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* @param array $options |
83
|
|
|
* @param array $collaborators |
84
|
|
|
*/ |
85
|
|
|
public function __construct(array $options = [], array $collaborators = []) |
86
|
|
|
{ |
87
|
|
|
$this->assertRequiredOptions($options); |
88
|
|
|
|
89
|
|
|
$possible = $this->getConfigurableOptions(); |
90
|
|
|
$configured = array_intersect_key($options, array_flip($possible)); |
91
|
|
|
|
92
|
|
|
foreach ($configured as $key => $value) { |
93
|
|
|
$this->$key = $value; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
// Remove all options that are only used locally |
97
|
|
|
$options = array_diff_key($options, $configured); |
98
|
|
|
|
99
|
|
|
parent::__construct($options, $collaborators); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Returns all options that can be configured. |
104
|
|
|
* |
105
|
|
|
* @return array |
106
|
|
|
*/ |
107
|
|
|
protected function getConfigurableOptions() |
108
|
|
|
{ |
109
|
|
|
return array_merge($this->getRequiredOptions(), [ |
110
|
|
|
'accessTokenMethod', |
111
|
|
|
'accessTokenResourceOwnerId', |
112
|
|
|
'scopeSeparator', |
113
|
|
|
'responseError', |
114
|
|
|
'responseCode', |
115
|
|
|
'responseResourceOwnerId', |
116
|
|
|
'scopes', |
117
|
|
|
]); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* Returns all options that are required. |
122
|
|
|
* |
123
|
|
|
* @return array |
124
|
|
|
*/ |
125
|
|
|
protected function getRequiredOptions() |
126
|
|
|
{ |
127
|
|
|
return [ |
128
|
|
|
'clientId', |
129
|
|
|
'clientSecret' |
130
|
|
|
]; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Verifies that all required options have been passed. |
135
|
|
|
* |
136
|
|
|
* @param array $options |
137
|
|
|
* @return void |
138
|
|
|
* @throws InvalidArgumentException |
139
|
|
|
*/ |
140
|
|
|
private function assertRequiredOptions(array $options) |
141
|
|
|
{ |
142
|
|
|
$missing = array_diff_key(array_flip($this->getRequiredOptions()), $options); |
143
|
|
|
|
144
|
|
|
if (!empty($missing)) { |
145
|
|
|
throw new InvalidArgumentException( |
146
|
|
|
'Required options not defined: ' . implode(', ', array_keys($missing)) |
147
|
|
|
); |
148
|
|
|
} |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* @return string |
153
|
|
|
*/ |
154
|
|
|
public function getBaseAuthorizationUrl() |
155
|
|
|
{ |
156
|
|
|
return $this->urlAuthorize; |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* @param array $params |
161
|
|
|
* @return string |
162
|
|
|
*/ |
163
|
|
|
public function getBaseAccessTokenUrl(array $params) |
164
|
|
|
{ |
165
|
|
|
return $this->urlAccessToken; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* @param AccessToken $token |
170
|
|
|
* @return string |
171
|
|
|
*/ |
172
|
|
|
public function getResourceOwnerDetailsUrl(AccessToken $token) |
173
|
|
|
{ |
174
|
|
|
return $this->urlResourceOwnerDetails; |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* @return array |
179
|
|
|
*/ |
180
|
|
|
public function getDefaultScopes() |
181
|
|
|
{ |
182
|
|
|
return array_merge($this->defaultScopes, $this->scopes); |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* @return string |
187
|
|
|
*/ |
188
|
|
|
protected function getAccessTokenMethod() |
189
|
|
|
{ |
190
|
|
|
return $this->accessTokenMethod; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* @return null|string |
195
|
|
|
*/ |
196
|
|
|
protected function getAccessTokenResourceOwnerId() |
197
|
|
|
{ |
198
|
|
|
return $this->accessTokenResourceOwnerId ?: parent::getAccessTokenResourceOwnerId(); |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* @return string |
203
|
|
|
*/ |
204
|
|
|
protected function getScopeSeparator() |
205
|
|
|
{ |
206
|
|
|
return $this->scopeSeparator; |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* @param ResponseInterface $response |
211
|
|
|
* @param array|string $data |
212
|
|
|
* @throws IdentityProviderException |
213
|
|
|
*/ |
214
|
|
|
protected function checkResponse(ResponseInterface $response, $data) |
215
|
|
|
{ |
216
|
|
|
if (!empty($data[$this->responseError])) { |
217
|
|
|
$error = $data[$this->responseError]; |
218
|
|
|
$code = $this->responseCode ? $data[$this->responseCode] : 0; |
219
|
|
|
throw new IdentityProviderException($error, $code, $data); |
220
|
|
|
} |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* @param array $response |
225
|
|
|
* @param AccessToken $token |
226
|
|
|
* @return ResourceOwner |
227
|
|
|
*/ |
228
|
|
|
protected function createResourceOwner(array $response, AccessToken $token) |
229
|
|
|
{ |
230
|
|
|
return new ResourceOwner($response, $this->responseResourceOwnerId); |
|
|
|
|
231
|
|
|
} |
232
|
|
|
} |
233
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.