|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/* |
|
4
|
|
|
* ***************************************************************************** |
|
5
|
|
|
* Contributions to this work were made on behalf of the GÉANT project, a |
|
6
|
|
|
* project that has received funding from the European Union’s Framework |
|
7
|
|
|
* Programme 7 under Grant Agreements No. 238875 (GN3) and No. 605243 (GN3plus), |
|
8
|
|
|
* Horizon 2020 research and innovation programme under Grant Agreements No. |
|
9
|
|
|
* 691567 (GN4-1) and No. 731122 (GN4-2). |
|
10
|
|
|
* On behalf of the aforementioned projects, GEANT Association is the sole owner |
|
11
|
|
|
* of the copyright in all material which was developed by a member of the GÉANT |
|
12
|
|
|
* project. GÉANT Vereniging (Association) is registered with the Chamber of |
|
13
|
|
|
* Commerce in Amsterdam with registration number 40535155 and operates in the |
|
14
|
|
|
* UK as a branch of GÉANT Vereniging. |
|
15
|
|
|
* |
|
16
|
|
|
* Registered office: Hoekenrode 3, 1102BR Amsterdam, The Netherlands. |
|
17
|
|
|
* UK branch address: City House, 126-130 Hills Road, Cambridge CB2 1PQ, UK |
|
18
|
|
|
* |
|
19
|
|
|
* License: see the web/copyright.inc.php file in the file structure or |
|
20
|
|
|
* <base_url>/copyright.php after deploying the software |
|
21
|
|
|
*/ |
|
22
|
|
|
|
|
23
|
|
|
/** |
|
24
|
|
|
* This is the collection of methods dedicated for the user GUI |
|
25
|
|
|
* @author Tomasz Wolniewicz <[email protected]> |
|
26
|
|
|
* @author Stefan Winter <[email protected]> |
|
27
|
|
|
* @package UserAPI |
|
28
|
|
|
* |
|
29
|
|
|
* Parts of this code are based on simpleSAMLPhp discojuice module. |
|
30
|
|
|
* This product includes GeoLite data created by MaxMind, available from |
|
31
|
|
|
* http://www.maxmind.com |
|
32
|
|
|
*/ |
|
33
|
|
|
|
|
34
|
|
|
namespace core; |
|
35
|
|
|
|
|
36
|
|
|
use \Exception; |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* The basic methoods for the user GUI |
|
40
|
|
|
* @package UserAPI |
|
41
|
|
|
* |
|
42
|
|
|
*/ |
|
43
|
|
|
class UserAPI extends CAT |
|
44
|
|
|
{ |
|
45
|
|
|
|
|
46
|
|
|
/** |
|
47
|
|
|
* nothing special to be done here. |
|
48
|
|
|
*/ |
|
49
|
|
|
public function __construct() |
|
50
|
|
|
{ |
|
51
|
|
|
parent::__construct(); |
|
52
|
|
|
} |
|
53
|
|
|
|
|
54
|
|
|
/** |
|
55
|
|
|
* Prepare the device module environment and send back the link |
|
56
|
|
|
* This method creates a device module instance via the {@link DeviceFactory} call, |
|
57
|
|
|
* then sets up the device module environment for the specific profile by calling |
|
58
|
|
|
* {@link DeviceConfig::setup()} method and finally, called the devide writeInstaller meethod |
|
59
|
|
|
* passing the returned path name. |
|
60
|
|
|
* |
|
61
|
|
|
* @param string $device identifier as in {@link devices.php} |
|
62
|
|
|
* @param int $profileId profile identifier |
|
63
|
|
|
* @param string $generatedFor which download area does this pertain to |
|
64
|
|
|
* @param string $token for silverbullet: invitation token to consume |
|
65
|
|
|
* @param string $password for silverbull: import PIN for the future certificate |
|
66
|
|
|
* |
|
67
|
|
|
* @return array|NULL array with the following fields: |
|
68
|
|
|
* profile - the profile identifier; |
|
69
|
|
|
* device - the device identifier; |
|
70
|
|
|
* link - the path name of the resulting installer |
|
71
|
|
|
* mime - the mimetype of the installer |
|
72
|
|
|
*/ |
|
73
|
|
|
public function generateInstaller($device, $profileId, $generatedFor = "user", $token = NULL, $password = NULL) |
|
74
|
|
|
{ |
|
75
|
|
|
$this->loggerInstance->debug(4, "installer:$device:$profileId\n"); |
|
76
|
|
|
$validator = new \web\lib\common\InputValidation(); |
|
77
|
|
|
$profile = $validator->existingProfile($profileId); |
|
78
|
|
|
// test if the profile is production-ready and if not if the authenticated user is an owner |
|
79
|
|
|
if ($this->verifyDownloadAccess($profile) === FALSE) { |
|
80
|
|
|
return; |
|
81
|
|
|
} |
|
82
|
|
|
$installerProperties = []; |
|
83
|
|
|
$installerProperties['profile'] = $profileId; |
|
84
|
|
|
$installerProperties['device'] = $device; |
|
85
|
|
|
$cache = $this->getCache($device, $profile); |
|
86
|
|
|
$this->installerPath = $cache['path']; |
|
87
|
|
|
if ($this->installerPath !== NULL && $token === NULL && $password === NULL) { |
|
88
|
|
|
$this->loggerInstance->debug(4, "Using cached installer for: $device\n"); |
|
89
|
|
|
$installerProperties['link'] = "API.php?action=downloadInstaller&lang=" . $this->languageInstance->getLang() . "&profile=$profileId&device=$device&generatedfor=$generatedFor"; |
|
90
|
|
|
$installerProperties['mime'] = $cache['mime']; |
|
91
|
|
|
} else { |
|
92
|
|
|
$myInstaller = $this->generateNewInstaller($device, $profile, $generatedFor, $token, $password); |
|
93
|
|
|
if ($myInstaller['link'] !== 0) { |
|
94
|
|
|
$installerProperties['mime'] = $myInstaller['mime']; |
|
95
|
|
|
} |
|
96
|
|
|
$installerProperties['link'] = $myInstaller['link']; |
|
97
|
|
|
} |
|
98
|
|
|
return $installerProperties; |
|
99
|
|
|
} |
|
100
|
|
|
|
|
101
|
|
|
/** |
|
102
|
|
|
* checks whether the requested profile data is public, XOR was requested by |
|
103
|
|
|
* its own admin. |
|
104
|
|
|
* @param \core\AbstractProfile $profile the profile in question |
|
105
|
|
|
* @return boolean |
|
106
|
|
|
*/ |
|
107
|
|
|
private function verifyDownloadAccess($profile) |
|
108
|
|
|
{ |
|
109
|
|
|
$attribs = $profile->getCollapsedAttributes(); |
|
110
|
|
|
if (\core\common\Entity::getAttributeValue($attribs, 'profile:production', 0) !== 'on') { |
|
111
|
|
|
$this->loggerInstance->debug(4, "Attempt to download a non-production ready installer for profile: $profile->identifier\n"); |
|
112
|
|
|
$auth = new \web\lib\admin\Authentication(); |
|
113
|
|
|
if (!$auth->isAuthenticated()) { |
|
114
|
|
|
$this->loggerInstance->debug(2, "User NOT authenticated, rejecting request for a non-production installer\n"); |
|
115
|
|
|
header("HTTP/1.0 403 Not Authorized"); |
|
116
|
|
|
return FALSE; |
|
117
|
|
|
} |
|
118
|
|
|
$auth->authenticate(); |
|
119
|
|
|
$userObject = new User($_SESSION['user']); |
|
120
|
|
|
if (!$userObject->isIdPOwner($profile->institution)) { |
|
121
|
|
|
$this->loggerInstance->debug(2, "User not an owner of a non-production profile - access forbidden\n"); |
|
122
|
|
|
header("HTTP/1.0 403 Not Authorized"); |
|
123
|
|
|
return FALSE; |
|
124
|
|
|
} |
|
125
|
|
|
$this->loggerInstance->debug(4, "User is the owner - allowing access\n"); |
|
126
|
|
|
} |
|
127
|
|
|
return TRUE; |
|
128
|
|
|
} |
|
129
|
|
|
|
|
130
|
|
|
/** |
|
131
|
|
|
* This function tries to find a cached copy of an installer for a given |
|
132
|
|
|
* combination of Profile and device |
|
133
|
|
|
* |
|
134
|
|
|
* @param string $device the device for which the installer is searched in cache |
|
135
|
|
|
* @param AbstractProfile $profile the profile for which the installer is searched in cache |
|
136
|
|
|
* @return array containing path to the installer and mime type of the file, the path is set to NULL if no cache can be returned |
|
137
|
|
|
*/ |
|
138
|
|
|
private function getCache($device, $profile) |
|
139
|
|
|
{ |
|
140
|
|
|
$deviceConfig = \devices\Devices::listDevices()[$device]; |
|
141
|
|
|
$noCache = (isset(\devices\Devices::$Options['no_cache']) && \devices\Devices::$Options['no_cache']) ? 1 : 0; |
|
142
|
|
|
if (isset($deviceConfig['options']['no_cache'])) { |
|
143
|
|
|
$noCache = $deviceConfig['options']['no_cache'] ? 1 : 0; |
|
144
|
|
|
} |
|
145
|
|
|
if ($noCache) { |
|
146
|
|
|
$this->loggerInstance->debug(5, "getCache: the no_cache option set for this device\n"); |
|
147
|
|
|
return ['path' => NULL, 'mime' => NULL]; |
|
148
|
|
|
} |
|
149
|
|
|
$this->loggerInstance->debug(5, "getCache: caching option set for this device\n"); |
|
150
|
|
|
$cache = $profile->testCache($device); |
|
151
|
|
|
$iPath = $cache['cache']; |
|
152
|
|
|
if ($iPath && is_file($iPath)) { |
|
153
|
|
|
return ['path' => $iPath, 'mime' => $cache['mime']]; |
|
154
|
|
|
} |
|
155
|
|
|
return ['path' => NULL, 'mime' => NULL]; |
|
156
|
|
|
} |
|
157
|
|
|
|
|
158
|
|
|
/** |
|
159
|
|
|
* Generates a new installer for the given combination of device and Profile |
|
160
|
|
|
* |
|
161
|
|
|
* @param string $device the device for which we want an installer |
|
162
|
|
|
* @param AbstractProfile $profile the profile for which we want an installer |
|
163
|
|
|
* @param string $generatedFor type of download requested (admin/user/silverbullet) |
|
164
|
|
|
* @param string $token in case of silverbullet, the token that was used to trigger the generation |
|
165
|
|
|
* @param string $password in case of silverbullet, the import PIN for the future client certificate |
|
166
|
|
|
* @return array info about the new installer (mime and link) |
|
167
|
|
|
*/ |
|
168
|
|
|
private function generateNewInstaller($device, $profile, $generatedFor, $token, $password) |
|
169
|
|
|
{ |
|
170
|
|
|
$this->loggerInstance->debug(5, "generateNewInstaller() - Enter"); |
|
171
|
|
|
$factory = new DeviceFactory($device); |
|
172
|
|
|
$this->loggerInstance->debug(5, "generateNewInstaller() - created Device"); |
|
173
|
|
|
$dev = $factory->device; |
|
174
|
|
|
$out = []; |
|
175
|
|
|
if (isset($dev)) { |
|
176
|
|
|
$dev->setup($profile, $token, $password); |
|
177
|
|
|
$this->loggerInstance->debug(5, "generateNewInstaller() - Device setup done"); |
|
178
|
|
|
$installer = $dev->writeInstaller(); |
|
179
|
|
|
$this->loggerInstance->debug(5, "generateNewInstaller() - writeInstaller complete"); |
|
180
|
|
|
$iPath = $dev->FPATH . '/tmp/' . $installer; |
|
181
|
|
|
if ($iPath && is_file($iPath)) { |
|
182
|
|
|
if (isset($dev->options['mime'])) { |
|
183
|
|
|
$out['mime'] = $dev->options['mime']; |
|
184
|
|
|
} else { |
|
185
|
|
|
$info = new \finfo(); |
|
186
|
|
|
$out['mime'] = $info->file($iPath, FILEINFO_MIME_TYPE); |
|
187
|
|
|
} |
|
188
|
|
|
$this->installerPath = $dev->FPATH . '/' . $installer; |
|
189
|
|
|
rename($iPath, $this->installerPath); |
|
190
|
|
|
$integerEap = (new \core\common\EAP($dev->selectedEap))->getIntegerRep(); |
|
191
|
|
|
$profile->updateCache($device, $this->installerPath, $out['mime'], $integerEap); |
|
192
|
|
|
if (\config\Master::DEBUG_LEVEL < 4) { |
|
193
|
|
|
\core\common\Entity::rrmdir($dev->FPATH . '/tmp'); |
|
194
|
|
|
} |
|
195
|
|
|
$this->loggerInstance->debug(4, "Generated installer: " . $this->installerPath . ": for: $device, EAP:" . $integerEap . "\n"); |
|
196
|
|
|
$out['link'] = "API.php?action=downloadInstaller&lang=" . $this->languageInstance->getLang() . "&profile=" . $profile->identifier . "&device=$device&generatedfor=$generatedFor"; |
|
197
|
|
|
} else { |
|
198
|
|
|
$this->loggerInstance->debug(2, "Installer generation failed for: " . $profile->identifier . ":$device:" . $this->languageInstance->getLang() . "\n"); |
|
199
|
|
|
$out['link'] = 0; |
|
200
|
|
|
} |
|
201
|
|
|
} |
|
202
|
|
|
return $out; |
|
203
|
|
|
} |
|
204
|
|
|
|
|
205
|
|
|
/** |
|
206
|
|
|
* interface to Devices::listDevices() |
|
207
|
|
|
* |
|
208
|
|
|
* @param int $showHidden whether or not hidden devices should be shown |
|
209
|
|
|
* @return array the list of devices |
|
210
|
|
|
* @throws Exception |
|
211
|
|
|
*/ |
|
212
|
|
|
public function listDevices($showHidden = 0) |
|
213
|
|
|
{ |
|
214
|
|
|
$returnList = []; |
|
215
|
|
|
$count = 0; |
|
216
|
|
|
if ($showHidden !== 0 && $showHidden != 1) { |
|
217
|
|
|
throw new Exception("show_hidden is only be allowed to be 0 or 1, but it is $showHidden!"); |
|
218
|
|
|
} |
|
219
|
|
|
foreach (\devices\Devices::listDevices() as $device => $deviceProperties) { |
|
220
|
|
|
if (\core\common\Entity::getAttributeValue($deviceProperties, 'options', 'hidden') === 1 && $showHidden === 0) { |
|
221
|
|
|
continue; |
|
222
|
|
|
} |
|
223
|
|
|
$count++; |
|
224
|
|
|
$deviceProperties['device'] = $device; |
|
225
|
|
|
$group = isset($deviceProperties['group']) ? $deviceProperties['group'] : 'other'; |
|
226
|
|
|
if (!isset($returnList[$group])) { |
|
227
|
|
|
$returnList[$group] = []; |
|
228
|
|
|
} |
|
229
|
|
|
$returnList[$group][$device] = $deviceProperties; |
|
230
|
|
|
} |
|
231
|
|
|
return $returnList; |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
/** |
|
235
|
|
|
* |
|
236
|
|
|
* @param string $device identifier of the device |
|
237
|
|
|
* @param int $profileId identifier of the profile |
|
238
|
|
|
* @return void |
|
239
|
|
|
*/ |
|
240
|
|
|
public function deviceInfo($device, $profileId) |
|
241
|
|
|
{ |
|
242
|
|
|
$validator = new \web\lib\common\InputValidation(); |
|
243
|
|
|
$out = 0; |
|
244
|
|
|
$profile = $validator->existingProfile($profileId); |
|
245
|
|
|
$factory = new DeviceFactory($device); |
|
246
|
|
|
$dev = $factory->device; |
|
247
|
|
|
if (isset($dev)) { |
|
248
|
|
|
$dev->setup($profile); |
|
249
|
|
|
$out = $dev->writeDeviceInfo(); |
|
250
|
|
|
} |
|
251
|
|
|
echo $out; |
|
252
|
|
|
} |
|
253
|
|
|
|
|
254
|
|
|
/** |
|
255
|
|
|
* Prepare the support data for a given profile |
|
256
|
|
|
* |
|
257
|
|
|
* @param int $profId profile identifier |
|
258
|
|
|
* @return array |
|
259
|
|
|
* array with the following fields: |
|
260
|
|
|
* - local_email |
|
261
|
|
|
* - local_phone |
|
262
|
|
|
* - local_url |
|
263
|
|
|
* - description |
|
264
|
|
|
* - devices - an array of device names and their statuses (for a given profile) |
|
265
|
|
|
* - last_changed |
|
266
|
|
|
*/ |
|
267
|
|
|
public function profileAttributes($profId) |
|
268
|
|
|
{ |
|
269
|
|
|
$validator = new \web\lib\common\InputValidation(); |
|
270
|
|
|
$profile = $validator->existingProfile($profId); |
|
271
|
|
|
$attribs = $profile->getCollapsedAttributes(); |
|
272
|
|
|
$returnArray = []; |
|
273
|
|
|
$returnArray['silverbullet'] = $profile instanceof ProfileSilverbullet ? 1 : 0; |
|
274
|
|
|
if (isset($attribs['support:email'])) { |
|
275
|
|
|
$returnArray['local_email'] = $attribs['support:email'][0]; |
|
276
|
|
|
} |
|
277
|
|
|
if (isset($attribs['support:phone'])) { |
|
278
|
|
|
$returnArray['local_phone'] = $attribs['support:phone'][0]; |
|
279
|
|
|
} |
|
280
|
|
|
if (isset($attribs['support:url'])) { |
|
281
|
|
|
$returnArray['local_url'] = $attribs['support:url'][0]; |
|
282
|
|
|
} |
|
283
|
|
|
if (isset($attribs['profile:description'])) { |
|
284
|
|
|
$returnArray['description'] = $attribs['profile:description'][0]; |
|
285
|
|
|
} |
|
286
|
|
|
if (isset($attribs['media:openroaming'])) { |
|
287
|
|
|
$returnArray['openroaming'] = $attribs['media:openroaming'][0]; |
|
288
|
|
|
} |
|
289
|
|
|
$returnArray['devices'] = $profile->listDevices(); |
|
290
|
|
|
$returnArray['last_changed'] = $profile->getFreshness(); |
|
291
|
|
|
return $returnArray; |
|
292
|
|
|
} |
|
293
|
|
|
|
|
294
|
|
|
/** |
|
295
|
|
|
* Generate and send the installer |
|
296
|
|
|
* |
|
297
|
|
|
* @param string $device identifier as in {@link devices.php} |
|
298
|
|
|
* @param int $prof_id profile identifier |
|
299
|
|
|
* @param string $generated_for which download area does this pertain to |
|
300
|
|
|
* @param string $token for silverbullet: invitation token to consume |
|
301
|
|
|
* @param string $password for silverbull: import PIN for the future certificate |
|
302
|
|
|
* @return string binary stream: installerFile |
|
303
|
|
|
*/ |
|
304
|
|
|
public function downloadInstaller($device, $prof_id, $generated_for = 'user', $token = NULL, $password = NULL) |
|
305
|
|
|
{ |
|
306
|
|
|
$this->loggerInstance->debug(4, "downloadInstaller arguments: $device,$prof_id,$generated_for\n"); |
|
307
|
|
|
$output = $this->generateInstaller($device, $prof_id, $generated_for, $token, $password); |
|
308
|
|
|
$this->loggerInstance->debug(4, "output from GUI::generateInstaller:"); |
|
309
|
|
|
$this->loggerInstance->debug(4, print_r($output, true)); |
|
310
|
|
|
if (empty($output['link']) || $output['link'] === 0) { |
|
311
|
|
|
header("HTTP/1.0 404 Not Found"); |
|
312
|
|
|
return; |
|
313
|
|
|
} |
|
314
|
|
|
$validator = new \web\lib\common\InputValidation(); |
|
315
|
|
|
$profile = $validator->existingProfile($prof_id); |
|
316
|
|
|
$profile->incrementDownloadStats($device, $generated_for); |
|
317
|
|
|
$file = $this->installerPath; |
|
318
|
|
|
$filetype = $output['mime']; |
|
319
|
|
|
$this->loggerInstance->debug(4, "installer MIME type:$filetype\n"); |
|
320
|
|
|
header("Content-type: " . $filetype); |
|
|
|
|
|
|
321
|
|
|
if ($filetype !== "application/x-wifi-config") { // for those installers to work on Android, Content-Disposition MUST NOT be set |
|
322
|
|
|
header('Content-Disposition: inline; filename="' . basename($file) . '"'); |
|
323
|
|
|
} else { |
|
324
|
|
|
header('Content-Transfer-Encoding: base64'); |
|
325
|
|
|
} |
|
326
|
|
|
header('Content-Length: ' . filesize($file)); |
|
327
|
|
|
ob_clean(); |
|
328
|
|
|
flush(); |
|
329
|
|
|
readfile($file); |
|
330
|
|
|
} |
|
331
|
|
|
|
|
332
|
|
|
/** |
|
333
|
|
|
* resizes image files |
|
334
|
|
|
* |
|
335
|
|
|
* @param string $inputImage the image we want to process |
|
336
|
|
|
* @param string $destFile the output file for the processed image |
|
337
|
|
|
* @param int $width if resizing, the target width |
|
338
|
|
|
* @param int $height if resizing, the target height |
|
339
|
|
|
* @param bool $resize shall we do resizing? width and height are ignored otherwise |
|
340
|
|
|
* @return array |
|
341
|
|
|
*/ |
|
342
|
|
|
private function processImage($inputImage, $destFile, $width, $height, $resize) |
|
343
|
|
|
{ |
|
344
|
|
|
$info = new \finfo(); |
|
345
|
|
|
$filetype = $info->buffer($inputImage, FILEINFO_MIME_TYPE); |
|
346
|
|
|
$offset = 60 * 60 * 24 * 30; |
|
347
|
|
|
// gmdate cannot fail here - time() is its default argument (and integer), and we are adding an integer to it |
|
348
|
|
|
$expiresString = "Expires: " . /** @scrutinizer ignore-type */ gmdate("D, d M Y H:i:s", time() + $offset) . " GMT"; |
|
349
|
|
|
$blob = $inputImage; |
|
350
|
|
|
|
|
351
|
|
|
if ($resize === TRUE) { |
|
352
|
|
|
$image = new \Imagick(); |
|
353
|
|
|
$image->readImageBlob($inputImage); |
|
354
|
|
|
$image->setImageFormat('PNG'); |
|
355
|
|
|
$image->thumbnailImage($width, $height, 1); |
|
356
|
|
|
$blob = $image->getImageBlob(); |
|
357
|
|
|
$this->loggerInstance->debug(4, "Writing cached logo $destFile for IdP/Federation.\n"); |
|
358
|
|
|
file_put_contents($destFile, $blob); |
|
359
|
|
|
} |
|
360
|
|
|
|
|
361
|
|
|
return ["filetype" => $filetype, "expires" => $expiresString, "blob" => $blob]; |
|
362
|
|
|
} |
|
363
|
|
|
|
|
364
|
|
|
/** |
|
365
|
|
|
* Get and prepare logo file |
|
366
|
|
|
* |
|
367
|
|
|
* When called for DiscoJuice, first check if file cache exists |
|
368
|
|
|
* If not then generate the file and save it in the cache |
|
369
|
|
|
* @param int|string $identifier IdP or Federation identifier |
|
370
|
|
|
* @param string $type either 'idp' or 'federation' is allowed |
|
371
|
|
|
* @param integer $widthIn maximum width of the generated image - if 0 then it is treated as no upper bound |
|
372
|
|
|
* @param integer $heightIn maximum height of the generated image - if 0 then it is treated as no upper bound |
|
373
|
|
|
* @return array|null array with image information or NULL if there is no logo |
|
374
|
|
|
* @throws Exception |
|
375
|
|
|
*/ |
|
376
|
|
|
protected function getLogo($identifier, $type, $widthIn, $heightIn) |
|
377
|
|
|
{ |
|
378
|
|
|
$expiresString = ''; |
|
379
|
|
|
$attributeName = [ |
|
380
|
|
|
'federation' => "fed:logo_file", |
|
381
|
|
|
'federation_from_idp' => "fed:logo_file", |
|
382
|
|
|
'idp' => "general:logo_file", |
|
383
|
|
|
]; |
|
384
|
|
|
|
|
385
|
|
|
$logoFile = ""; |
|
386
|
|
|
$validator = new \web\lib\common\InputValidation(); |
|
387
|
|
|
switch ($type) { |
|
388
|
|
|
case "federation": |
|
389
|
|
|
$entity = $validator->existingFederation($identifier); |
|
390
|
|
|
break; |
|
391
|
|
|
case "idp": |
|
392
|
|
|
$entity = $validator->existingIdP($identifier); |
|
393
|
|
|
break; |
|
394
|
|
|
case "federation_from_idp": |
|
395
|
|
|
$idp = $validator->existingIdP($identifier); |
|
396
|
|
|
$entity = $validator->existingFederation($idp->federation); |
|
397
|
|
|
break; |
|
398
|
|
|
default: |
|
399
|
|
|
throw new Exception("Unknown type of logo requested!"); |
|
400
|
|
|
} |
|
401
|
|
|
$filetype = 'image/png'; // default, only one code path where it can become different |
|
402
|
|
|
list($width, $height, $resize) = $this->testForResize($widthIn, $heightIn); |
|
403
|
|
|
if ($resize) { |
|
404
|
|
|
$logoFile = ROOT . '/web/downloads/logos/' . $identifier . '_' . $width . '_' . $height . '.png'; |
|
405
|
|
|
} |
|
406
|
|
|
if (is_file($logoFile)) { // $logoFile could be an empty string but then we will get a FALSE |
|
407
|
|
|
$this->loggerInstance->debug(4, "Using cached logo $logoFile for: $identifier\n"); |
|
408
|
|
|
$blob = file_get_contents($logoFile); |
|
409
|
|
|
} else { |
|
410
|
|
|
$logoAttribute = $entity->getAttributes($attributeName[$type]); |
|
411
|
|
|
if (count($logoAttribute) == 0) { |
|
412
|
|
|
return NULL; |
|
413
|
|
|
} |
|
414
|
|
|
$this->loggerInstance->debug(4, "RESIZE:$width:$height\n"); |
|
415
|
|
|
$meta = $this->processImage($logoAttribute[0]['value'], $logoFile, $width, $height, $resize); |
|
416
|
|
|
$filetype = $meta['filetype']; |
|
417
|
|
|
$expiresString = $meta['expires']; |
|
418
|
|
|
$blob = $meta['blob']; |
|
419
|
|
|
} |
|
420
|
|
|
return ["filetype" => $filetype, "expires" => $expiresString, "blob" => $blob]; |
|
421
|
|
|
} |
|
422
|
|
|
|
|
423
|
|
|
/** |
|
424
|
|
|
* see if we have to resize an image |
|
425
|
|
|
* |
|
426
|
|
|
* @param integer $width the desired max width (0 = unbounded) |
|
427
|
|
|
* @param integer $height the desired max height (0 = unbounded) |
|
428
|
|
|
* @return array |
|
429
|
|
|
*/ |
|
430
|
|
|
private function testForResize($width, $height) |
|
431
|
|
|
{ |
|
432
|
|
|
if (is_numeric($width) && is_numeric($height) && ($width > 0 || $height > 0)) { |
|
433
|
|
|
if ($height == 0) { |
|
434
|
|
|
$height = 10000; |
|
435
|
|
|
} |
|
436
|
|
|
if ($width == 0) { |
|
437
|
|
|
$width = 10000; |
|
438
|
|
|
} |
|
439
|
|
|
return [$width, $height, TRUE]; |
|
440
|
|
|
} |
|
441
|
|
|
return [0, 0, FALSE]; |
|
442
|
|
|
} |
|
443
|
|
|
|
|
444
|
|
|
/** |
|
445
|
|
|
* find out where the device is currently located |
|
446
|
|
|
* @return array |
|
447
|
|
|
*/ |
|
448
|
|
|
public function locateDevice() |
|
449
|
|
|
{ |
|
450
|
|
|
return \core\DeviceLocation::locateDevice(); |
|
451
|
|
|
} |
|
452
|
|
|
|
|
453
|
|
|
/** |
|
454
|
|
|
* Lists all identity providers in the database |
|
455
|
|
|
* adding information required by DiscoJuice. |
|
456
|
|
|
* |
|
457
|
|
|
* @param int $activeOnly if set to non-zero will cause listing of only those institutions which have some valid profiles defined. |
|
458
|
|
|
* @param string $country if set, only list IdPs in a specific country |
|
459
|
|
|
* @return array the list of identity providers |
|
460
|
|
|
* |
|
461
|
|
|
*/ |
|
462
|
|
|
public function listAllIdentityProviders($activeOnly = 0, $country = "") |
|
463
|
|
|
{ |
|
464
|
|
|
return IdPlist::listAllIdentityProviders($activeOnly, $country); |
|
465
|
|
|
} |
|
466
|
|
|
|
|
467
|
|
|
/** |
|
468
|
|
|
* Order active identity providers according to their distance and name |
|
469
|
|
|
* @param string $country NRO to work with |
|
470
|
|
|
* @param array $currentLocation current location |
|
471
|
|
|
* |
|
472
|
|
|
* @return array $IdPs - list of arrays ('id', 'name'); |
|
473
|
|
|
*/ |
|
474
|
|
|
public function orderIdentityProviders($country, $currentLocation) |
|
475
|
|
|
{ |
|
476
|
|
|
return IdPlist::orderIdentityProviders($country, $currentLocation); |
|
477
|
|
|
} |
|
478
|
|
|
|
|
479
|
|
|
/** |
|
480
|
|
|
* outputs a full list of IdPs containing the fllowing data: |
|
481
|
|
|
* institution_is, institution name in all available languages, |
|
482
|
|
|
* list of production profiles. |
|
483
|
|
|
* For eache profile the profile identifier, profile name in all languages |
|
484
|
|
|
* and redirect values (empty rediret value means that no redirect has been |
|
485
|
|
|
* set). |
|
486
|
|
|
* |
|
487
|
|
|
* @return array of identity providers with attributes |
|
488
|
|
|
*/ |
|
489
|
|
|
public function listIdentityProvidersWithProfiles() { |
|
490
|
|
|
return IdPlist::listIdentityProvidersWithProfiles(); |
|
491
|
|
|
} |
|
492
|
|
|
|
|
493
|
|
|
/** |
|
494
|
|
|
* Detect the best device driver form the browser |
|
495
|
|
|
* Detects the operating system and returns its id |
|
496
|
|
|
* display name and group membership (as in devices.php) |
|
497
|
|
|
* @return array|boolean OS information, indexed by 'id', 'display', 'group' |
|
498
|
|
|
*/ |
|
499
|
|
|
public function detectOS() |
|
500
|
|
|
{ |
|
501
|
|
|
$Dev = \devices\Devices::listDevices(); |
|
502
|
|
|
$devId = $this->deviceFromRequest(); |
|
503
|
|
|
if ($devId !== NULL) { |
|
504
|
|
|
$ret = $this->returnDevice($devId, $Dev[$devId]); |
|
505
|
|
|
if ($ret !== FALSE) { |
|
506
|
|
|
return $ret; |
|
507
|
|
|
} |
|
508
|
|
|
} |
|
509
|
|
|
// the device has not been specified or not specified correctly, try to detect if from the browser ID |
|
510
|
|
|
$browser = filter_input(INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_SANITIZE_STRING); |
|
511
|
|
|
$this->loggerInstance->debug(4, "HTTP_USER_AGENT=$browser\n"); |
|
512
|
|
|
foreach ($Dev as $devId => $device) { |
|
513
|
|
|
if (!isset($device['match'])) { |
|
514
|
|
|
continue; |
|
515
|
|
|
} |
|
516
|
|
|
if (preg_match('/' . $device['match'] . '/', $browser)) { |
|
517
|
|
|
return $this->returnDevice($devId, $device); |
|
518
|
|
|
} |
|
519
|
|
|
} |
|
520
|
|
|
$this->loggerInstance->debug(2, "Unrecognised system: $browser\n"); |
|
521
|
|
|
return FALSE; |
|
522
|
|
|
} |
|
523
|
|
|
|
|
524
|
|
|
/** |
|
525
|
|
|
* test if devise is defined and is not hidden. If all is fine return extracted information. |
|
526
|
|
|
* |
|
527
|
|
|
* @param string $devId device id as defined as index in Devices.php |
|
528
|
|
|
* @param array $device device info as defined in Devices.php |
|
529
|
|
|
* @return array|FALSE if the device has not been correctly specified |
|
530
|
|
|
*/ |
|
531
|
|
|
private function returnDevice($devId, $device) |
|
532
|
|
|
{ |
|
533
|
|
|
if (\core\common\Entity::getAttributeValue($device, 'options', 'hidden') !== 1) { |
|
534
|
|
|
$this->loggerInstance->debug(4, "Browser_id: $devId\n"); |
|
535
|
|
|
return ['device' => $devId, 'display' => $device['display'], 'group' => $device['group']]; |
|
536
|
|
|
} |
|
537
|
|
|
return FALSE; |
|
538
|
|
|
} |
|
539
|
|
|
|
|
540
|
|
|
/** |
|
541
|
|
|
* This methods cheks if the devide has been specified as the HTTP parameters |
|
542
|
|
|
* |
|
543
|
|
|
* @return device id|NULL if correcty specified or FALSE otherwise |
|
544
|
|
|
*/ |
|
545
|
|
|
private function deviceFromRequest() |
|
546
|
|
|
{ |
|
547
|
|
|
$devId = filter_input(INPUT_GET, 'device', FILTER_SANITIZE_STRING) ?? filter_input(INPUT_POST, 'device', FILTER_SANITIZE_STRING); |
|
548
|
|
|
if ($devId === NULL || $devId === FALSE) { |
|
549
|
|
|
$this->loggerInstance->debug(2, "Invalid device id provided\n"); |
|
550
|
|
|
return NULL; |
|
551
|
|
|
} |
|
552
|
|
|
if (!isset(\devices\Devices::listDevices()[$devId])) { |
|
553
|
|
|
$this->loggerInstance->debug(2, "Unrecognised system: $devId\n"); |
|
554
|
|
|
return NULL; |
|
555
|
|
|
} |
|
556
|
|
|
return $devId; |
|
557
|
|
|
} |
|
558
|
|
|
|
|
559
|
|
|
/** |
|
560
|
|
|
* finds all the user certificates that originated in a given token |
|
561
|
|
|
* |
|
562
|
|
|
* @param string $token the token for which we are fetching all associated user certs |
|
563
|
|
|
* @return array|boolean returns FALSE if a token is invalid, otherwise array of certs |
|
564
|
|
|
*/ |
|
565
|
|
|
public function getUserCerts($token) |
|
566
|
|
|
{ |
|
567
|
|
|
$validator = new \web\lib\common\InputValidation(); |
|
568
|
|
|
$cleanToken = $validator->token($token); |
|
569
|
|
|
if ($cleanToken) { |
|
570
|
|
|
// check status of this silverbullet token according to info in DB: |
|
571
|
|
|
// it can be VALID (exists and not redeemed, EXPIRED, REDEEMED or INVALID (non existent) |
|
572
|
|
|
$invitationObject = new \core\SilverbulletInvitation($cleanToken); |
|
573
|
|
|
} else { |
|
574
|
|
|
return false; |
|
575
|
|
|
} |
|
576
|
|
|
$profile = new \core\ProfileSilverbullet($invitationObject->profile, NULL); |
|
577
|
|
|
$userdata = $profile->userStatus($invitationObject->userId); |
|
578
|
|
|
$allcerts = []; |
|
579
|
|
|
foreach ($userdata as $content) { |
|
580
|
|
|
$allcerts = array_merge($allcerts, $content->associatedCertificates); |
|
581
|
|
|
} |
|
582
|
|
|
return $allcerts; |
|
583
|
|
|
} |
|
584
|
|
|
|
|
585
|
|
|
/** |
|
586
|
|
|
* device name |
|
587
|
|
|
* |
|
588
|
|
|
* @var string |
|
589
|
|
|
*/ |
|
590
|
|
|
public $device; |
|
591
|
|
|
|
|
592
|
|
|
/** |
|
593
|
|
|
* path to installer |
|
594
|
|
|
* |
|
595
|
|
|
* @var string |
|
596
|
|
|
*/ |
|
597
|
|
|
private $installerPath; |
|
598
|
|
|
|
|
599
|
|
|
/** |
|
600
|
|
|
* helper function to sort profiles by their name |
|
601
|
|
|
* @param \core\AbstractProfile $profile1 the first profile's information |
|
602
|
|
|
* @param \core\AbstractProfile $profile2 the second profile's information |
|
603
|
|
|
* @return int |
|
604
|
|
|
*/ |
|
605
|
|
|
private static function profileSort($profile1, $profile2) |
|
606
|
|
|
{ |
|
607
|
|
|
return strcasecmp($profile1->name, $profile2->name); |
|
608
|
|
|
} |
|
609
|
|
|
} |
'Content-type: ' . $filetypecan contain request data and is used in response header context(s) leading to a potential security vulnerability.1 path for user data to reach this point
$_GET,and InputValidation::existingProfile() is calledin web/admin/overview_installers.php on line 37
$inputin web/lib/common/InputValidation.php on line 119
array('w10' => array('group' => 'microsoft', 'display' => _('MS Windows 10'), 'match' => 'Windows NT 10', 'directory' => 'ms', 'module' => 'W8W10', 'signer' => 'ms_windows_sign', 'options' => array('sign' => 1, 'device_id' => 'W10', 'clientcert' => devices\Devices::SUPPORT_EMBEDDED_ECDSA, 'mime' => 'application/x-dosexec')), 'w8' => array('group' => 'microsoft', 'display' => _('MS Windows 8, 8.1'), 'match' => 'Windows NT 6[._][23]', 'directory' => 'ms', 'module' => 'W8W10', 'signer' => 'ms_windows_sign', 'options' => array('sign' => 1, 'device_id' => 'W8', 'clientcert' => devices\Devices::SUPPORT_EMBEDDED_ECDSA, 'mime' => 'application/x-dosexec')), 'w7' => array('group' => 'microsoft', 'display' => _('MS Windows 7'), 'match' => 'Windows NT 6[._]1', 'directory' => 'ms', 'module' => 'Vista7', 'signer' => 'ms_windows_sign', 'options' => array('sign' => 1, 'device_id' => 'W7', 'mime' => 'application/x-dosexec')), 'vista' => array('group' => 'microsoft', 'display' => _('MS Windows Vista'), 'match' => 'Windows NT 6[._]0', 'directory' => 'ms', 'module' => 'Vista7', 'signer' => 'ms_windows_sign', 'options' => array('sign' => 1, 'device_id' => 'Vista', 'mime' => 'application/x-dosexec')), 'win-rt' => array('group' => 'microsoft', 'display' => _('Windows RT'), 'directory' => 'redirect_dev', 'module' => 'RedirectDev', 'options' => array('hidden' => 0, 'redirect' => 1)), 'apple_global' => array('group' => 'apple', 'display' => _('Apple device'), 'match' => '(Mac OS X 1[01][._][0-9])|((iPad|iPhone|iPod);.*OS (\d+)_)', 'directory' => 'apple_mobileconfig', 'module' => 'MobileconfigOsX', 'signer' => 'mobileconfig_sign', 'options' => array('sign' => 1, 'device_id' => 'OS_X', 'mime' => 'application/x-apple-aspen-config', 'clientcert' => devices\Devices::SUPPORT_EMBEDDED_ECDSA, 'sb_message' => _('During the installation you will be first asked to enter settings for certificate and there you need to enter the import PIN shown on this page. Later you will be prompted to enter your password to allow making changes to the profile, this time it is your computer password.'))), 'apple_catalina' => array('group' => 'apple', 'display' => _('Apple macOS Catalina'), 'match' => 'Mac OS X 10[._]15', 'directory' => 'apple_mobileconfig', 'module' => 'MobileconfigOsX', 'signer' => 'mobileconfig_sign', 'options' => array('hidden' => 1, 'sign' => 1, 'device_id' => 'OS_X', 'mime' => 'application/x-apple-aspen-config', 'clientcert' => devices\Devices::SUPPORT_EMBEDDED_ECDSA, 'sb_message' => _('During the installation you will be first asked to enter settings for certificate and there you need to enter the import PIN shown on this page. Later you will be prompted to enter your password to allow making changes to the profile, this time it is your computer password.'))), 'apple_mojave' => array('group' => 'apple', 'display' => _('Apple macOS Mojave'), 'match' => 'Mac OS X 10[._]14', 'directory' => 'apple_mobileconfig', 'module' => 'MobileconfigOsX', 'signer' => 'mobileconfig_sign', 'options' => array('hidden' => 1, 'sign' => 1, 'device_id' => 'OS_X', 'mime' => 'application/x-apple-aspen-config', 'clientcert' => devices\Devices::SUPPORT_EMBEDDED_ECDSA, 'sb_message' => _('During the installation you will be first asked to enter settings for certificate and there you need to enter the import PIN shown on this page. Later you will be prompted to enter your password to allow making changes to the profile, this time it is your computer password.'))), 'apple_hi_sierra' => array('group' => 'apple', 'display' => _('Apple macOS High Sierra'), 'match' => 'Mac OS X 10[._]13', 'directory' => 'apple_mobileconfig', 'module' => 'MobileconfigOsX', 'signer' => 'mobileconfig_sign', 'options' => array('hidden' => 1, 'sign' => 1, 'device_id' => 'OS_X', 'mime' => 'application/x-apple-aspen-config', 'clientcert' => devices\Devices::SUPPORT_EMBEDDED_ECDSA, 'sb_message' => _('During the installation you will be first asked to enter settings for certificate and there you need to enter the import PIN shown on this page. Later you will be prompted to enter your password to allow making changes to the profile, this time it is your computer password.'))), 'apple_sierra' => array('group' => 'apple', 'display' => _('Apple macOS Sierra'), 'match' => 'Mac OS X 10[._]12', 'directory' => 'apple_mobileconfig', 'module' => 'MobileconfigOsX', 'signer' => 'mobileconfig_sign', 'options' => array('hidden' => 1, 'sign' => 1, 'device_id' => 'OS_X', 'mime' => 'application/x-apple-aspen-config', 'sb_message' => _('During the installation you will be first asked to enter settings for certificate and there you need to enter the import PIN shown on this page. Later you will be prompted to enter your password to allow making changes to the profile, this time it is your computer password.'))), 'apple_el_cap' => array('group' => 'apple', 'display' => _('Apple OS X El Capitan'), 'match' => 'Mac OS X 10[._]11', 'directory' => 'apple_mobileconfig', 'module' => 'MobileconfigOsX', 'signer' => 'mobileconfig_sign', 'options' => array('hidden' => 1, 'sign' => 1, 'device_id' => 'OS_X', 'mime' => 'application/x-apple-aspen-config', 'sb_message' => _('During the installation you will be first asked to enter settings for certificate and there you need to enter the import PIN shown on this page. Later you will be prompted to enter your password to allow making changes to the profile, this time it is your computer password.'))), 'apple_yos' => array('group' => 'apple', 'display' => _('Apple OS X Yosemite'), 'match' => 'Mac OS X 10[._]10', 'directory' => 'apple_mobileconfig', 'module' => 'MobileconfigOsX', 'signer' => 'mobileconfig_sign', 'options' => array('hidden' => 1, 'sign' => 1, 'device_id' => 'OS_X', 'mime' => 'application/x-apple-aspen-config', 'sb_message' => _('During the installation you will be first asked to enter settings for certificate and there you need to enter the import PIN shown on this page. Later you will be prompted to enter your password to allow making changes to the profile, this time it is your computer password.'))), 'apple_mav' => array('group' => 'apple', 'display' => _('Apple OS X Mavericks'), 'match' => 'Mac OS X 10[._]9', 'directory' => 'apple_mobileconfig', 'module' => 'MobileconfigOsX', 'signer' => 'mobileconfig_sign', 'options' => array('hidden' => 1, 'sign' => 1, 'device_id' => 'OS_X', 'mime' => 'application/x-apple-aspen-config', 'sb_message' => _('During the installation you will be first asked to enter settings for certificate and there you need to enter the import PIN shown on this page. Later you will be prompted to enter your password to allow making changes to the profile, this time it is your computer password.'))), 'apple_m_lion' => array('group' => 'apple', 'display' => _('Apple OS X Mountain Lion'), 'match' => 'Mac OS X 10[._]8', 'directory' => 'apple_mobileconfig', 'module' => 'MobileconfigOsX', 'signer' => 'mobileconfig_sign', 'options' => array('hidden' => 1, 'sign' => 1, 'device_id' => 'OS_X', 'mime' => 'application/x-apple-aspen-config', 'sb_message' => _('During the installation you will be first asked to enter settings for certificate and there you need to enter the import PIN shown on this page. Later you will be prompted to enter your password to allow making changes to the profile, this time it is your computer password.'))), 'apple_lion' => array('group' => 'apple', 'display' => _('Apple OS X Lion'), 'match' => 'Mac OS X 10[._]7', 'directory' => 'apple_mobileconfig', 'module' => 'MobileconfigOsX', 'signer' => 'mobileconfig_sign', 'options' => array('hidden' => 1, 'sign' => 1, 'device_id' => 'OS_X', 'mime' => 'application/x-apple-aspen-config', 'sb_message' => _('During the installation you will be first asked to enter settings for certificate and there you need to enter the import PIN shown on this page. Later you will be prompted to enter your password to allow making changes to the profile, this time it is your computer password.'))), 'mobileconfig' => array('group' => 'apple', 'display' => _('Apple iOS mobile device (iOS 7-11)'), 'match' => '(iPad|iPhone|iPod);.*OS ([7-9]|1[0-1])_', 'directory' => 'apple_mobileconfig', 'module' => 'MobileconfigIos7plus', 'signer' => 'mobileconfig_sign', 'options' => array('hidden' => 1, 'sign' => 1, 'device_id' => 'iOS', 'mime' => 'application/x-apple-aspen-config', 'sb_message' => _('During the installation you will be first asked to enter your passcode - this is your device security code! Later on you will be prompted for the password to the certificate and there you need to enter the import PIN shown on this page.'))), 'mobileconfig-56' => array('group' => 'apple', 'display' => _('Apple iOS mobile device (iOS 5 and 6)'), 'match' => '(iPad|iPhone|iPod);.*OS [56]_', 'directory' => 'apple_mobileconfig', 'module' => 'MobileconfigIos5plus', 'signer' => 'mobileconfig_sign', 'options' => array('hidden' => 1, 'sign' => 1, 'device_id' => 'iOS', 'mime' => 'application/x-apple-aspen-config')), 'linux' => array('group' => 'linux', 'display' => _('Linux'), 'match' => 'Linux(?!.*Android)', 'directory' => 'linux', 'module' => 'Linux', 'options' => array('mime' => 'application/x-sh')), 'chromeos' => array('group' => 'chrome', 'display' => _('Chrome OS'), 'match' => 'CrOS', 'directory' => 'chromebook', 'module' => 'Chromebook', 'options' => array('mime' => 'application/x-onc', 'message' => sprintf(_('After downloading the file, open the Chrome browser and browse to this URL: <a href='chrome://net-internals/#chromeos'>chrome://net-internals/#chromeos</a>. Then, use the 'Import ONC file' button. The import is silent; the new network definitions will be added to the preferred networks.')))), 'android_recent' => array('group' => 'android', 'display' => _('Android 11 and higher'), 'match' => 'Android 1[1-9]', 'directory' => 'xml', 'module' => 'Lollipop', 'options' => array('mime' => 'application/eap-config', 'message' => sprintf(_('Before you proceed with installation on Android systems, please make sure that you have installed the %s application. This application is available from these sites: %s and will use the configuration file downloaded from CAT to create all necessary settings.'), 'geteduroam', '<a target='_blank' href='https://play.google.com/store/apps/details?id=app.eduroam.geteduroam'>Google Play</a>, <a target='_blank' href='geteduroam-stable.apk'>' . _('as local download') . '</a>'))), 'android_8_10' => array('group' => 'android', 'display' => _('Android 8 to 10'), 'match' => 'Android ([89]|10)', 'directory' => 'xml', 'module' => 'Lollipop', 'options' => array('mime' => 'application/eap-config', 'message' => sprintf(_('Before you proceed with installation on Android systems, please make sure that you have installed the %s application. This application is available from these sites: %s and will use the configuration file downloaded from CAT to create all necessary settings.'), 'geteduroam', '<a target='_blank' href='https://play.google.com/store/apps/details?id=app.eduroam.geteduroam'>Google Play</a>, <a target='_blank' href='geteduroam-stable.apk'>' . _('as local download') . '</a>'))), 'android_4_7' => array('group' => 'android', 'display' => _('Android 4.3 to 7'), 'match' => 'Android [4-7]', 'directory' => 'xml', 'module' => 'Lollipop', 'options' => array('mime' => 'application/eap-config', 'message' => sprintf(_('Before you proceed with installation on Android systems, please make sure that you have installed the %s application. This application is available from these sites: %s and will use the configuration file downloaded from CAT to create all necessary settings.'), 'eduroamCAT', '<a target='_blank' href='https://play.google.com/store/apps/details?id=uk.ac.swansea.eduroamcat'>Google Play</a>, <a target='_blank' href='https://www.amazon.com/dp/B01EACCX0S/'>Amazon Appstore</a>, <a target='_blank' href='eduroamCAT-stable.apk'>' . _('as local download') . '</a>'))), 'android_q' => array('group' => 'android', 'display' => _('Android 10.0 Q'), 'match' => 'Android 10', 'directory' => 'xml', 'module' => 'Lollipop', 'options' => array('hidden' => 1, 'mime' => 'application/eap-config', 'message' => sprintf(_('Before you proceed with installation on Android systems, please make sure that you have installed the %s application. This application is available from these sites: %s and will use the configuration file downloaded from CAT to create all necessary settings.'), 'eduroamCAT', '<a target='_blank' href='https://play.google.com/store/apps/details?id=uk.ac.swansea.eduroamcat'>Google Play</a>, <a target='_blank' href='https://www.amazon.com/dp/B01EACCX0S/'>Amazon Appstore</a>, <a target='_blank' href='eduroamCAT-stable.apk'>' . _('as local download') . '</a>'))), 'android_pie' => array('group' => 'android', 'display' => _('Android 9.0 Pie'), 'match' => 'Android 9', 'directory' => 'xml', 'module' => 'Lollipop', 'options' => array('hidden' => 1, 'mime' => 'application/eap-config', 'message' => sprintf(_('Before you proceed with installation on Android systems, please make sure that you have installed the %s application. This application is available from these sites: %s and will use the configuration file downloaded from CAT to create all necessary settings.'), 'eduroamCAT', '<a target='_blank' href='https://play.google.com/store/apps/details?id=uk.ac.swansea.eduroamcat'>Google Play</a>, <a target='_blank' href='https://www.amazon.com/dp/B01EACCX0S/'>Amazon Appstore</a>, <a target='_blank' href='eduroamCAT-stable.apk'>' . _('as local download') . '</a>'))), 'android_oreo' => array('group' => 'android', 'display' => _('Android 8.0 Oreo'), 'match' => 'Android 8', 'directory' => 'xml', 'module' => 'Lollipop', 'options' => array('hidden' => 1, 'mime' => 'application/eap-config', 'message' => sprintf(_('Before you proceed with installation on Android systems, please make sure that you have installed the %s application. This application is available from these sites: %s and will use the configuration file downloaded from CAT to create all necessary settings.'), 'eduroamCAT', '<a target='_blank' href='https://play.google.com/store/apps/details?id=uk.ac.swansea.eduroamcat'>Google Play</a>, <a target='_blank' href='https://www.amazon.com/dp/B01EACCX0S/'>Amazon Appstore</a>, <a target='_blank' href='eduroamCAT-stable.apk'>' . _('as local download') . '</a>'))), 'android_nougat' => array('group' => 'android', 'display' => _('Android 7.0 Nougat'), 'match' => 'Android 7', 'directory' => 'xml', 'module' => 'Lollipop', 'options' => array('hidden' => 1, 'mime' => 'application/eap-config', 'message' => sprintf(_('Before you proceed with installation on Android systems, please make sure that you have installed the %s application. This application is available from these sites: %s and will use the configuration file downloaded from CAT to create all necessary settings.'), 'eduroamCAT', '<a target='_blank' href='https://play.google.com/store/apps/details?id=uk.ac.swansea.eduroamcat'>Google Play</a>, <a target='_blank' href='https://www.amazon.com/dp/B01EACCX0S/'>Amazon Appstore</a>, <a target='_blank' href='eduroamCAT-stable.apk'>' . _('as local download') . '</a>'))), 'android_marshmallow' => array('group' => 'android', 'display' => _('Android 6.0 Marshmallow'), 'match' => 'Android 6', 'directory' => 'xml', 'module' => 'Lollipop', 'options' => array('hidden' => 1, 'mime' => 'application/eap-config', 'message' => sprintf(_('Before you proceed with installation on Android systems, please make sure that you have installed the %s application. This application is available from these sites: %s and will use the configuration file downloaded from CAT to create all necessary settings.'), 'eduroamCAT', '<a target='_blank' href='https://play.google.com/store/apps/details?id=uk.ac.swansea.eduroamcat'>Google Play</a>, <a target='_blank' href='https://www.amazon.com/dp/B01EACCX0S/'>Amazon Appstore</a>, <a target='_blank' href='eduroamCAT-stable.apk'>' . _('as local download') . '</a>'))), 'android_lollipop' => array('group' => 'android', 'display' => _('Android 5.0 Lollipop'), 'match' => 'Android 5', 'directory' => 'xml', 'module' => 'Lollipop', 'options' => array('hidden' => 1, 'mime' => 'application/eap-config', 'message' => sprintf(_('Before you proceed with installation on Android systems, please make sure that you have installed the %s application. This application is available from these sites: %s and will use the configuration file downloaded from CAT to create all necessary settings.'), 'eduroamCAT', '<a target='_blank' href='https://play.google.com/store/apps/details?id=uk.ac.swansea.eduroamcat'>Google Play</a>, <a target='_blank' href='https://www.amazon.com/dp/B01EACCX0S/'>Amazon Appstore</a>, <a target='_blank' href='eduroamCAT-stable.apk'>' . _('as local download') . '</a>'))), 'android_kitkat' => array('group' => 'android', 'display' => _('Android 4.4 KitKat'), 'match' => 'Android 4\.[4-9]', 'directory' => 'xml', 'module' => 'KitKat', 'options' => array('hidden' => 1, 'mime' => 'application/eap-config', 'message' => sprintf(_('Before you proceed with installation on Android systems, please make sure that you have installed the %s application. This application is available from these sites: %s and will use the configuration file downloaded from CAT to create all necessary settings.'), 'eduroamCAT', '<a target='_blank' href='https://play.google.com/store/apps/details?id=uk.ac.swansea.eduroamcat'>Google Play</a>, <a target='_blank' href='https://www.amazon.com/dp/B01EACCX0S/'>Amazon Appstore</a>, <a target='_blank' href='eduroamCAT-stable.apk'>' . _('as local download') . '</a>'))), 'android_43' => array('group' => 'android', 'display' => _('Android 4.3'), 'match' => 'Android 4\.3', 'directory' => 'xml', 'module' => 'KitKat', 'options' => array('hidden' => 1, 'mime' => 'application/eap-config', 'message' => sprintf(_('Before you proceed with installation on Android systems, please make sure that you have installed the %s application. This application is available from these sites: %s and will use the configuration file downloaded from CAT to create all necessary settings.'), 'eduroamCAT', '<a target='_blank' href='https://play.google.com/store/apps/details?id=uk.ac.swansea.eduroamcat'>Google Play</a>, <a target='_blank' href='https://www.amazon.com/dp/B01EACCX0S/'>Amazon Appstore</a>, <a target='_blank' href='eduroamCAT-stable.apk'>' . _('as local download') . '</a>'))), 'android_legacy' => array('group' => 'android', 'display' => _('Android'), 'match' => 'Android', 'directory' => 'redirect_dev', 'module' => 'RedirectDev', 'options' => array('redirect' => 1)), 'eap-config' => array('group' => 'eap-config', 'display' => _('EAP config'), 'directory' => 'xml', 'module' => 'XMLAll', 'options' => array('mime' => 'application/eap-config', 'message' => sprintf(_('This option provides an EAP config XML file, which can be consumed by the eduroamCAT app for Android.')))), 'eap-generic' => array('group' => 'eap-config', 'display' => _('EAP generic'), 'directory' => 'xml', 'module' => 'Generic', 'options' => array('mime' => 'application/eap-config', 'message' => sprintf(_('This option provides a generic EAP config XML file, which can be consumed by the GetEduroam applications.')), 'hidden' => 1)), 'test' => array('group' => 'other', 'display' => _('Test'), 'directory' => 'test_module', 'module' => 'TestModule', 'options' => array('hidden' => 1)))is assigned to$retArrayin devices/Devices-template.php on line 125
$retArrayis returnedin devices/Devices-template.php on line 649
devices\Devices::listDevices()is assigned to$Devin core/DeviceFactory.php on line 66
$Dev[$blueprint]['options']is assigned to$Optin core/DeviceFactory.php on line 83
$Optis assigned to$valuein core/DeviceFactory.php on line 84
$valueis assigned to$optionsin core/DeviceFactory.php on line 85
$optionsis assigned to property DeviceConfig::$optionsin core/DeviceFactory.php on line 88
$dev->options['mime']is assigned to$outin core/UserAPI.php on line 183
$outis returnedin core/UserAPI.php on line 202
$this->generateNewInstaller($device, $profile, $generatedFor, $token, $password)is assigned to$myInstallerin core/UserAPI.php on line 92
$myInstaller['mime']is assigned to$installerPropertiesin core/UserAPI.php on line 94
$installerPropertiesis returnedin core/UserAPI.php on line 98
$this->generateInstaller($device, $prof_id, $generated_for, $token, $password)is assigned to$outputin core/UserAPI.php on line 307
$output['mime']is assigned to$filetypein core/UserAPI.php on line 318
Response Splitting Attacks
Allowing an attacker to set a response header, opens your application to response splitting attacks; effectively allowing an attacker to send any response, he would like.
General Strategies to prevent injection
In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:
if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) { throw new \InvalidArgumentException('This input is not allowed.'); }For numeric data, we recommend to explicitly cast the data: