|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/* |
|
4
|
|
|
* ****************************************************************************** |
|
5
|
|
|
* Copyright 2011-2017 DANTE Ltd. and GÉANT on behalf of the GN3, GN3+, GN4-1 |
|
6
|
|
|
* and GN4-2 consortia |
|
7
|
|
|
* |
|
8
|
|
|
* License: see the web/copyright.php file in the file structure |
|
9
|
|
|
* ****************************************************************************** |
|
10
|
|
|
*/ |
|
11
|
|
|
|
|
12
|
|
|
/** |
|
13
|
|
|
* This file contains the Federation class. |
|
14
|
|
|
* |
|
15
|
|
|
* @author Stefan Winter <[email protected]> |
|
16
|
|
|
* @author Tomasz Wolniewicz <[email protected]> |
|
17
|
|
|
* |
|
18
|
|
|
* @package Developer |
|
19
|
|
|
* |
|
20
|
|
|
*/ |
|
21
|
|
|
|
|
22
|
|
|
namespace core; |
|
23
|
|
|
|
|
24
|
|
|
use \Exception; |
|
25
|
|
|
|
|
26
|
|
|
/** |
|
27
|
|
|
* This class represents an consortium federation. |
|
28
|
|
|
* |
|
29
|
|
|
* It is semantically a country(!). Do not confuse this with a TLD; a federation |
|
30
|
|
|
* may span more than one TLD, and a TLD may be distributed across multiple federations. |
|
31
|
|
|
* |
|
32
|
|
|
* Example: a federation "fr" => "France" may also contain other TLDs which |
|
33
|
|
|
* belong to France in spite of their different TLD |
|
34
|
|
|
* Example 2: Domains ending in .edu are present in multiple different |
|
35
|
|
|
* federations |
|
36
|
|
|
* |
|
37
|
|
|
* @author Stefan Winter <[email protected]> |
|
38
|
|
|
* @author Tomasz Wolniewicz <[email protected]> |
|
39
|
|
|
* |
|
40
|
|
|
* @license see LICENSE file in root directory |
|
41
|
|
|
* |
|
42
|
|
|
* @package Developer |
|
43
|
|
|
*/ |
|
44
|
|
|
class Federation extends EntityWithDBProperties { |
|
45
|
|
|
|
|
46
|
|
|
/** |
|
47
|
|
|
* the handle to the FRONTEND database (only needed for some stats access) |
|
48
|
|
|
* |
|
49
|
|
|
* @var DBConnection |
|
50
|
|
|
*/ |
|
51
|
|
|
private $frontendHandle; |
|
52
|
|
|
|
|
53
|
|
|
/** |
|
54
|
|
|
* retrieve the statistics from the database in an internal array representation |
|
55
|
|
|
* |
|
56
|
|
|
* @return array |
|
57
|
|
|
*/ |
|
58
|
|
|
private function downloadStatsCore() { |
|
59
|
|
|
$grossAdmin = 0; |
|
60
|
|
|
$grossUser = 0; |
|
61
|
|
|
$grossSilverbullet = 0; |
|
62
|
|
|
$dataArray = []; |
|
63
|
|
|
// first, find out which profiles belong to this federation |
|
64
|
|
|
$cohesionQuery = "SELECT profile_id FROM profile, institution WHERE profile.inst_id = institution.inst_id AND institution.country = ?"; |
|
65
|
|
|
$profilesList = $this->databaseHandle->exec($cohesionQuery, "s", $this->identifier); |
|
66
|
|
|
$profilesArray = []; |
|
67
|
|
|
// SELECT -> resource is returned, no boolean |
|
68
|
|
|
while ($result = mysqli_fetch_object(/** @scrutinizer ignore-type */ $profilesList)) { |
|
69
|
|
|
$profilesArray[] = $result->profile_id; |
|
70
|
|
|
} |
|
71
|
|
|
foreach (\devices\Devices::listDevices() as $index => $deviceArray) { |
|
72
|
|
|
$countDevice = []; |
|
73
|
|
|
$countDevice['ADMIN'] = 0; |
|
74
|
|
|
$countDevice['SILVERBULLET'] = 0; |
|
75
|
|
|
$countDevice['USER'] = 0; |
|
76
|
|
|
foreach ($profilesArray as $profileNumber) { |
|
77
|
|
|
$deviceQuery = "SELECT downloads_admin, downloads_silverbullet, downloads_user FROM downloads WHERE device_id = ? AND profile_id = ?"; |
|
78
|
|
|
$statsList = $this->frontendHandle->exec($deviceQuery, "si", $index, $profileNumber); |
|
79
|
|
|
// SELECT -> resource, no boolean |
|
80
|
|
|
while ($queryResult = mysqli_fetch_object(/** @scrutinizer ignore-type */ $statsList)) { |
|
81
|
|
|
$countDevice['ADMIN'] = $countDevice['ADMIN'] + $queryResult->downloads_admin; |
|
82
|
|
|
$countDevice['SILVERBULLET'] = $countDevice['SILVERBULLET'] + $queryResult->downloads_silverbullet; |
|
83
|
|
|
$countDevice['USER'] = $countDevice['USER'] + $queryResult->downloads_user; |
|
84
|
|
|
$grossAdmin = $grossAdmin + $queryResult->downloads_admin; |
|
85
|
|
|
$grossSilverbullet = $grossSilverbullet + $queryResult->downloads_silverbullet; |
|
86
|
|
|
$grossUser = $grossUser + $queryResult->downloads_user; |
|
87
|
|
|
} |
|
88
|
|
|
$dataArray[$deviceArray['display']] = ["ADMIN" => $countDevice['ADMIN'], "SILVERBULLET" => $countDevice['SILVERBULLET'], "USER" => $countDevice['USER']]; |
|
89
|
|
|
} |
|
90
|
|
|
} |
|
91
|
|
|
$dataArray["TOTAL"] = ["ADMIN" => $grossAdmin, "SILVERBULLET" => $grossSilverbullet, "USER" => $grossUser]; |
|
92
|
|
|
return $dataArray; |
|
93
|
|
|
} |
|
94
|
|
|
|
|
95
|
|
|
/** |
|
96
|
|
|
* NOOP on Federations, but have to override the abstract parent method |
|
97
|
|
|
*/ |
|
98
|
|
|
public function updateFreshness() { |
|
99
|
|
|
// Federation is always fresh |
|
100
|
|
|
} |
|
101
|
|
|
|
|
102
|
|
|
/** |
|
103
|
|
|
* gets the download statistics for the federation |
|
104
|
|
|
* @param string $format either as an html *table* or *XML* |
|
105
|
|
|
* @return string |
|
106
|
|
|
*/ |
|
107
|
|
|
public function downloadStats($format) { |
|
108
|
|
|
$data = $this->downloadStatsCore(); |
|
109
|
|
|
$retstring = ""; |
|
110
|
|
|
|
|
111
|
|
|
switch ($format) { |
|
112
|
|
|
case "table": |
|
113
|
|
View Code Duplication |
foreach ($data as $device => $numbers) { |
|
|
|
|
|
|
114
|
|
|
if ($device == "TOTAL") { |
|
115
|
|
|
continue; |
|
116
|
|
|
} |
|
117
|
|
|
$retstring .= "<tr><td>$device</td><td>" . $numbers['ADMIN'] . "</td><td>" . $numbers['SILVERBULLET'] . "</td><td>" . $numbers['USER'] . "</td></tr>"; |
|
118
|
|
|
} |
|
119
|
|
|
$retstring .= "<tr><td><strong>TOTAL</strong></td><td><strong>" . $data['TOTAL']['ADMIN'] . "</strong></td><td><strong>" . $data['TOTAL']['SILVERBULLET'] . "</strong></td><td><strong>" . $data['TOTAL']['USER'] . "</strong></td></tr>"; |
|
120
|
|
|
break; |
|
121
|
|
|
case "XML": |
|
122
|
|
|
// the calls to date() operate on current date, so there is no chance for a FALSE to be returned. Silencing scrutinizer. |
|
123
|
|
|
$retstring .= "<federation id='$this->identifier' ts='" . /** @scrutinizer ignore-type */ date("Y-m-d") . "T" . /** @scrutinizer ignore-type */ date("H:i:s") . "'>\n"; |
|
124
|
|
View Code Duplication |
foreach ($data as $device => $numbers) { |
|
|
|
|
|
|
125
|
|
|
if ($device == "TOTAL") { |
|
126
|
|
|
continue; |
|
127
|
|
|
} |
|
128
|
|
|
$retstring .= " <device name='" . $device . "'>\n <downloads group='admin'>" . $numbers['ADMIN'] . "</downloads>\n <downloads group='managed_idp'>" . $numbers['SILVERBULLET'] . "</downloads>\n <downloads group='user'>" . $numbers['USER'] . "</downloads>\n </device>"; |
|
129
|
|
|
} |
|
130
|
|
|
$retstring .= "<total>\n <downloads group='admin'>" . $data['TOTAL']['ADMIN'] . "</downloads>\n <downloads group='managed_idp'>" . $data['TOTAL']['SILVERBULLET'] . "</downloads>\n <downloads group='user'>" . $data['TOTAL']['USER'] . "</downloads>\n</total>\n"; |
|
131
|
|
|
$retstring .= "</federation>"; |
|
132
|
|
|
break; |
|
133
|
|
|
default: |
|
134
|
|
|
throw new Exception("Statistics can be requested only in 'table' or 'XML' format!"); |
|
135
|
|
|
} |
|
136
|
|
|
|
|
137
|
|
|
return $retstring; |
|
138
|
|
|
} |
|
139
|
|
|
|
|
140
|
|
|
/** |
|
141
|
|
|
* |
|
142
|
|
|
* Constructs a Federation object. |
|
143
|
|
|
* |
|
144
|
|
|
* @param string $fedname - textual representation of the Federation object |
|
145
|
|
|
* Example: "lu" (for Luxembourg) |
|
146
|
|
|
*/ |
|
147
|
|
|
public function __construct($fedname = "") { |
|
148
|
|
|
|
|
149
|
|
|
// initialise the superclass variables |
|
150
|
|
|
|
|
151
|
|
|
$this->databaseType = "INST"; |
|
152
|
|
|
$this->entityOptionTable = "federation_option"; |
|
153
|
|
|
$this->entityIdColumn = "federation_id"; |
|
154
|
|
|
|
|
155
|
|
|
$cat = new CAT(); |
|
156
|
|
|
if (!isset($cat->knownFederations[$fedname])) { |
|
157
|
|
|
throw new Exception("This federation is not known to the system!"); |
|
158
|
|
|
} |
|
159
|
|
|
$this->identifier = $fedname; |
|
160
|
|
|
$this->name = $cat->knownFederations[$this->identifier]; |
|
161
|
|
|
|
|
162
|
|
|
parent::__construct(); // we now have access to our database handle |
|
163
|
|
|
|
|
164
|
|
|
$this->frontendHandle = DBConnection::handle("FRONTEND"); |
|
165
|
|
|
|
|
166
|
|
|
// fetch attributes from DB; populates $this->attributes array |
|
167
|
|
|
$this->attributes = $this->retrieveOptionsFromDatabase("SELECT DISTINCT option_name, option_lang, option_value, row |
|
168
|
|
|
FROM $this->entityOptionTable |
|
169
|
|
|
WHERE $this->entityIdColumn = ? |
|
170
|
|
|
ORDER BY option_name", "FED", "s", $this->identifier); |
|
171
|
|
|
|
|
172
|
|
|
|
|
173
|
|
|
$this->attributes[] = array("name" => "internal:country", |
|
174
|
|
|
"lang" => NULL, |
|
175
|
|
|
"value" => $this->identifier, |
|
176
|
|
|
"level" => "FED", |
|
177
|
|
|
"row" => 0, |
|
178
|
|
|
"flag" => NULL); |
|
179
|
|
|
} |
|
180
|
|
|
|
|
181
|
|
|
/** |
|
182
|
|
|
* Creates a new IdP inside the federation. |
|
183
|
|
|
* |
|
184
|
|
|
* @param string $ownerId Persistent identifier of the user for whom this IdP is created (first administrator) |
|
185
|
|
|
* @param string $level Privilege level of the first administrator (was he blessed by a federation admin or a peer?) |
|
186
|
|
|
* @param string $mail e-mail address with which the user was invited to administer (useful for later user identification if the user chooses a "funny" real name) |
|
187
|
|
|
* @return int identifier of the new IdP |
|
188
|
|
|
*/ |
|
189
|
|
|
public function newIdP($ownerId, $level, $mail) { |
|
190
|
|
|
$this->databaseHandle->exec("INSERT INTO institution (country) VALUES('$this->identifier')"); |
|
191
|
|
|
$identifier = $this->databaseHandle->lastID(); |
|
192
|
|
|
|
|
193
|
|
|
if ($identifier == 0 || !$this->loggerInstance->writeAudit($ownerId, "NEW", "IdP $identifier")) { |
|
194
|
|
|
$text = "<p>Could not create a new " . CONFIG_CONFASSISTANT['CONSORTIUM']['nomenclature_inst'] . "!</p>"; |
|
195
|
|
|
echo $text; |
|
196
|
|
|
throw new Exception($text); |
|
197
|
|
|
} |
|
198
|
|
|
|
|
199
|
|
|
if ($ownerId != "PENDING") { |
|
200
|
|
|
$this->databaseHandle->exec("INSERT INTO ownership (user_id,institution_id, blesslevel, orig_mail) VALUES(?,?,?,?)", "siss", $ownerId, $identifier, $level, $mail); |
|
201
|
|
|
} |
|
202
|
|
|
return $identifier; |
|
203
|
|
|
} |
|
204
|
|
|
|
|
205
|
|
|
/** |
|
206
|
|
|
* Lists all Identity Providers in this federation |
|
207
|
|
|
* |
|
208
|
|
|
* @param int $activeOnly if set to non-zero will list only those institutions which have some valid profiles defined. |
|
209
|
|
|
* @return array (Array of IdP instances) |
|
210
|
|
|
* |
|
211
|
|
|
*/ |
|
212
|
|
|
public function listIdentityProviders($activeOnly = 0) { |
|
213
|
|
|
// default query is: |
|
214
|
|
|
$allIDPs = $this->databaseHandle->exec("SELECT inst_id FROM institution |
|
215
|
|
|
WHERE country = '$this->identifier' ORDER BY inst_id"); |
|
216
|
|
|
// the one for activeOnly is much more complex: |
|
217
|
|
|
if ($activeOnly) { |
|
218
|
|
|
$allIDPs = $this->databaseHandle->exec("SELECT distinct institution.inst_id AS inst_id |
|
219
|
|
|
FROM institution |
|
220
|
|
|
JOIN profile ON institution.inst_id = profile.inst_id |
|
221
|
|
|
WHERE institution.country = '$this->identifier' |
|
222
|
|
|
AND profile.showtime = 1 |
|
223
|
|
|
ORDER BY inst_id"); |
|
224
|
|
|
} |
|
225
|
|
|
|
|
226
|
|
|
$returnarray = []; |
|
227
|
|
|
// SELECT -> resource, not boolean |
|
228
|
|
|
while ($idpQuery = mysqli_fetch_object(/** @scrutinizer ignore-type */ $allIDPs)) { |
|
229
|
|
|
$idp = new IdP($idpQuery->inst_id); |
|
230
|
|
|
$name = $idp->name; |
|
231
|
|
|
$idpInfo = ['entityID' => $idp->identifier, |
|
232
|
|
|
'title' => $name, |
|
233
|
|
|
'country' => strtoupper($idp->federation), |
|
234
|
|
|
'instance' => $idp]; |
|
235
|
|
|
$returnarray[$idp->identifier] = $idpInfo; |
|
236
|
|
|
} |
|
237
|
|
|
return $returnarray; |
|
238
|
|
|
} |
|
239
|
|
|
|
|
240
|
|
|
/** |
|
241
|
|
|
* returns an array with information about the authorised administrators of the federation |
|
242
|
|
|
* |
|
243
|
|
|
* @return array |
|
244
|
|
|
*/ |
|
245
|
|
|
public function listFederationAdmins() { |
|
246
|
|
|
$returnarray = []; |
|
247
|
|
|
$query = "SELECT user_id FROM user_options WHERE option_name = 'user:fedadmin' AND option_value = ?"; |
|
248
|
|
|
if (CONFIG_CONFASSISTANT['CONSORTIUM']['name'] == "eduroam" && isset(CONFIG_CONFASSISTANT['CONSORTIUM']['deployment-voodoo']) && CONFIG_CONFASSISTANT['CONSORTIUM']['deployment-voodoo'] == "Operations Team") { // SW: APPROVED |
|
249
|
|
|
$query = "SELECT eptid as user_id FROM view_admin WHERE role = 'fedadmin' AND realm = ?"; |
|
250
|
|
|
} |
|
251
|
|
|
$userHandle = DBConnection::handle("USER"); // we need something from the USER database for a change |
|
252
|
|
|
$upperFed = strtoupper($this->identifier); |
|
253
|
|
|
// SELECT -> resource, not boolean |
|
254
|
|
|
$admins = $userHandle->exec($query, "s", $upperFed); |
|
255
|
|
|
|
|
256
|
|
|
while ($fedAdminQuery = mysqli_fetch_object(/** @scrutinizer ignore-type */ $admins)) { |
|
257
|
|
|
$returnarray[] = $fedAdminQuery->user_id; |
|
258
|
|
|
} |
|
259
|
|
|
return $returnarray; |
|
260
|
|
|
} |
|
261
|
|
|
|
|
262
|
|
|
/** |
|
263
|
|
|
* cross-checks in the EXTERNAL customer DB which institutions exist there for the federations |
|
264
|
|
|
* |
|
265
|
|
|
* @param bool $unmappedOnly if set to TRUE, only returns those which do not have a known mapping to our internally known institutions |
|
266
|
|
|
* @return array |
|
267
|
|
|
*/ |
|
268
|
|
|
public function listExternalEntities($unmappedOnly) { |
|
269
|
|
|
$returnarray = []; |
|
270
|
|
|
|
|
271
|
|
|
if (CONFIG_CONFASSISTANT['CONSORTIUM']['name'] == "eduroam" && isset(CONFIG_CONFASSISTANT['CONSORTIUM']['deployment-voodoo']) && CONFIG_CONFASSISTANT['CONSORTIUM']['deployment-voodoo'] == "Operations Team") { // SW: APPROVED |
|
272
|
|
|
$usedarray = []; |
|
273
|
|
|
$query = "SELECT id_institution AS id, country, inst_realm as realmlist, name AS collapsed_name, contact AS collapsed_contact FROM view_active_idp_institution WHERE country = ?"; |
|
274
|
|
|
|
|
275
|
|
|
|
|
276
|
|
|
$externalHandle = DBConnection::handle("EXTERNAL"); |
|
277
|
|
|
$externals = $externalHandle->exec($query, "s", $this->identifier); |
|
278
|
|
|
$syncstate = IdP::EXTERNAL_DB_SYNCSTATE_SYNCED; |
|
279
|
|
|
$alreadyUsed = $this->databaseHandle->exec("SELECT DISTINCT external_db_id FROM institution |
|
280
|
|
|
WHERE external_db_id IS NOT NULL |
|
281
|
|
|
AND external_db_syncstate = ?", "i", $syncstate); |
|
282
|
|
|
$pendingInvite = $this->databaseHandle->exec("SELECT DISTINCT external_db_uniquehandle FROM invitations |
|
283
|
|
|
WHERE external_db_uniquehandle IS NOT NULL |
|
284
|
|
|
AND invite_created >= TIMESTAMPADD(DAY, -1, NOW()) |
|
285
|
|
|
AND used = 0"); |
|
286
|
|
|
// SELECT -> resource, no boolean |
|
287
|
|
|
while ($alreadyUsedQuery = mysqli_fetch_object(/** @scrutinizer ignore-type */ $alreadyUsed)) { |
|
288
|
|
|
$usedarray[] = $alreadyUsedQuery->external_db_id; |
|
289
|
|
|
} |
|
290
|
|
|
// SELECT -> resource, no boolean |
|
291
|
|
|
while ($pendingInviteQuery = mysqli_fetch_object(/** @scrutinizer ignore-type */ $pendingInvite)) { |
|
292
|
|
|
if (!in_array($pendingInviteQuery->external_db_uniquehandle, $usedarray)) { |
|
293
|
|
|
$usedarray[] = $pendingInviteQuery->external_db_uniquehandle; |
|
294
|
|
|
} |
|
295
|
|
|
} |
|
296
|
|
|
// was a SELECT query, so a resource and not a boolean |
|
297
|
|
|
while ($externalQuery = mysqli_fetch_object(/** @scrutinizer ignore-type */ $externals)) { |
|
298
|
|
|
if (($unmappedOnly === TRUE) && (in_array($externalQuery->id, $usedarray))) { |
|
299
|
|
|
continue; |
|
300
|
|
|
} |
|
301
|
|
|
$names = explode('#', $externalQuery->collapsed_name); |
|
302
|
|
|
// trim name list to current best language match |
|
303
|
|
|
$availableLanguages = []; |
|
304
|
|
|
foreach ($names as $name) { |
|
305
|
|
|
$thislang = explode(': ', $name, 2); |
|
306
|
|
|
$availableLanguages[$thislang[0]] = $thislang[1]; |
|
307
|
|
|
} |
|
308
|
|
|
if (array_key_exists($this->languageInstance->getLang(), $availableLanguages)) { |
|
309
|
|
|
$thelangauge = $availableLanguages[$this->languageInstance->getLang()]; |
|
310
|
|
|
} else if (array_key_exists("en", $availableLanguages)) { |
|
311
|
|
|
$thelangauge = $availableLanguages["en"]; |
|
312
|
|
|
} else { // whatever. Pick one out of the list |
|
313
|
|
|
$thelangauge = array_pop($availableLanguages); |
|
314
|
|
|
} |
|
315
|
|
|
$contacts = explode('#', $externalQuery->collapsed_contact); |
|
316
|
|
|
|
|
317
|
|
|
|
|
318
|
|
|
$mailnames = ""; |
|
319
|
|
|
foreach ($contacts as $contact) { |
|
320
|
|
|
$matches = []; |
|
321
|
|
|
preg_match("/^n: (.*), e: (.*), p: .*$/", $contact, $matches); |
|
322
|
|
|
if ($matches[2] != "") { |
|
323
|
|
|
if ($mailnames != "") { |
|
324
|
|
|
$mailnames .= ", "; |
|
325
|
|
|
} |
|
326
|
|
|
// extracting real names is nice, but the <> notation |
|
327
|
|
|
// really gets screwed up on POSTs and HTML safety |
|
328
|
|
|
// so better not do this; use only mail addresses |
|
329
|
|
|
$mailnames .= $matches[2]; |
|
330
|
|
|
} |
|
331
|
|
|
} |
|
332
|
|
|
$returnarray[] = ["ID" => $externalQuery->id, "name" => $thelangauge, "contactlist" => $mailnames, "country" => $externalQuery->country, "realmlist" => $externalQuery->realmlist]; |
|
333
|
|
|
} |
|
334
|
|
|
usort($returnarray, array($this, "usortInstitution")); |
|
335
|
|
|
} |
|
336
|
|
|
return $returnarray; |
|
337
|
|
|
} |
|
338
|
|
|
|
|
339
|
|
|
const UNKNOWN_IDP = -1; |
|
340
|
|
|
const AMBIGUOUS_IDP = -2; |
|
341
|
|
|
|
|
342
|
|
|
/** |
|
343
|
|
|
* for a MySQL list of institutions, find an institution or find out that |
|
344
|
|
|
* there is no single best match |
|
345
|
|
|
* |
|
346
|
|
|
* @param \mysqli_result $dbResult |
|
347
|
|
|
* @param string $country used to return the country of the inst, if can be found out |
|
348
|
|
|
* @return int the identifier of the inst, or one of the special return values if unsuccessful |
|
349
|
|
|
*/ |
|
350
|
|
|
private static function findCandidates(\mysqli_result $dbResult, &$country) { |
|
351
|
|
|
$retArray = []; |
|
352
|
|
|
while ($row = mysqli_fetch_object($dbResult)) { |
|
353
|
|
|
if (!in_array($row->id, $retArray)) { |
|
354
|
|
|
$retArray[] = $row->id; |
|
355
|
|
|
$country = strtoupper($row->country); |
|
356
|
|
|
} |
|
357
|
|
|
} |
|
358
|
|
|
if (count($retArray) <= 0) { |
|
359
|
|
|
return Federation::UNKNOWN_IDP; |
|
360
|
|
|
} |
|
361
|
|
|
if (count($retArray) > 1) { |
|
362
|
|
|
return Federation::AMBIGUOUS_IDP; |
|
363
|
|
|
} |
|
364
|
|
|
|
|
365
|
|
|
return array_pop($retArray); |
|
366
|
|
|
} |
|
367
|
|
|
|
|
368
|
|
|
/** |
|
369
|
|
|
* If we are running diagnostics, our input from the user is the realm. We |
|
370
|
|
|
* need to find out which IdP this realm belongs to. |
|
371
|
|
|
* @param string $realm the realm to search for |
|
372
|
|
|
* @return array an array with two entries, CAT ID and DB ID, with either the respective ID of the IdP in the system, or UNKNOWN_IDP or AMBIGUOUS_IDP |
|
373
|
|
|
*/ |
|
374
|
|
|
public static function determineIdPIdByRealm($realm) { |
|
375
|
|
|
$country = NULL; |
|
376
|
|
|
$candidatesExternalDb = Federation::UNKNOWN_IDP; |
|
377
|
|
|
$dbHandle = DBConnection::handle("INST"); |
|
378
|
|
|
$realmSearchStringCat = "%@$realm"; |
|
379
|
|
|
$candidateCatQuery = $dbHandle->exec("SELECT p.profile_id as id, i.country as country FROM profile p, institution i WHERE p.inst_id = i.inst_id AND p.realm LIKE ?", "s", $realmSearchStringCat); |
|
380
|
|
|
// this is a SELECT returning a resource, not a boolean |
|
381
|
|
|
$candidatesCat = Federation::findCandidates(/** @scrutinizer ignore-type */ $candidateCatQuery, $country); |
|
382
|
|
|
|
|
383
|
|
|
if (CONFIG_CONFASSISTANT['CONSORTIUM']['name'] == "eduroam" && isset(CONFIG_CONFASSISTANT['CONSORTIUM']['deployment-voodoo']) && CONFIG_CONFASSISTANT['CONSORTIUM']['deployment-voodoo'] == "Operations Team") { // SW: APPROVED |
|
384
|
|
|
$externalHandle = DBConnection::handle("EXTERNAL"); |
|
385
|
|
|
$realmSearchStringDb1 = "$realm"; |
|
386
|
|
|
$realmSearchStringDb2 = "%,$realm"; |
|
387
|
|
|
$realmSearchStringDb3 = "$realm,%"; |
|
388
|
|
|
$realmSearchStringDb4 = "%,$realm,%"; |
|
389
|
|
|
$candidateExternalQuery = $externalHandle->exec("SELECT id_institution as id, country FROM view_active_idp_institution WHERE inst_realm LIKE ? or inst_realm LIKE ? or inst_realm LIKE ? or inst_realm LIKE ?", "ssss", $realmSearchStringDb1, $realmSearchStringDb2, $realmSearchStringDb3, $realmSearchStringDb4); |
|
390
|
|
|
// SELECT -> resource, not boolean |
|
391
|
|
|
$candidatesExternalDb = Federation::findCandidates(/** @scrutinizer ignore-type */ $candidateExternalQuery, $country); |
|
392
|
|
|
} |
|
393
|
|
|
|
|
394
|
|
|
return ["CAT" => $candidatesCat, "EXTERNAL" => $candidatesExternalDb, "FEDERATION" => $country]; |
|
395
|
|
|
} |
|
396
|
|
|
|
|
397
|
|
|
/** |
|
398
|
|
|
* helper function to sort institutions by their name |
|
399
|
|
|
* @param array $a an array with institution a's information |
|
400
|
|
|
* @param array $b an array with institution b's information |
|
401
|
|
|
* @return int the comparison result |
|
402
|
|
|
*/ |
|
403
|
|
|
private function usortInstitution($a, $b) { |
|
404
|
|
|
return strcasecmp($a["name"], $b["name"]); |
|
405
|
|
|
} |
|
406
|
|
|
|
|
407
|
|
|
} |
|
408
|
|
|
|
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.