ILIAS  trunk Revision v12.0_alpha-377-g3641b37b9db
class.ilAuthProviderECS.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
21use ILIAS\Refinery\Factory as Refinery;
22use ILIAS\HTTP\Services as HTTPServices;
23
30{
35 private Refinery $refinery;
36 private HTTPServices $http;
39
40 protected ?int $mid = null;
41 protected ?string $abreviation = null;
42
46
47
53 {
55
56 global $DIC;
57
58 $this->clientIniFile = $DIC->clientIni();
59 $this->rbacAdmin = $DIC->rbac()->admin();
60 $this->setting = $DIC->settings();
61 $this->lng = $DIC->language();
62 $this->lng->loadLanguageModule('ecs');
63 $this->http = $DIC->http();
64 $this->refinery = $DIC->refinery();
65 $this->authSession = $DIC['ilAuthSession'];
66 $this->ctrl = $DIC->ctrl();
67 $this->auth_factory = new ilECSAuthFactory();
68
69 $this->initECSServices();
70 }
71
75 public function getAbreviation(): string
76 {
77 return $this->abreviation;
78 }
79
83 public function getMID(): int
84 {
85 return $this->mid;
86 }
87
88 public function setMID(int $a_mid): void
89 {
90 $this->mid = $a_mid;
91 }
92
96 public function setCurrentServer(ilECSSetting $server): void
97 {
98 $this->currentServer = $server;
99 }
100
105 {
107 }
108
113 {
114 return $this->servers;
115 }
116
117
121 public function doAuthentication(\ilAuthStatus $status): bool
122 {
123 $this->getLogger()->debug('Starting ECS authentication');
124 if (!$this->getServerSettings()->activeServerExists()) {
125 $this->getLogger()->warning('No active ecs server found. Aborting');
126 $this->handleAuthenticationFail($status, 'err_wrong_login');
127 return false;
128 }
129
130 // Iterate through all active ecs instances
131 foreach ($this->getServerSettings()->getServers(ilECSServerSettings::ACTIVE_SERVER) as $server) {
132 $this->setCurrentServer($server);
133 if ($this->validateHash()) {
134 return $this->handleLoginByAuthMode($status);
135 }
136 }
137 $this->getLogger()->warning('Could not validate ecs hash for any active server.');
138 $this->handleAuthenticationFail($status, 'err_wrong_login');
139 return false;
140 }
141
146 protected function handleLoginByAuthMode(ilAuthStatus $status): bool
147 {
148 $is_external_account = false;
149 if ($this->http->wrapper()->query()->has('ecs_external_account')) {
150 $is_external_account = $this->http->wrapper()->query()->retrieve(
151 'ecs_external_account',
152 $this->refinery->kindlyTo()->bool()
153 );
154 }
155 if ($this->http->wrapper()->query()->has('target')) {
156 $redirection_target = $this->http->wrapper()->query()->retrieve(
157 'target',
158 $this->refinery->kindlyTo()->string()
159 );
160 } else {
161 $redirection_target = $this->http->request()->getUri()->getPath();
162 }
163 $part_settings = new ilECSParticipantSetting(
164 $this->getCurrentServer()->getServerId(),
165 $this->getMID()
166 );
167 if ($this->resumeCurrentSession()) {
168 $this->getLogger()->debug('Continuing current user session');
170 $status->setAuthenticatedUserId($this->authSession->getUserId());
171 return true;
172 }
173 if ($is_external_account) {
175 $this->auth_factory->build($part_settings->getIncomingAuthType())->handleLogin($redirection_target);
176 return false;
177 }
178 if ($part_settings->areIncomingLocalAccountsSupported()) {
179 // handle successful authentication
180 $new_usr_id = $this->handleLogin();
181 $this->getLogger()->info('ECS authentication successful.');
183 $status->setAuthenticatedUserId($new_usr_id);
184 return true;
185 }
186 $this->handleAuthenticationFail($status, 'err_wrong_login');
187 return false;
188 }
189
190 protected function resumeCurrentSession(): bool
191 {
192 $session_user_id = $this->authSession->getUserId();
193 if (!$session_user_id || $session_user_id === ANONYMOUS_USER_ID) {
194 $this->getLogger()->debug('No valid session found');
195 $this->authSession->setAuthenticated(false, ANONYMOUS_USER_ID);
196 return false;
197 }
198 $session_ext_account = ilObjUser::_lookupExternalAccount($session_user_id);
199 $user = new ilECSUser($this->http->request()->getQueryParams());
200 $this->getLogger()->debug('ECS user name: ' . $user->getLogin());
201 $this->getLogger()->debug('Session external account: ' . $session_ext_account);
202 if (!$session_ext_account || strcmp($user->getLogin(), $session_ext_account) !== 0) {
203 $this->getLogger()->debug('No matching session found. Terminating current user session.');
204 $this->authSession->setAuthenticated(false, ANONYMOUS_USER_ID);
205 return false;
206 }
207 // assign to ECS global role
208 $this->rbacAdmin->assignUser($this->getCurrentServer()->getGlobalRole(), $this->authSession->getUserId());
209 return true;
210 }
211
212
216 public function handleLogin()
217 {
218 $user = new ilECSUser($this->http->request()->getQueryParams());
219
220 if (!$usr_id = ilObject::_lookupObjIdByImportId($user->getImportId())) {
221 $username = $this->createUser($user);
222 } else {
223 $username = $this->updateUser($user, $usr_id);
224 }
225
226 // set user imported
227 $import = new ilECSImport($this->getCurrentServer()->getServerId(), $usr_id);
228 $import->save();
229
230 // Store remote user data
231 $remoteUserRepository = new ilECSRemoteUserRepository();
232 $remoteUserRepository->createIfNotExisting(
233 $this->getCurrentServer()->getServerId(),
234 $this->getMID(),
235 ilObjUser::_lookupId($username),
236 $user->getImportId()
237 );
238
239 $this->getLogger()->info('Current user is: ' . $username);
240
241 return ilObjUser::_lookupId($username);
242 }
243
244 public function initRemoteUserWithRemoteId(): void
245 {
246 $user = new ilECSUser($this->http->request()->getQueryParams());
247
248 // Store remote user data
249 $remoteUserRepository = new ilECSRemoteUserRepository();
250 $remoteUserRepository->createIfRemoteUserNotExisting(
251 $this->getCurrentServer()->getServerId(),
252 $this->getMID(),
253 0,
254 $user->getLogin()
255 );
256 }
257
261 public function validateHash(): bool
262 {
263 // fetch hash
264 $hash = "";
265 if ($this->http->wrapper()->query()->has('ecs_hash')) {
266 $hash = $this->http->wrapper()->query()->retrieve(
267 'ecs_hash',
268 $this->refinery->kindlyTo()->string()
269 );
270 }
271 if ($this->http->wrapper()->query()->has('ecs_hash_url')) {
272 $hashurl = urldecode(
273 $this->http->wrapper()->query()->retrieve(
274 'ecs_hash_url',
275 $this->refinery->kindlyTo()->string()
276 )
277 );
278 $hash = basename(parse_url($hashurl, PHP_URL_PATH));
279 }
280
281 $this->getLogger()->info('Using ecs hash: ' . $hash);
282 // Check if hash is valid ...
283 try {
284 $connector = new ilECSConnector($this->getCurrentServer());
285 $res = $connector->getAuth($hash);
286 $auths = $res->getResult();
287
288 //$this->getLogger()->dump($auths, ilLogLevel::DEBUG);
289
290 if ($auths->pid) {
291 try {
292 $reader = ilECSCommunityReader::getInstanceByServerId($this->getCurrentServer()->getServerId());
293 foreach ($reader->getParticipantsByPid($auths->pid) as $participant) {
294 if ($participant->getOrganisation() instanceof \ilECSOrganisation) {
295 $this->abreviation = $participant->getOrganisation()->getAbbreviation();
296 break;
297 }
298 }
299 if (!$this->abreviation) {
300 $this->abreviation = $auths->abbr;
301 }
302 } catch (Exception $e) {
303 $this->getLogger()->warning('Authentication failed with message: ' . $e->getMessage());
304 return false;
305 }
306 } else {
307 $this->abreviation = $auths->abbr;
308 }
309
310 $this->getLogger()->debug('Got abbreviation: ' . $this->abreviation);
311 } catch (ilECSConnectorException $e) {
312 $this->getLogger()->warning('Authentication failed with message: ' . $e->getMessage());
313 return false;
314 }
315
316 // read current mid
317 try {
318 $connector = new ilECSConnector($this->getCurrentServer());
319 $details = $connector->getAuth($hash, true);
320
321 //$this->getLogger()->dump($details, ilLogLevel::DEBUG);
322 $this->getLogger()->debug('Token create for mid: ' . $details->getFirstSender());
323
324 $this->setMID($details->getFirstSender());
325 } catch (ilECSConnectorException $e) {
326 $this->getLogger()->warning('Receiving mid failed with message: ' . $e->getMessage());
327 return false;
328 }
329 return true;
330 }
331
332
336 private function initECSServices(): void
337 {
338 $this->servers = ilECSServerSettings::getInstance();
339 }
340
344 protected function createUser(ilECSUser $user): string
345 {
346 $userObj = new ilObjUser();
347 $userObj->setOwner(SYSTEM_USER_ID);
348
349 $local_user = ilAuthUtils::_generateLogin($this->getAbreviation() . '_' . $user->getLogin());
350
351 // system data
352 $userObj->setLogin($local_user);
353 $userObj->setFirstname($user->getFirstname());
354 $userObj->setLastname($user->getLastname());
355 $userObj->setTitle($userObj->getFullname());
356 $userObj->setDescription($userObj->getEmail());
357 $userObj->setEmail($user->getEmail());
358 $userObj->setInstitution($user->getInstitution());
359 $userObj->setPasswd('', ilObjUser::PASSWD_CRYPTED);
360 $userObj->setAuthMode('ecs');
361 // set user language to system language
362 $userObj->setLanguage($this->setting->get("language"));
363
364 // Time limit
365 $userObj->setTimeLimitUnlimited(false);
366 $userObj->setTimeLimitFrom(time() - 5);
367 $userObj->setTimeLimitUntil(time() + (int) $this->clientIniFile->readVariable("session", "expire"));
368
369 // Create user in DB
370 $userObj->setOwner(6);
371 $tmp_date = new ilDateTime(time(), IL_CAL_UNIX);
372 $userObj->setAgreeDate($tmp_date->get(IL_CAL_DATETIME));
373 $userObj->create();
374 $userObj->setActive(true);
375 $userObj->saveAsNew();
376 $userObj->updateOwner();
377 $userObj->writePrefs();
378
379 if ($this->getCurrentServer()->getGlobalRole()) {
380 $this->rbacAdmin->assignUser($this->getCurrentServer()->getGlobalRole(), $userObj->getId());
381 }
382 ilObject::_writeImportId($userObj->getId(), $user->getImportId());
383
384 $this->getLogger()->info('Created new remote user with usr_id: ' . $user->getImportId());
385
386 // Send Mail
387 #$this->sendNotification($userObj);
388 $this->resetMailOptions($userObj->getId());
389
390 return $userObj->getLogin();
391 }
392
396 protected function updateUser(ilECSUser $user, int $a_local_user_id): string
397 {
398 $user_obj = new ilObjUser($a_local_user_id);
399 $user_obj->setFirstname($user->getFirstname());
400 $user_obj->setLastname($user->getLastname());
401 $user_obj->setEmail($user->getEmail());
402 $user_obj->setInstitution($user->getInstitution());
403 $user_obj->setActive(true);
404
405 $until = $user_obj->getTimeLimitUntil();
406
407 if ($until < (time() + (int) $this->clientIniFile->readVariable('session', 'expire'))) {
408 $user_obj->setTimeLimitFrom(time() - 60);
409 $user_obj->setTimeLimitUntil(time() + (int) $this->clientIniFile->readVariable("session", "expire"));
410 }
411 $user_obj->refreshLogin();
412 $user_obj->update();
413
414 if ($this->getCurrentServer()->getGlobalRole()) {
415 $this->rbacAdmin->assignUser(
416 $this->getCurrentServer()->getGlobalRole(),
417 $user_obj->getId()
418 );
419 }
420
421 $this->resetMailOptions($a_local_user_id);
422
423 $this->getLogger()->debug('Finished update of remote user with usr_id: ' . $user->getImportId());
424 return $user_obj->getLogin();
425 }
426
431 protected function resetMailOptions(int $a_usr_id): void
432 {
433 $options = new ilMailOptions($a_usr_id);
434 $options->setIncomingType(ilMailOptions::INCOMING_LOCAL);
435 $options->updateOptions();
436 }
437}
Builds data types.
Definition: Factory.php:36
Class Services.
Definition: Services.php:38
const IL_CAL_UNIX
const IL_CAL_DATETIME
Auth prvider for ecs auth.
doAuthentication(\ilAuthStatus $status)
Try ecs authentication.
__construct(\ilAuthCredentials $credentials)
Constructor.
resetMailOptions(int $a_usr_id)
Reset mail options to "local only".
getServerSettings()
Get server settings.
setCurrentServer(ilECSSetting $server)
Set current server.
getAbreviation()
get abbreviation
createUser(ilECSUser $user)
create new user
updateUser(ilECSUser $user, int $a_local_user_id)
update existing user
initECSServices()
Init ECS Services.
handleLogin()
Called from base class after successful login.
handleLoginByAuthMode(ilAuthStatus $status)
Redirects to shibboleth login; to standard login page for LDAP based authentication or authenticates/...
getCurrentServer()
Get current server.
ilECSServerSettings $servers
validateHash()
Validate ECS hash.
ilECSAuthFactory $auth_factory
handleAuthenticationFail(ilAuthStatus $status, string $a_reason)
ilAuthCredentials $credentials
setAuthenticatedUserId(int $a_id)
setStatus(int $a_status)
Set auth status.
const int STATUS_AUTHENTICATED
static _generateLogin(string $a_login)
generate free login by starting with a default string and adding postfix numbers
@classDescription Date and time handling
static getInstanceByServerId(int $a_server_id)
Get instance by server id.
Storage of ECS imported objects.
Collection of ECS settings.
static getInstance()
Get singleton instance.
Stores relevant user data.
getFirstname()
get firstname
getLastname()
getLastname
getLogin()
get login
getImportId()
get Email
getEmail()
get email
getInstitution()
get institution
INIFile Parser Early access in init proceess! Avoid further dependencies like logging or other servic...
language handling
final const int INCOMING_LOCAL
User class.
const PASSWD_CRYPTED
static _lookupExternalAccount(int $a_user_id)
static _lookupId(string|array $a_user_str)
static _lookupObjIdByImportId(string $import_id)
Get (latest) object id for an import id.
static _writeImportId(int $obj_id, string $import_id)
write import id to db (static)
Class ilRbacAdmin Core functions for role based access control.
ILIAS Setting Class.
const SYSTEM_USER_ID
This file contains constants for PHPStan analyis, see: https://phpstan.org/config-reference#constants...
Definition: constants.php:26
const ANONYMOUS_USER_ID
Definition: constants.php:27
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$res
Definition: ltiservices.php:69
static http()
Fetches the global http state from ILIAS.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
global $DIC
Definition: shib_login.php:26
$server
Definition: shib_login.php:28