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 | declare(strict_types = 1); |
||
3 | |||
4 | /** |
||
5 | * Micro |
||
6 | * |
||
7 | * @author Raffael Sahli <[email protected]> |
||
8 | * @copyright Copyright (c) 2017 gyselroth GmbH (https://gyselroth.com) |
||
9 | * @license MIT https://opensource.org/licenses/MIT |
||
10 | */ |
||
11 | |||
12 | namespace Micro\Auth\Adapter; |
||
13 | |||
14 | use \Psr\Log\LoggerInterface; |
||
15 | use \Micro\Auth\Exception; |
||
16 | |||
17 | class Oidc extends AbstractAdapter |
||
18 | { |
||
19 | /** |
||
20 | * OpenID-connect discovery path |
||
21 | */ |
||
22 | CONST DISCOVERY_PATH = '/.well-known/openid-configuration'; |
||
23 | |||
24 | |||
25 | /** |
||
26 | * OpenID-connect provider url |
||
27 | * |
||
28 | * @var string |
||
29 | */ |
||
30 | protected $provider_url = 'https://oidc.example.org'; |
||
31 | |||
32 | |||
33 | /** |
||
34 | * Token validation endpoint (rfc7662) |
||
35 | * |
||
36 | * @var string |
||
37 | */ |
||
38 | protected $token_validation_url; |
||
39 | |||
40 | |||
41 | /** |
||
42 | * Identity attribute |
||
43 | * |
||
44 | * @var string |
||
45 | */ |
||
46 | protected $identity_attribute = 'preferred_username'; |
||
47 | |||
48 | |||
49 | /** |
||
50 | * Attributes |
||
51 | * |
||
52 | * @var array |
||
53 | */ |
||
54 | protected $attributes = []; |
||
55 | |||
56 | |||
57 | /** |
||
58 | * Access token |
||
59 | * |
||
60 | * @var string |
||
61 | */ |
||
62 | private $access_token; |
||
63 | |||
64 | |||
65 | /** |
||
66 | * Init adapter |
||
67 | * |
||
68 | * @param LoggerInterface $logger |
||
69 | * @param Iterable $config |
||
70 | * @return void |
||
0 ignored issues
–
show
|
|||
71 | */ |
||
72 | public function __construct(LoggerInterface $logger, ?Iterable $config=null) |
||
73 | { |
||
74 | $this->logger = $logger; |
||
75 | $this->setOptions($config); |
||
76 | } |
||
77 | |||
78 | |||
79 | /** |
||
80 | * Set options |
||
81 | * |
||
82 | * @param Iterable $config |
||
83 | * @return AdapterInterface |
||
84 | */ |
||
85 | public function setOptions(? Iterable $config = null) : AdapterInterface |
||
86 | { |
||
87 | if ($config === null) { |
||
88 | return $this; |
||
89 | } |
||
90 | |||
91 | foreach($config as $option => $value) { |
||
92 | switch($option) { |
||
93 | case 'provider_url': |
||
0 ignored issues
–
show
case statements should be defined using a colon.
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces.
There is no need for braces, since each case is terminated by the next There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages. switch ($expr) {
case "A": { //wrong
doSomething();
break;
}
case "B"; //wrong
doSomething();
break;
case "C": //right
doSomething();
break;
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
94 | case 'token_validation_url': |
||
95 | case 'identity_attribute': |
||
96 | $this->{$option} = (string)$value; |
||
97 | unset($config[$option]); |
||
98 | break; |
||
99 | } |
||
100 | } |
||
101 | |||
102 | return parent::setOptions($config); |
||
103 | } |
||
104 | |||
105 | |||
106 | /** |
||
107 | * Authenticate |
||
108 | * |
||
109 | * @return bool |
||
110 | */ |
||
111 | public function authenticate(): bool |
||
112 | { |
||
113 | if (!isset($_SERVER['HTTP_AUTHORIZATION'])) { |
||
114 | $this->logger->debug('skip auth adapter ['.get_class($this).'], no http authorization header or access_token param found', [ |
||
115 | 'category' => get_class($this) |
||
116 | ]); |
||
117 | |||
118 | return false; |
||
119 | } else { |
||
120 | $header = $_SERVER['HTTP_AUTHORIZATION']; |
||
121 | $parts = explode(' ', $header); |
||
122 | |||
123 | if ($parts[0] == 'Bearer') { |
||
124 | $this->logger->debug('found http bearer authorization header', [ |
||
125 | 'category' => get_class($this) |
||
126 | ]); |
||
127 | |||
128 | return $this->verifyToken($parts[1]); |
||
129 | } else { |
||
130 | $this->logger->debug('http authorization header contains no bearer string or invalid authentication string', [ |
||
131 | 'category' => get_class($this) |
||
132 | ]); |
||
133 | |||
134 | return false; |
||
135 | } |
||
136 | } |
||
137 | } |
||
138 | |||
139 | |||
140 | /** |
||
141 | * Get discovery url |
||
142 | * |
||
143 | * @return string |
||
144 | */ |
||
145 | public function getDiscoveryUrl(): string |
||
146 | { |
||
147 | return $this->provider_url.self::DISCOVERY_PATH; |
||
148 | } |
||
149 | |||
150 | |||
151 | /** |
||
152 | * Get discovery document |
||
153 | * |
||
154 | * @return array |
||
155 | */ |
||
156 | public function getDiscoveryDocument(): array |
||
157 | { |
||
158 | if ($apc = extension_loaded('apc') && apc_exists($this->provider_url)) { |
||
0 ignored issues
–
show
|
|||
159 | return apc_get($this->provider_url); |
||
160 | } else { |
||
161 | $ch = curl_init(); |
||
162 | $url = $this->getDiscoveryUrl(); |
||
163 | curl_setopt($ch, CURLOPT_URL, $url); |
||
164 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
||
165 | |||
166 | $this->logger->debug('fetch openid-connect discovery document from ['.$url.']', [ |
||
167 | 'category' => get_class($this) |
||
168 | ]); |
||
169 | |||
170 | $result = curl_exec($ch); |
||
171 | $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); |
||
172 | curl_close($ch); |
||
173 | |||
174 | if($code === 200) { |
||
175 | $discovery = json_decode($result, true); |
||
176 | $this->logger->debug('received openid-connect discovery document from ['.$url.']', [ |
||
177 | 'category' => get_class($this), |
||
178 | 'discovery'=> $discovery |
||
179 | ]); |
||
180 | |||
181 | if ($apc === true) { |
||
182 | apc_store($this->provider_url, $discovery); |
||
183 | } |
||
184 | |||
185 | return $discovery; |
||
186 | } else { |
||
187 | $this->logger->error('failed to receive openid-connect discovery document from ['.$url.'], request ended with status ['.$code.']', [ |
||
188 | 'category' => get_class($this), |
||
189 | ]); |
||
190 | |||
191 | throw new Exception('failed to get openid-connect discovery document'); |
||
192 | } |
||
193 | } |
||
194 | } |
||
195 | |||
196 | |||
197 | /** |
||
198 | * Token verification |
||
199 | * |
||
200 | * @param string $token |
||
201 | * @return bool |
||
202 | */ |
||
203 | protected function verifyToken(string $token): bool |
||
204 | { |
||
205 | if($this->token_validation_url) { |
||
206 | $this->logger->debug('validate oauth2 token via rfc7662 token validation endpoint ['.$this->token_validation_url.']', [ |
||
207 | 'category' => get_class($this), |
||
208 | ]); |
||
209 | |||
210 | $url = str_replace('{token}', $token, $this->token_validation_url); |
||
211 | } else { |
||
212 | $discovery = $this->getDiscoveryDocument(); |
||
213 | if (!(isset($discovery['userinfo_endpoint']))) { |
||
214 | throw new Exception('userinfo_endpoint could not be determained'); |
||
215 | } |
||
216 | |||
217 | $this->logger->debug('validate token via openid-connect userinfo_endpoint ['.$discovery['userinfo_endpoint'].']', [ |
||
218 | 'category' => get_class($this), |
||
219 | ]); |
||
220 | |||
221 | $url = $discovery['userinfo_endpoint'].'?access_token='.$token; |
||
222 | } |
||
223 | |||
224 | $ch = curl_init(); |
||
225 | curl_setopt($ch, CURLOPT_URL, $url); |
||
226 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
||
227 | $result = curl_exec($ch); |
||
228 | $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); |
||
229 | curl_close($ch); |
||
230 | $response = json_decode($result, true); |
||
0 ignored issues
–
show
$response is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
231 | |||
232 | if($code === 200) { |
||
233 | $attributes = json_decode($result, true); |
||
234 | $this->logger->debug('successfully verified oauth2 access token via authorization server', [ |
||
235 | 'category' => get_class($this), |
||
236 | ]); |
||
237 | |||
238 | if(!isset($attributes[$this->identity_attribute])) { |
||
239 | throw new Exception('identity attribute '.$this->identity_attribute.' not found in oauth2 response'); |
||
240 | } |
||
241 | |||
242 | $this->identifier = $attributes['preferred_username']; |
||
243 | |||
244 | if($this->token_validation_url) { |
||
245 | $this->attributes = $attributes; |
||
246 | } else { |
||
247 | $this->access_token = $token; |
||
248 | } |
||
249 | |||
250 | return true; |
||
251 | } else { |
||
252 | $this->logger->error('failed verify oauth2 access token via authorization server, received status ['.$code.']', [ |
||
253 | 'category' => get_class($this), |
||
254 | ]); |
||
255 | |||
256 | throw new Exception('failed verify oauth2 access token via authorization server'); |
||
257 | } |
||
258 | } |
||
259 | |||
260 | |||
261 | /** |
||
262 | * Get attributes |
||
263 | * |
||
264 | * @return array |
||
265 | */ |
||
266 | public function getAttributes(): array |
||
267 | { |
||
268 | if(count($this->attributes) !== 0) { |
||
269 | return $this->attributes; |
||
270 | } |
||
271 | |||
272 | $discovery = $this->getDiscoveryDocument(); |
||
273 | if (!(isset($discovery['authorization_endpoint']))) { |
||
274 | throw new Exception('authorization_endpoint could not be determained'); |
||
275 | } |
||
276 | |||
277 | $this->logger->debug('fetch user attributes from userinfo_endpoint ['.$discovery['userinfo_endpoint'].']', [ |
||
278 | 'category' => get_class($this), |
||
279 | ]); |
||
280 | |||
281 | $url = $discovery['userinfo_endpoint'].'?access_token='.$this->access_token; |
||
282 | $ch = curl_init(); |
||
283 | curl_setopt($ch, CURLOPT_URL, $url); |
||
284 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
||
285 | $result = curl_exec($ch); |
||
286 | $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); |
||
287 | curl_close($ch); |
||
288 | $response = json_decode($result, true); |
||
0 ignored issues
–
show
$response is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
289 | |||
290 | if($code === 200) { |
||
291 | $attributes = json_decode($result, true); |
||
292 | $this->logger->debug('successfully requested user attributes from userinfo_endpoint', [ |
||
293 | 'category' => get_class($this), |
||
294 | ]); |
||
295 | |||
296 | return $this->attributes = $attributes; |
||
297 | } else { |
||
298 | $this->logger->error('failed requesting user attributes from userinfo_endpoint, status code ['.$code.']', [ |
||
299 | 'category' => get_class($this), |
||
300 | ]); |
||
301 | |||
302 | throw new Exception('failed requesting user attribute from userinfo_endpoint'); |
||
303 | } |
||
304 | |||
305 | } |
||
306 | } |
||
307 |
Adding a
@return
annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.Please refer to the PHP core documentation on constructors.