| Total Complexity | 88 |
| Total Lines | 658 |
| Duplicated Lines | 0 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Complex classes like UserManagement often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use UserManagement, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 49 | class UserManagement extends \core\common\Entity |
||
| 50 | { |
||
| 51 | |||
| 52 | /** |
||
| 53 | * our handle to the INST database |
||
| 54 | * |
||
| 55 | * @var DBConnection |
||
| 56 | */ |
||
| 57 | private $databaseHandle; |
||
| 58 | public $currentInstitutions; |
||
| 59 | public $newUser = false; |
||
| 60 | public $hasPotenialNewInst = false; |
||
| 61 | |||
| 62 | /** |
||
| 63 | * Class constructor. Nothing special to be done when constructing. |
||
| 64 | * |
||
| 65 | * @throws Exception |
||
| 66 | */ |
||
| 67 | public function __construct() |
||
| 68 | { |
||
| 69 | parent::__construct(); |
||
| 70 | $handle = DBConnection::handle(self::$databaseType); |
||
| 71 | if ($handle instanceof DBConnection) { |
||
| 72 | $this->databaseHandle = $handle; |
||
| 73 | } else { |
||
| 74 | throw new Exception("This database type is never an array!"); |
||
| 75 | } |
||
| 76 | } |
||
| 77 | |||
| 78 | /** |
||
| 79 | * database which this class queries by default |
||
| 80 | * |
||
| 81 | * @var string |
||
| 82 | */ |
||
| 83 | private static $databaseType = "INST"; |
||
| 84 | |||
| 85 | const TOKENSTATUS_OK_NEW = 1; |
||
| 86 | const TOKENSTATUS_OK_EXISTING = 2; |
||
| 87 | const TOKENSTATUS_FAIL_ALREADYCONSUMED = -1; |
||
| 88 | const TOKENSTATUS_FAIL_EXPIRED = -2; |
||
| 89 | const TOKENSTATUS_FAIL_NONEXISTING = -3; |
||
| 90 | |||
| 91 | /** |
||
| 92 | * Checks if a given invitation token exists and is valid in the invitations database |
||
| 93 | * returns a string with the following values: |
||
| 94 | * |
||
| 95 | * OK-NEW valid token exists, and is not attached to an existing institution. When consuming the token, a new inst will be created |
||
| 96 | * OK-EXISTING valid token exists, and is attached to an existing institution. When consuming the token, user will be added as an admin |
||
| 97 | * FAIL-NONEXISTINGTOKEN this token does not exist at all in the database |
||
| 98 | * FAIL-ALREADYCONSUMED the token exists, but has been used before |
||
| 99 | * FAIL-EXPIRED the token exists, but has expired |
||
| 100 | * |
||
| 101 | * @param string $token the invitation token |
||
| 102 | * @return int |
||
| 103 | */ |
||
| 104 | public function checkTokenValidity($token) |
||
| 105 | { |
||
| 106 | $check = $this->databaseHandle->exec("SELECT invite_token, cat_institution_id |
||
| 107 | FROM invitations |
||
| 108 | WHERE invite_token = ? AND invite_created >= TIMESTAMPADD(DAY, -1, NOW()) AND used = 0", "s", $token); |
||
| 109 | // SELECT -> resource, not boolean |
||
| 110 | if ($tokenCheck = mysqli_fetch_object(/** @scrutinizer ignore-type */ $check)) { |
||
| 111 | if ($tokenCheck->cat_institution_id === NULL) { |
||
| 112 | return self::TOKENSTATUS_OK_NEW; |
||
| 113 | } |
||
| 114 | return self::TOKENSTATUS_OK_EXISTING; |
||
| 115 | } |
||
| 116 | // if we haven't returned from the function yet, it is an invalid token... |
||
| 117 | // be a little verbose what's wrong with it |
||
| 118 | $checkReason = $this->databaseHandle->exec("SELECT invite_token, used FROM invitations WHERE invite_token = ?", "s", $token); |
||
| 119 | // SELECT -> resource, not boolean |
||
| 120 | if ($invalidTokenCheck = mysqli_fetch_object(/** @scrutinizer ignore-type */ $checkReason)) { |
||
| 121 | if ($invalidTokenCheck->used == 1) { |
||
| 122 | return self::TOKENSTATUS_FAIL_ALREADYCONSUMED; |
||
| 123 | } |
||
| 124 | return self::TOKENSTATUS_FAIL_EXPIRED; |
||
| 125 | } |
||
| 126 | return self::TOKENSTATUS_FAIL_NONEXISTING; |
||
| 127 | } |
||
| 128 | |||
| 129 | /** |
||
| 130 | * This function creates a new IdP in the database based on a valid invitation token - or adds a new administrator |
||
| 131 | * to an existing one. The institution is created for the logged-in user (second argument) who presents the token (first |
||
| 132 | * argument). The tokens are created via createToken(). |
||
| 133 | * |
||
| 134 | * @param string $token The invitation token (must exist in the database and be valid). |
||
| 135 | * @param string $owner Persistent User ID who becomes the administrator of the institution |
||
| 136 | * @return IdP |
||
| 137 | */ |
||
| 138 | public function createIdPFromToken(string $token, string $owner) |
||
| 139 | { |
||
| 140 | new CAT(); // be sure that Entity's static members are initialised |
||
| 141 | common\Entity::intoThePotatoes(); |
||
| 142 | // the token either has cat_institution_id set -> new admin for existing inst |
||
| 143 | // or contains a number of parameters from external DB -> set up new inst |
||
| 144 | $instinfo = $this->databaseHandle->exec("SELECT cat_institution_id, country, name, invite_issuer_level, invite_dest_mail, external_db_uniquehandle, invite_fortype |
||
| 145 | FROM invitations |
||
| 146 | WHERE invite_token = ? AND invite_created >= TIMESTAMPADD(DAY, -1, NOW()) AND used = 0", "s", $token); |
||
| 147 | // SELECT -> resource, no boolean |
||
| 148 | if ($invitationDetails = mysqli_fetch_assoc(/** @scrutinizer ignore-type */ $instinfo)) { |
||
| 149 | if ($invitationDetails['cat_institution_id'] !== NULL) { // add new admin to existing IdP |
||
| 150 | // we can't rely on a unique key on this table (user IDs |
||
| 151 | // possibly too long), so run a query to find there's an |
||
| 152 | // tuple already; and act accordingly |
||
| 153 | $catId = $invitationDetails['cat_institution_id']; |
||
| 154 | $level = $invitationDetails['invite_issuer_level']; |
||
| 155 | $destMail = $invitationDetails['invite_dest_mail']; |
||
| 156 | $existing = $this->databaseHandle->exec("SELECT user_id FROM ownership WHERE user_id = ? AND institution_id = ?", "si", $owner, $catId); |
||
| 157 | // SELECT -> resource, not boolean |
||
| 158 | if (mysqli_num_rows(/** @scrutinizer ignore-type */ $existing) > 0) { |
||
| 159 | $this->databaseHandle->exec("UPDATE ownership SET blesslevel = ?, orig_mail = ? WHERE user_id = ? AND institution_id = ?", "sssi", $level, $destMail, $owner, $catId); |
||
| 160 | } else { |
||
| 161 | $this->databaseHandle->exec("INSERT INTO ownership (user_id, institution_id, blesslevel, orig_mail) VALUES(?, ?, ?, ?)", "siss", $owner, $catId, $level, $destMail); |
||
| 162 | } |
||
| 163 | common\Logging::writeAudit_s((string) $owner, "OWN", "IdP " . $invitationDetails['cat_institution_id'] . " - added user as owner"); |
||
| 164 | common\Entity::outOfThePotatoes(); |
||
| 165 | return new IdP($invitationDetails['cat_institution_id']); |
||
| 166 | } |
||
| 167 | // create new IdP |
||
| 168 | $fed = new Federation($invitationDetails['country']); |
||
| 169 | // find the best name for the entity: C if specified, otherwise English, otherwise whatever |
||
| 170 | if ($invitationDetails['external_db_uniquehandle'] != NULL) { |
||
| 171 | $idp = $this->newIdPFromExternal($invitationDetails['external_db_uniquehandle'], $fed, $invitationDetails, $owner); |
||
| 172 | } else { |
||
| 173 | $bestnameguess = $invitationDetails['name']; |
||
| 174 | $idp = new IdP($fed->newIdP('TOKEN', $invitationDetails['invite_fortype'], $owner, $invitationDetails['invite_issuer_level'], $invitationDetails['invite_dest_mail'], $bestnameguess)); |
||
| 175 | $idp->addAttribute("general:instname", 'C', $bestnameguess); |
||
| 176 | } |
||
| 177 | common\Logging::writeAudit_s($owner, "NEW", "IdP " . $idp->identifier . " - created from invitation"); |
||
| 178 | |||
| 179 | // in case we have more admins in the queue which were invited to |
||
| 180 | // administer the same inst but haven't redeemed their invitations |
||
| 181 | // yet, then we will have to rewrite the invitations to point to the |
||
| 182 | // newly created actual IdP rather than the placeholder entry in the |
||
| 183 | // invitations table |
||
| 184 | // which other pending invites do we have? |
||
| 185 | |||
| 186 | $otherPending = $this->databaseHandle->exec("SELECT id |
||
| 187 | FROM invitations |
||
| 188 | WHERE invite_created >= TIMESTAMPADD(DAY, -1, NOW()) AND used = 0 AND name = ? AND country = ? AND ( cat_institution_id IS NULL OR external_db_uniquehandle IS NULL ) ", "ss", $invitationDetails['name'], $invitationDetails['country']); |
||
| 189 | // SELECT -> resource, no boolean |
||
| 190 | while ($pendingDetail = mysqli_fetch_object(/** @scrutinizer ignore-type */ $otherPending)) { |
||
| 191 | $this->databaseHandle->exec("UPDATE invitations SET cat_institution_id = " . $idp->identifier . " WHERE id = " . $pendingDetail->id); |
||
| 192 | } |
||
| 193 | common\Entity::outOfThePotatoes(); |
||
| 194 | return $idp; |
||
| 195 | } |
||
| 196 | } |
||
| 197 | |||
| 198 | /** |
||
| 199 | * create new institution based on the edxternalDB data |
||
| 200 | * @param string $extId - the eduroam database identifier |
||
| 201 | * @param object $fed - the CAT federation object where the institution should be created |
||
| 202 | * @param string $owner |
||
| 203 | * @return type |
||
| 204 | */ |
||
| 205 | public function createIdPFromExternal($extId, $fed, $owner) |
||
| 218 | } |
||
| 219 | |||
| 220 | /* |
||
| 221 | * This is the common part of the code for createIdPFromToken and createIdPFromExternal |
||
| 222 | */ |
||
| 223 | private function newIdPFromExternal($extId, $fed, $invitationDetails, $owner, $externalinfo = []) |
||
| 239 | } |
||
| 240 | |||
| 241 | /** |
||
| 242 | * Adds a new administrator to an existing IdP |
||
| 243 | * @param IdP $idp institution to which the admin is to be added. |
||
| 244 | * @param string $user persistent user ID that is to be added as an admin. |
||
| 245 | * @return boolean This function always returns TRUE. |
||
| 246 | */ |
||
| 247 | public function addAdminToIdp($idp, $user) |
||
| 248 | { |
||
| 249 | $existing = $this->databaseHandle->exec("SELECT user_id FROM ownership WHERE user_id = ? AND institution_id = ?", "si", $user, $idp->identifier); |
||
| 250 | // SELECT -> resource, not boolean |
||
| 251 | if (mysqli_num_rows(/** @scrutinizer ignore-type */ $existing) == 0) { |
||
| 252 | $this->databaseHandle->exec("INSERT INTO ownership (institution_id,user_id,blesslevel,orig_mail) VALUES(?, ?, 'FED', 'SELF-APPOINTED')", "is", $idp->identifier, $user); |
||
| 253 | } |
||
| 254 | return TRUE; |
||
| 255 | } |
||
| 256 | |||
| 257 | /** |
||
| 258 | * Deletes an administrator from the IdP. If the IdP and user combination doesn't match, nothing happens. |
||
| 259 | * @param IdP $idp institution from which the admin is to be deleted. |
||
| 260 | * @param string $user persistent user ID that is to be deleted as an admin. |
||
| 261 | * @return boolean This function always returns TRUE. |
||
| 262 | */ |
||
| 263 | public function removeAdminFromIdP($idp, $user) |
||
| 264 | { |
||
| 265 | $this->databaseHandle->exec("DELETE from ownership WHERE institution_id = $idp->identifier AND user_id = ?", "s", $user); |
||
| 266 | return TRUE; |
||
| 267 | } |
||
| 268 | |||
| 269 | /** |
||
| 270 | * Invalidates a token so that it can't be used any more. Tokens automatically expire after 24h, but can be invalidated |
||
| 271 | * earlier, e.g. after having been used to create an institution. If the token doesn't exist in the DB or is already invalidated, |
||
| 272 | * nothing happens. |
||
| 273 | * |
||
| 274 | * @param string $token the token to invalidate |
||
| 275 | * @return boolean This function always returns TRUE. |
||
| 276 | */ |
||
| 277 | public function invalidateToken($token) |
||
| 281 | } |
||
| 282 | |||
| 283 | /** |
||
| 284 | * Creates a new invitation token. The token's main purpose is to be sent out by mail. The function either can generate a token for a new |
||
| 285 | * administrator of an existing institution, or for a new institution. In the latter case, the institution only actually gets |
||
| 286 | * created in the DB if the token is actually consumed via createIdPFromToken(). |
||
| 287 | * |
||
| 288 | * @param boolean $isByFedadmin is the invitation token created from a federation admin (TRUE) or from an existing inst admin (FALSE) |
||
| 289 | * @param array $for identifiers (typically email addresses) for which the invitation is created |
||
| 290 | * @param mixed $instIdentifier either an instance of the IdP class (for existing institutions to invite new admins) or a string (new institution - this is the inst name then) |
||
| 291 | * @param string $externalId if the IdP to be created is related to an external DB entity, this parameter contains that ID |
||
| 292 | * @param string $country if the institution is new (i.e. $inst is a string) this parameter needs to specify the federation of the new inst |
||
| 293 | * @param string $partType the type of participant |
||
| 294 | * @return mixed The function returns either the token (as string) or FALSE if something went wrong |
||
| 295 | * @throws Exception |
||
| 296 | */ |
||
| 297 | public function createTokens($isByFedadmin, $for, $instIdentifier, $externalId = 0, $country = 0, $partType = 0) |
||
| 298 | { |
||
| 299 | $level = ($isByFedadmin ? "FED" : "INST"); |
||
| 300 | $tokenList = []; |
||
| 301 | foreach ($for as $oneDest) { |
||
| 302 | $token = bin2hex(random_bytes(40)); |
||
| 303 | if ($instIdentifier instanceof IdP) { |
||
| 304 | $this->databaseHandle->exec("INSERT INTO invitations (invite_fortype, invite_issuer_level, invite_dest_mail, invite_token,cat_institution_id) VALUES(?, ?, ?, ?, ?)", "ssssi", $instIdentifier->type, $level, $oneDest, $token, $instIdentifier->identifier); |
||
| 305 | $tokenList[$token] = $oneDest; |
||
| 306 | } else if (func_num_args() == 5) { |
||
| 307 | $ROid = strtoupper($country).'01'; |
||
| 308 | $cat = new CAT(); |
||
| 309 | $extinfo = $cat->getExternalDBEntityDetails($externalId, $ROid); |
||
| 310 | $extCountry = $extinfo['country']; |
||
| 311 | $extType = $extinfo['type']; |
||
| 312 | if(\config\Master::FUNCTIONALITY_FLAGS['SINGLE_SERVICE'] === 'MSP') { |
||
| 313 | $extType = \core\IdP::TYPE_SP; |
||
| 314 | } |
||
| 315 | $this->databaseHandle->exec("INSERT INTO invitations (invite_fortype, invite_issuer_level, invite_dest_mail, invite_token,name,country, external_db_uniquehandle) VALUES(?, ?, ?, ?, ?, ?, ?)", "sssssss", $extType, $level, $oneDest, $token, $instIdentifier, $extCountry, $externalId); |
||
| 316 | $tokenList[$token] = $oneDest; |
||
| 317 | } else if (func_num_args() == 6) { // string name, and country set - whole new IdP |
||
| 318 | $this->databaseHandle->exec("INSERT INTO invitations (invite_fortype, invite_issuer_level, invite_dest_mail, invite_token,name,country) VALUES(?, ?, ?, ?, ?, ?)", "ssssss", $partType, $level, $oneDest, $token, $instIdentifier, $country); |
||
| 319 | $tokenList[$token] = $oneDest; |
||
| 320 | } else { |
||
| 321 | throw new Exception("The invitation is somehow ... wrong."); |
||
| 322 | } |
||
| 323 | } |
||
| 324 | if (count($for) != count($tokenList)) { |
||
| 325 | throw new Exception("Creation of a new token failed!"); |
||
| 326 | } |
||
| 327 | return $tokenList; |
||
| 328 | } |
||
| 329 | |||
| 330 | /** |
||
| 331 | * Retrieves all pending invitations for an institution or for a federation. |
||
| 332 | * |
||
| 333 | * @param int $idpIdentifier the identifier of the institution. If not set, returns invitations for not-yet-created insts |
||
| 334 | * @return array if idp_identifier is set: an array of strings (mail addresses); otherwise an array of tuples (country;name;mail) |
||
| 335 | */ |
||
| 336 | public function listPendingInvitations($idpIdentifier = 0) |
||
| 337 | { |
||
| 338 | $retval = []; |
||
| 339 | $invitations = $this->databaseHandle->exec("SELECT cat_institution_id, country, name, invite_issuer_level, invite_dest_mail, invite_token , TIMESTAMPADD(DAY, 1, invite_created) as expiry |
||
| 340 | FROM invitations |
||
| 341 | WHERE cat_institution_id " . ( $idpIdentifier != 0 ? "= $idpIdentifier" : "IS NULL") . " AND invite_created >= TIMESTAMPADD(DAY, -1, NOW()) AND used = 0"); |
||
| 342 | // SELECT -> resource, not boolean |
||
| 343 | common\Logging::debug_s(4, "Retrieving pending invitations for " . ($idpIdentifier != 0 ? "IdP $idpIdentifier" : "IdPs awaiting initial creation" ) . ".\n"); |
||
| 344 | while ($invitationQuery = mysqli_fetch_object(/** @scrutinizer ignore-type */ $invitations)) { |
||
| 345 | $retval[] = ["country" => $invitationQuery->country, "name" => $invitationQuery->name, "mail" => $invitationQuery->invite_dest_mail, "token" => $invitationQuery->invite_token, "expiry" => $invitationQuery->expiry]; |
||
| 346 | } |
||
| 347 | return $retval; |
||
| 348 | } |
||
| 349 | |||
| 350 | /** Retrieves all invitations which have expired in the last hour. |
||
| 351 | * |
||
| 352 | * @return array of expired invitations |
||
| 353 | */ |
||
| 354 | public function listRecentlyExpiredInvitations() |
||
| 370 | } |
||
| 371 | |||
| 372 | /** |
||
| 373 | * For a given persistent user identifier, returns an array of institution identifiers (not the actual objects!) for which this |
||
| 374 | * user is the/a administrator and also do comparisons to the eduroam DB results. |
||
| 375 | * If the federation autoregister-synced flag is set if it turns out that the eduroam DB |
||
| 376 | * lists the email of the current logged-in admin as an admin of an existing CAT institution |
||
| 377 | * and this institution is synced to the matching external institutuin then this admin |
||
| 378 | * will be automatically added tho the institution and the 'existing' part of $this->currentInstitutions |
||
| 379 | * will be updated. This identifier will also be listed to $this->currentInstitutions['resynced'] |
||
| 380 | * |
||
| 381 | * If the federation autoregister-new-inst flag is set and there are exeternal institututions which could be |
||
| 382 | * candidated for creating them in CAT - add the identifiers of these institutuins to this->currentInstitutions[new'] |
||
| 383 | * |
||
| 384 | * @return array array of institution IDs |
||
| 385 | */ |
||
| 386 | public function listInstitutionsByAdmin() |
||
| 387 | { |
||
| 388 | $edugain = $_SESSION['eduGAIN']; |
||
| 389 | // get the list of local identifers of institutions managed by this user |
||
| 390 | // it will be returned as $this->currentInstitutions |
||
| 391 | $this->getCurrentInstitutionsByAdmin(); |
||
| 392 | if (count($this->currentInstitutions) == 0) { |
||
| 393 | $this->newUser = true; |
||
| 394 | } |
||
| 395 | // check if selfservice_registration is set to eduGAIN - if not then return with the durrent list |
||
| 396 | if (\config\ConfAssistant::CONSORTIUM['selfservice_registration'] !== 'eduGAIN') { |
||
| 397 | common\Logging::debug_s(4, "selfservice_registration not set to eduGAIN\n"); |
||
| 398 | return $this->currentInstitutions; |
||
| 399 | } |
||
| 400 | // now add additional institutions based on the external DB |
||
| 401 | // proceed only if user has been authenticated fron an eduGAIN IdP |
||
| 402 | if ($edugain == false) { |
||
| 403 | return $this->currentInstitutions; |
||
| 404 | } |
||
| 405 | $email = $_SESSION['auth_email']; |
||
| 406 | $externalDB = CAT::determineExternalConnection(); |
||
| 407 | // get the list of identifiers in the external DB with this user listed as the admin and linked to CAT institutions |
||
| 408 | $extInstList = $externalDB->listExternalEntitiesByUserEmail($email); |
||
| 409 | $extInstListTmp = $extInstList; |
||
| 410 | // we begin by removing entites in $extInstList which are already managed by this user and synced - |
||
| 411 | // these require no further checking |
||
| 412 | foreach ($extInstListTmp as $country => $extInstCountryList) { |
||
| 413 | $len = count($extInstCountryList); |
||
| 414 | for($i = 0; $i < $len; ++$i) { |
||
| 415 | $extInst = $extInstCountryList[$i]; |
||
| 416 | if ($extInst['inst_id'] != NULL && in_array($extInst['inst_id'], $this->currentInstitutions['existing'])) { |
||
| 417 | unset($extInstList[$country][$i]); |
||
| 418 | } |
||
| 419 | } |
||
| 420 | if (count($extInstList[$country]) == 0) { |
||
| 421 | unset($extInstList[$country]); |
||
| 422 | } |
||
| 423 | } |
||
| 424 | // now verify the $extInstList separately for each federation making sure |
||
| 425 | // that the federation allows autoregistration |
||
| 426 | foreach ($extInstList as $country => $extInstCountryList) { |
||
| 427 | $fed = new Federation($country); |
||
| 428 | $this->doExternalDBAutoregister($extInstCountryList, $fed); |
||
| 429 | $this->doExternalDBAutoregisterNew($extInstCountryList, $fed); |
||
| 430 | } |
||
| 431 | // now we run tests for adding admins based on pairwise-id and entitlement |
||
| 432 | $entitledCountries = $this->getUserEntitledFed(); |
||
| 433 | $entitlementInst = $this->listCatInstitutionsByPairwiseId(); |
||
| 434 | common\Logging::debug_s(4, $entitlementInst, "entitlementInst\n", "\n"); |
||
| 435 | foreach ($entitlementInst as $country => $instList) { |
||
| 436 | if (!in_array($country, $entitledCountries)) { |
||
| 437 | continue; |
||
| 438 | } |
||
| 439 | $fed = new Federation($country); |
||
| 440 | $this->doEntitlementAutoregister($instList, $fed); |
||
| 441 | } |
||
| 442 | $_SESSION['entitledIdPs'] = array_column($this->currentInstitutions['entitlement'], 0); |
||
| 443 | $_SESSION['resyncedIdPs'] = $this->currentInstitutions['resynced']; |
||
| 444 | $_SESSION['newIdPs'] = $this->currentInstitutions['new']; |
||
| 445 | common\Logging::debug_s(4, $this->currentInstitutions, "currentInstitutions\n", "\n"); |
||
| 446 | return $this->currentInstitutions; |
||
| 447 | } |
||
| 448 | |||
| 449 | /** |
||
| 450 | * Handle auto-registration of admin for CAT institutions which are synced to |
||
| 451 | * eduroam DB institutions which have the current admin listed |
||
| 452 | * The method verifies that the federation allows auto-registration |
||
| 453 | * |
||
| 454 | * @param array $extInstCountryList - list of eduroam DB candidate institutions |
||
| 455 | * @param object $fed - the Federation object |
||
| 456 | */ |
||
| 457 | private function doExternalDBAutoregister($extInstCountryList, $fed) { |
||
| 473 | } |
||
| 474 | } |
||
| 475 | |||
| 476 | /** |
||
| 477 | * Handle auto-creation of new CAT institutions which match |
||
| 478 | * eduroam DB institutions which have the current admin listed |
||
| 479 | * The method verifies that the federation allows auto-cereation |
||
| 480 | * |
||
| 481 | * @param array $extInstCountryList - list of eduroam DB candidate institutions |
||
| 482 | * @param object $fed - the Federation object |
||
| 483 | */ |
||
| 484 | private function doExternalDBAutoregisterNew($extInstCountryList, $fed) { |
||
| 485 | $newInstFlag = $fed->getAttributes('fed:autoregister-new-inst'); |
||
| 486 | if ($newInstFlag == []) { |
||
| 487 | return; |
||
| 488 | } |
||
| 489 | foreach ($extInstCountryList as $extInst) { |
||
| 490 | common\Logging::debug_s(4, "Testing ".$extInst['external_db_id']." for potential new inst\n"); |
||
| 491 | if ($extInst['inst_id'] != null) { // there alreay exeists a CAT institution synced to this one |
||
| 492 | continue; |
||
| 493 | } |
||
| 494 | $country = strtoupper($fed->tld); |
||
| 495 | // now run checks against creating dupplicates in CAT DB |
||
| 496 | $disectedNames = ExternalEduroamDBData::dissectCollapsedInstitutionNames($extInst['name']); |
||
| 497 | $names = $disectedNames['joint']; |
||
| 498 | $realms = ExternalEduroamDBData::dissectCollapsedInstitutionRealms($extInst['realm']); |
||
| 499 | $foundMatch = $this->checkForSimilarInstitutions($names, $realms); |
||
| 500 | common\Logging::debug_s(4, $foundMatch, "checkForSimilarInstitutions returned: ","\n"); |
||
| 501 | if ($foundMatch == 0) { |
||
| 502 | $this->currentInstitutions['new'][] = [$extInst['external_db_id'], $disectedNames['perlang'], $country]; |
||
| 503 | } |
||
| 504 | } |
||
| 505 | } |
||
| 506 | |||
| 507 | /** |
||
| 508 | * Handle auto-registration of admin for CAT institutions |
||
| 509 | * based on data from eduGAIN login |
||
| 510 | * The method verifies that the federation allows this type of auto-registration |
||
| 511 | * |
||
| 512 | * @param object $fed - the Federation object |
||
| 513 | */ |
||
| 514 | private function doEntitlementAutoregister($instList, $fed) { |
||
| 523 | } |
||
| 524 | } |
||
| 525 | |||
| 526 | } |
||
| 527 | |||
| 528 | /** |
||
| 529 | * Generate a list of externalDB institutions for which the admin is entitled |
||
| 530 | * based on the eduPersonEntitlement setting and scope from pairwise-id |
||
| 531 | * The |
||
| 532 | * @return array indexed by countries |
||
| 533 | */ |
||
| 534 | private function listCatInstitutionsByPairwiseId() { |
||
| 535 | if (!isset(\config\ConfAssistant::CONSORTIUM['entitlement'])) { |
||
| 536 | return []; |
||
| 537 | } |
||
| 538 | // first check if pairwise-id is set |
||
| 539 | $userId = $_SESSION['user']; |
||
| 540 | if (substr($userId, 0, 12) !== 'pairwise-id:') { |
||
| 541 | return []; |
||
| 542 | } |
||
| 543 | |||
| 544 | // next check if entitlement is setand matches our expectations |
||
| 545 | if (!isset($_SESSION['entitlement'])) { |
||
| 546 | return []; |
||
| 547 | } |
||
| 548 | |||
| 549 | // get realm from pariwise-id |
||
| 550 | if (preg_match('/^pairwise-id:[^@]+@([^!]+)!/', $userId, $matches) == 0) { |
||
| 551 | return []; |
||
| 552 | } |
||
| 553 | |||
| 554 | $userRealm = $matches[1]; |
||
| 555 | common\Logging::debug_s(4, $userRealm, "userRealm:", "\n"); |
||
| 556 | // list CAT inst_id and country from the profile |
||
| 557 | $query = "SELECT DISTINCT profile.inst_id,country FROM profile JOIN institution on profile.inst_id = institution.inst_id WHERE realm LIKE '%@$userRealm' OR realm LIKE '%@%.$userRealm'"; |
||
| 558 | $institutions = $this->databaseHandle->exec($query); |
||
| 559 | $catInstList = $institutions->fetch_all(); |
||
| 560 | $returnarray = []; |
||
| 561 | foreach ($catInstList as $inst) { |
||
| 562 | $country = $inst[1]; |
||
| 563 | if (!isset($returnarray[$country])) { |
||
| 564 | $returnarray[$country] = []; |
||
| 565 | } |
||
| 566 | $returnarray[$country][] = $inst[0]; |
||
| 567 | } |
||
| 568 | return $returnarray; |
||
| 569 | } |
||
| 570 | |||
| 571 | /** |
||
| 572 | * Get the list of eduroam countries that the user could potentially auto-register |
||
| 573 | * based on eduPersonEntitlement. The list of countries is based on matching between |
||
| 574 | * the eduGAIN federation where the eduGAIN IdP is registered and the counters that this federation serves |
||
| 575 | * Before passing on the list it is checked if particular countries allow entitlement-based |
||
| 576 | * autoregistration |
||
| 577 | * |
||
| 578 | * @return array indexed by countries |
||
| 579 | */ |
||
| 580 | private function getUserEntitledFed() { |
||
| 581 | if (!isset($_SESSION['entitlement'])) { |
||
| 582 | return []; |
||
| 583 | } |
||
| 584 | $entitledCountries = []; |
||
| 585 | $countries = $this->databaseHandle->exec("SELECT country FROM edugain WHERE reg_auth = ?", 's', $_SESSION['eduGAIN']); |
||
| 586 | $countryList = $countries->fetch_all(); |
||
| 587 | $countriesTmp = []; |
||
| 588 | foreach ($countryList as $country) { |
||
| 589 | $requiredEntitlement = NULL; |
||
| 590 | $countryCode = $country[0]; |
||
| 591 | $fed = new Federation($countryCode); |
||
| 592 | $autoreg = $fed->getAttributes('fed:autoregister-entitlement'); |
||
| 593 | $entitlementVal = $fed->getAttributes('fed:entitlement-attr'); |
||
| 594 | if (isset($autoreg[0]['value']) && $autoreg[0]['value'] == 'on') { |
||
| 595 | $requiredEntitlement = isset($entitlementVal[0]['value']) ? $entitlementVal[0]['value'] : \config\ConfAssistant::CONSORTIUM['entitlement']; |
||
| 596 | } |
||
| 597 | common\Logging::debug_s(4, $requiredEntitlement, "$countryCode requiredEntitlement\n", "\n"); |
||
| 598 | if (in_array($requiredEntitlement, $_SESSION['entitlement'])) { |
||
| 599 | $entitledCountries[] = $countryCode; |
||
| 600 | } |
||
| 601 | } |
||
| 602 | common\Logging::debug_s(4, $entitledCountries, "entitledCountries:\n", "\n"); |
||
| 603 | return $entitledCountries; |
||
| 604 | } |
||
| 605 | |||
| 606 | /** |
||
| 607 | * Tests if the institution with these identifier does not yet exist in CAT. |
||
| 608 | * This is done by testing the admins "new" institutions, this way we also make sure |
||
| 609 | * that this admin is actually also allowed to create the new one |
||
| 610 | * |
||
| 611 | * @return int 1 or 0. 1 means we are free to create the inst. |
||
| 612 | */ |
||
| 613 | |||
| 614 | public function checkForCatMatch($extId, $ROid) { |
||
| 615 | $this->listInstitutionsByAdmin(); |
||
| 616 | foreach ($this->currentInstitutions['new'] as $newInst) { |
||
| 617 | if ($extId == $newInst[0] && $ROid == strtoupper($newInst[2]).'01') { |
||
| 618 | return 0; |
||
| 619 | } |
||
| 620 | } |
||
| 621 | return 1; |
||
| 622 | } |
||
| 623 | |||
| 624 | /** |
||
| 625 | * get the list of current institutions of the given admin |
||
| 626 | * |
||
| 627 | * This method does not rerurn anything but sets $this->currentInstitutions |
||
| 628 | * it only fillsh the 'existing' block, leaving the other two for other methods |
||
| 629 | * to deal with |
||
| 630 | */ |
||
| 631 | private function getCurrentInstitutionsByAdmin() { |
||
| 647 | } |
||
| 648 | |||
| 649 | /** |
||
| 650 | * given arrays of realms and names check if there already are institutions in CAT that |
||
| 651 | * could be a match - this is for ellimination and against creating duplicates |
||
| 652 | * still this is not perfect, no realms given and institutions with a slightly different |
||
| 653 | * name will return no-match and thus open possibility for dupplicates |
||
| 654 | * |
||
| 655 | * @param array $namesToTest |
||
| 656 | * @param array $realmsToTest |
||
| 657 | * @return int - 1 - a match was found, 0 - no match found |
||
| 658 | */ |
||
| 659 | private function checkForSimilarInstitutions($namesToTest, $realmsToTest) { |
||
| 691 | } |
||
| 692 | |||
| 693 | /** |
||
| 694 | * read the last login date of given user identifier |
||
| 695 | * |
||
| 696 | * @param string $user |
||
| 697 | * @return string NULL - the date last seen or NULL if not recorded yet |
||
| 698 | */ |
||
| 699 | public function getAdminLastAuth($user) { |
||
| 707 | } |
||
| 708 | } |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths