This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace EntWeChat\Auth; |
||
4 | |||
5 | use EntWeChat\Core\AbstractAPI; |
||
6 | use EntWeChat\Core\AccessToken; |
||
7 | use Symfony\Component\HttpFoundation\RedirectResponse; |
||
8 | use Symfony\Component\HttpFoundation\Request; |
||
9 | |||
10 | /** |
||
11 | * Class AbstractAuthentication. |
||
12 | */ |
||
13 | abstract class AbstractAuthentication extends AbstractAPI |
||
14 | { |
||
15 | /** |
||
16 | * The HTTP request instance. |
||
17 | * |
||
18 | * @var \Symfony\Component\HttpFoundation\Request |
||
19 | */ |
||
20 | protected $request; |
||
21 | |||
22 | /** |
||
23 | * The client ID. |
||
24 | * |
||
25 | * @var string |
||
26 | */ |
||
27 | protected $clientId; |
||
28 | |||
29 | /** |
||
30 | * The client secret. |
||
31 | * |
||
32 | * @var string |
||
33 | */ |
||
34 | protected $clientSecret; |
||
35 | |||
36 | /** |
||
37 | * The redirect URL. |
||
38 | * |
||
39 | * @var string |
||
40 | */ |
||
41 | protected $redirectUrl; |
||
42 | |||
43 | /** |
||
44 | * The custom parameters to be sent with the request. |
||
45 | * |
||
46 | * @var array |
||
47 | */ |
||
48 | protected $parameters = []; |
||
49 | |||
50 | /** |
||
51 | * The scopes being requested. |
||
52 | * |
||
53 | * @var array |
||
54 | */ |
||
55 | protected $scopes = []; |
||
56 | |||
57 | /** |
||
58 | * The separating character for the requested scopes. |
||
59 | * |
||
60 | * @var string |
||
61 | */ |
||
62 | protected $scopeSeparator = ','; |
||
63 | |||
64 | /** |
||
65 | * The type of the encoding in the query. |
||
66 | * |
||
67 | * @var int Can be either PHP_QUERY_RFC3986 or PHP_QUERY_RFC1738 |
||
68 | */ |
||
69 | protected $encodingType = PHP_QUERY_RFC1738; |
||
70 | |||
71 | /** |
||
72 | * Indicates if the session state should be utilized. |
||
73 | * |
||
74 | * @var bool |
||
75 | */ |
||
76 | protected $stateless = false; |
||
77 | |||
78 | /** |
||
79 | * AbstractService constructor. |
||
80 | * |
||
81 | * @param AccessToken $accessToken |
||
82 | */ |
||
83 | public function __construct(AccessToken $accessToken) |
||
84 | { |
||
85 | parent::__construct($accessToken); |
||
86 | |||
87 | $this->clientId = $this->getAccessToken()->getCorpId(); |
||
88 | $this->clientSecret = $this->getAccessToken()->getSecret(); |
||
89 | $this->request = Request::createFromGlobals(); |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * Get the authentication URL. |
||
94 | * |
||
95 | * @param string $state |
||
96 | * |
||
97 | * @return string |
||
98 | */ |
||
99 | abstract protected function getAuthUrl($state); |
||
100 | |||
101 | /** |
||
102 | * Redirect the user of the application to the provider's authentication screen. |
||
103 | * |
||
104 | * @param string $redirectUrl |
||
105 | * |
||
106 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
||
107 | */ |
||
108 | public function redirect($redirectUrl = null) |
||
109 | { |
||
110 | $state = null; |
||
111 | |||
112 | if (!is_null($redirectUrl)) { |
||
113 | $this->redirectUrl = $redirectUrl; |
||
114 | } |
||
115 | |||
116 | if ($this->usesState()) { |
||
117 | $state = $this->makeState(); |
||
118 | } |
||
119 | |||
120 | return new RedirectResponse($this->getAuthUrl($state)); |
||
0 ignored issues
–
show
|
|||
121 | } |
||
122 | |||
123 | /** |
||
124 | * Set redirect url. |
||
125 | * |
||
126 | * @param string $redirectUrl |
||
127 | * |
||
128 | * @return $this |
||
129 | */ |
||
130 | public function setRedirectUrl($redirectUrl) |
||
131 | { |
||
132 | $this->redirectUrl = $redirectUrl; |
||
133 | |||
134 | return $this; |
||
135 | } |
||
136 | |||
137 | /** |
||
138 | * Set redirect url. |
||
139 | * |
||
140 | * @param string $redirectUrl |
||
141 | * |
||
142 | * @return $this |
||
143 | */ |
||
144 | public function withRedirectUrl($redirectUrl) |
||
145 | { |
||
146 | $this->redirectUrl = $redirectUrl; |
||
147 | |||
148 | return $this; |
||
149 | } |
||
150 | |||
151 | /** |
||
152 | * Return the redirect url. |
||
153 | * |
||
154 | * @return string |
||
155 | */ |
||
156 | public function getRedirectUrl() |
||
157 | { |
||
158 | return $this->redirectUrl; |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * Set the scopes of the requested access. |
||
163 | * |
||
164 | * @param array $scopes |
||
165 | * |
||
166 | * @return $this |
||
167 | */ |
||
168 | public function scopes(array $scopes) |
||
169 | { |
||
170 | $this->scopes = $scopes; |
||
171 | |||
172 | return $this; |
||
173 | } |
||
174 | |||
175 | /** |
||
176 | * Set the request instance. |
||
177 | * |
||
178 | * @param Request $request |
||
179 | * |
||
180 | * @return $this |
||
181 | */ |
||
182 | public function setRequest(Request $request) |
||
0 ignored issues
–
show
You have injected the Request via parameter
$request . This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest() .
![]() |
|||
183 | { |
||
184 | $this->request = $request; |
||
185 | |||
186 | return $this; |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * Get the request instance. |
||
191 | * |
||
192 | * @return Request |
||
193 | */ |
||
194 | public function getRequest() |
||
195 | { |
||
196 | return $this->request; |
||
197 | } |
||
198 | |||
199 | /** |
||
200 | * Indicates that the provider should operate as stateless. |
||
201 | * |
||
202 | * @return $this |
||
203 | */ |
||
204 | public function stateless() |
||
205 | { |
||
206 | $this->stateless = true; |
||
207 | |||
208 | return $this; |
||
209 | } |
||
210 | |||
211 | /** |
||
212 | * Set the custom parameters of the request. |
||
213 | * |
||
214 | * @param array $parameters |
||
215 | * |
||
216 | * @return $this |
||
217 | */ |
||
218 | public function with(array $parameters) |
||
219 | { |
||
220 | $this->parameters = $parameters; |
||
221 | |||
222 | return $this; |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * Get the authentication URL for the provider. |
||
227 | * |
||
228 | * @param string $url |
||
229 | * @param string $state |
||
230 | * |
||
231 | * @return string |
||
232 | */ |
||
233 | protected function buildAuthUrlFromBase($url, $state) |
||
234 | { |
||
235 | return $url.'?'.http_build_query($this->getCodeFields($state), '', '&', $this->encodingType); |
||
236 | } |
||
237 | |||
238 | /** |
||
239 | * Get the GET parameters for the code request. |
||
240 | * |
||
241 | * @param string|null $state |
||
242 | * |
||
243 | * @return array |
||
244 | */ |
||
245 | protected function getCodeFields($state = null) |
||
246 | { |
||
247 | $fields = array_merge([ |
||
248 | 'client_id' => $this->clientId, |
||
249 | 'redirect_uri' => $this->redirectUrl, |
||
250 | 'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator), |
||
251 | 'response_type' => 'code', |
||
252 | ], $this->parameters); |
||
253 | |||
254 | if ($this->usesState()) { |
||
255 | $fields['state'] = $state; |
||
256 | } |
||
257 | |||
258 | return $fields; |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Format the given scopes. |
||
263 | * |
||
264 | * @param array $scopes |
||
265 | * @param string $scopeSeparator |
||
266 | * |
||
267 | * @return string |
||
268 | */ |
||
269 | protected function formatScopes(array $scopes, $scopeSeparator) |
||
270 | { |
||
271 | return implode($scopeSeparator, $scopes); |
||
272 | } |
||
273 | |||
274 | /** |
||
275 | * Determine if the current request / session has a mismatching "state". |
||
276 | * |
||
277 | * @return bool |
||
278 | */ |
||
279 | protected function hasInvalidState() |
||
280 | { |
||
281 | if ($this->isStateless()) { |
||
282 | return false; |
||
283 | } |
||
284 | |||
285 | $state = $this->request->getSession()->get('state'); |
||
286 | |||
287 | return !(strlen($state) > 0 && $this->request->get('state') === $state); |
||
288 | } |
||
289 | |||
290 | /** |
||
291 | * Get the POST fields for the token request. |
||
292 | * |
||
293 | * @param string $code |
||
294 | * |
||
295 | * @return array |
||
296 | */ |
||
297 | protected function getTokenFields($code) |
||
298 | { |
||
299 | return [ |
||
300 | 'client_id' => $this->clientId, |
||
301 | 'client_secret' => $this->clientSecret, |
||
302 | 'code' => $code, |
||
303 | 'redirect_uri' => $this->redirectUrl, |
||
304 | ]; |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * Get the code from the request. |
||
309 | * |
||
310 | * @return string |
||
311 | */ |
||
312 | protected function getCode() |
||
313 | { |
||
314 | return $this->request->get('code'); |
||
315 | } |
||
316 | |||
317 | /** |
||
318 | * Determine if the provider is operating with state. |
||
319 | * |
||
320 | * @return bool |
||
321 | */ |
||
322 | protected function usesState() |
||
323 | { |
||
324 | return !$this->stateless; |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * Determine if the provider is operating as stateless. |
||
329 | * |
||
330 | * @return bool |
||
331 | */ |
||
332 | protected function isStateless() |
||
333 | { |
||
334 | return $this->stateless; |
||
335 | } |
||
336 | |||
337 | /** |
||
338 | * Return array item by key. |
||
339 | * |
||
340 | * @param array $array |
||
341 | * @param string $key |
||
342 | * @param mixed $default |
||
343 | * |
||
344 | * @return mixed |
||
345 | */ |
||
346 | View Code Duplication | protected function arrayItem(array $array, $key, $default = null) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
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. ![]() |
|||
347 | { |
||
348 | if (is_null($key)) { |
||
349 | return $array; |
||
350 | } |
||
351 | |||
352 | if (isset($array[$key])) { |
||
353 | return $array[$key]; |
||
354 | } |
||
355 | |||
356 | foreach (explode('.', $key) as $segment) { |
||
357 | if (!is_array($array) || !array_key_exists($segment, $array)) { |
||
358 | return $default; |
||
359 | } |
||
360 | |||
361 | $array = $array[$segment]; |
||
362 | } |
||
363 | |||
364 | return $array; |
||
365 | } |
||
366 | |||
367 | /** |
||
368 | * Put state to session storage and return it. |
||
369 | * |
||
370 | * @return string|bool |
||
371 | */ |
||
372 | protected function makeState() |
||
373 | { |
||
374 | $state = sha1(uniqid(mt_rand(1, 1000000), true)); |
||
375 | $session = $this->request->getSession(); |
||
376 | |||
377 | if (is_callable([$session, 'put'])) { |
||
378 | $session->put('state', $state); |
||
0 ignored issues
–
show
The method
put() does not seem to exist on object<Symfony\Component...ssion\SessionInterface> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
379 | } elseif (is_callable([$session, 'set'])) { |
||
380 | $session->set('state', $state); |
||
381 | } else { |
||
382 | return false; |
||
383 | } |
||
384 | |||
385 | return $state; |
||
386 | } |
||
387 | } |
||
388 |
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.