ILIAS  release_8 Revision v8.24
class.ilAuthFrontend.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
26//TODO check why authfront does not include frontendInterface
28{
29 public const MIG_EXTERNAL_ACCOUNT = 'mig_ext_account';
30 public const MIG_TRIGGER_AUTHMODE = 'mig_trigger_auth_mode';
31 public const MIG_DESIRED_AUTHMODE = 'mig_desired_auth_mode';
32
36
40 private array $providers;
43
44 private bool $authenticated = false;
45
53 {
54 global $DIC;
55 $this->logger = $DIC->logger()->auth();
56 $this->settings = $DIC->settings();
57 $this->lng = $DIC->language();
58 $this->ilAppEventHandler = $DIC->event();
59
60 $this->auth_session = $session;
61 $this->credentials = $credentials;
62 $this->status = $status;
63 $this->providers = $providers;
64 }
65
69 public function getAuthSession(): ilAuthSession
70 {
72 }
73
78 {
79 return $this->credentials;
80 }
81
86 public function getProviders(): array
87 {
88 return $this->providers;
89 }
90
94 public function getStatus(): ilAuthStatus
95 {
96 return $this->status;
97 }
98
102 public function resetStatus(): void
103 {
104 $this->getStatus()->setStatus(ilAuthStatus::STATUS_UNDEFINED);
105 $this->getStatus()->setReason('');
106 $this->getStatus()->setAuthenticatedUserId(ANONYMOUS_USER_ID);
107 }
108
113 public function migrateAccount(ilAuthSession $session): bool
114 {
115 if (!$session->isAuthenticated()) {
116 $this->logger->warning('Desired user account is not authenticated');
117 return false;
118 }
119 $user = ilObjectFactory::getInstanceByObjId($session->getUserId(), false);
120
121 if (!$user instanceof ilObjUser) {
122 $this->logger->info('Cannot instantiate user account for account migration: ' . $session->getUserId());
123 return false;
124 }
125
126 $user->setAuthMode(ilSession::get(static::MIG_DESIRED_AUTHMODE));
127
128 $this->logger->debug('new auth mode is: ' . ilSession::get(self::MIG_DESIRED_AUTHMODE));
129
130 $user->setExternalAccount(ilSession::get(static::MIG_EXTERNAL_ACCOUNT));
131 $user->update();
132
133 foreach ($this->getProviders() as $provider) {
135 $this->logger->warning('Provider: ' . get_class($provider) . ' does not support account migration.');
136 throw new InvalidArgumentException('Invalid auth provider given.');
137 }
138 $this->getCredentials()->setUsername(ilSession::get(static::MIG_EXTERNAL_ACCOUNT));
139 $provider->migrateAccount($this->getStatus());
141 return $this->handleAuthenticationSuccess($provider);
142 }
143 }
144 return $this->handleAuthenticationFail();
145 }
146
150 public function migrateAccountNew(): bool
151 {
152 foreach ($this->providers as $provider) {
154 $this->logger->warning('Provider: ' . get_class($provider) . ' does not support account migration.');
155 throw new InvalidArgumentException('Invalid auth provider given.');
156 }
157 $provider->createNewAccount($this->getStatus());
158
159 if ($provider instanceof ilAuthProviderInterface &&
161 return $this->handleAuthenticationSuccess($provider);
162 }
163 }
164 return $this->handleAuthenticationFail();
165 }
166
167
168
172 public function authenticate(): bool
173 {
174 foreach ($this->getProviders() as $provider) {
175 $this->resetStatus();
176
177 $this->logger->debug('Trying authentication against: ' . get_class($provider));
178
179 $provider->doAuthentication($this->getStatus());
180
181 $this->logger->debug('Authentication user id: ' . $this->getStatus()->getAuthenticatedUserId());
182
183 switch ($this->getStatus()->getStatus()) {
185 return $this->handleAuthenticationSuccess($provider);
186
188 $this->logger->notice("Account migration required.");
189 if ($provider instanceof ilAuthProviderAccountMigrationInterface) {
190 return $this->handleAccountMigration($provider);
191 }
192
193 $this->logger->error('Authentication migratittion required but provider does not support interface' . get_class($provider));
194 break;
196 default:
197 $this->logger->debug('Authentication failed against: ' . get_class($provider));
198 break;
199 }
200 }
201 return $this->handleAuthenticationFail();
202 }
203
209 {
210 $this->logger->debug('Trigger auth mode: ' . $provider->getTriggerAuthMode());
211 $this->logger->debug('Desired auth mode: ' . $provider->getUserAuthModeName());
212 $this->logger->debug('External account: ' . $provider->getExternalAccountName());
213
214 $this->getStatus()->setAuthenticatedUserId(ANONYMOUS_USER_ID);
215 #$this->getStatus()->setStatus(ilAuthStatus::STATUS_AUTHENTICATED);
216
217 ilSession::set(static::MIG_TRIGGER_AUTHMODE, $provider->getTriggerAuthMode());
218 ilSession::set(static::MIG_DESIRED_AUTHMODE, $provider->getUserAuthModeName());
219 ilSession::set(static::MIG_EXTERNAL_ACCOUNT, $provider->getExternalAccountName());
220
222
223 return true;
224 }
225
230 {
231 $user = ilObjectFactory::getInstanceByObjId($this->getStatus()->getAuthenticatedUserId(), false);
232
233 // reset expired status
234 $this->getAuthSession()->setExpired(false);
235
236 if (!$user instanceof ilObjUser) {
237 $this->logger->error('Cannot instantiate user account with id: ' . $this->getStatus()->getAuthenticatedUserId());
239 $this->getStatus()->setAuthenticatedUserId(ANONYMOUS_USER_ID);
240 $this->getStatus()->setReason('auth_err_invalid_user_account');
241 return false;
242 }
243
244 if (!$this->checkExceededLoginAttempts($user)) {
245 $this->logger->info('Authentication failed for inactive user with id and too may login attempts: ' . $this->getStatus()->getAuthenticatedUserId());
247 $this->getStatus()->setAuthenticatedUserId(ANONYMOUS_USER_ID);
248 $this->getStatus()->setReason('auth_err_login_attempts_deactivation');
249 return false;
250 }
251
252 if (!$this->checkActivation($user)) {
253 $this->logger->info('Authentication failed for inactive user with id: ' . $this->getStatus()->getAuthenticatedUserId());
255 $this->getStatus()->setAuthenticatedUserId(ANONYMOUS_USER_ID);
256 $this->getStatus()->setReason('err_inactive');
257 return false;
258 }
259
260 // time limit
261 if (!$this->checkTimeLimit($user)) {
262 $this->logger->info('Authentication failed (time limit restriction) for user with id: ' . $this->getStatus()->getAuthenticatedUserId());
263
264 if ($this->settings->get('user_reactivate_code')) {
265 $this->logger->debug('Accout reactivation codes are active');
267 } else {
268 $this->logger->debug('Accout reactivation codes are inactive');
270 $this->getStatus()->setAuthenticatedUserId(ANONYMOUS_USER_ID);
271 }
272 $this->getStatus()->setReason('time_limit_reached');
273 return false;
274 }
275
276 // ip check
277 if (!$this->checkIp($user)) {
278 $this->logger->info('Authentication failed (wrong ip) for user with id: ' . $this->getStatus()->getAuthenticatedUserId());
280 $this->getStatus()->setAuthenticatedUserId(ANONYMOUS_USER_ID);
281
282 $this->getStatus()->setTranslatedReason(
283 sprintf(
284 $this->lng->txt('wrong_ip_detected'),
285 $_SERVER['REMOTE_ADDR']
286 )
287 );
288 return false;
289 }
290
291 // check simultaneos logins
292 $this->logger->debug('Check simutaneous login');
293 if (!$this->checkSimultaneousLogins($user)) {
294 $this->logger->info('Authentication failed: simultaneous logins forbidden for user: ' . $this->getStatus()->getAuthenticatedUserId());
296 $this->getStatus()->setAuthenticatedUserId(ANONYMOUS_USER_ID);
297 $this->getStatus()->setReason('simultaneous_login_detected');
298 return false;
299 }
300
301 // check if profile is complete
302 if (
306 ) {
307 ilLoggerFactory::getLogger('auth')->info('User profile is incomplete.');
308 $user->setProfileIncomplete(true);
309 $user->update();
310 }
311
312 // redirects in case of error (session pool limit reached)
313 ilSessionControl::handleLoginEvent($user->getLogin(), $this->getAuthSession());
314
315
316 // @todo move to event handling
317 ilOnlineTracking::addUser($user->getId());
318
319 // @todo move to event handling
320 ilObjForum::_updateOldAccess($user->getId());
321
322 $security_settings = ilSecuritySettings::_getInstance();
323
324 // determine first login of user for setting an indicator
325 // which still is available in PersonalDesktop, Repository, ...
326 // (last login date is set to current date in next step)
327 if (
328 $security_settings->isPasswordChangeOnFirstLoginEnabled() &&
329 $user->getLastLogin() === ''
330 ) {
331 $user->resetLastPasswordChange();
332 }
333 $user->refreshLogin();
334
335 if ($user->getLoginAttempts() > 0) {
336 $user->setLoginAttempts(0);
337 $user->update();
338 }
339
340
341 $this->logger->info('Successfully authenticated: ' . ilObjUser::_lookupLogin($this->getStatus()->getAuthenticatedUserId()));
342 $this->getAuthSession()->setAuthenticated(true, $this->getStatus()->getAuthenticatedUserId());
343
345
346 ilSession::set('orig_request_target', '');
347 $user->hasToAcceptTermsOfServiceInSession(true);
348
349
350 // --- anonymous/registered user
351 if (PHP_SAPI !== "cli") {
352 $this->logger->info(
353 'logged in as ' . $user->getLogin() .
354 ', remote:' . $_SERVER['REMOTE_ADDR'] . ':' . $_SERVER['REMOTE_PORT'] .
355 ', server:' . $_SERVER['SERVER_ADDR'] . ':' . $_SERVER['SERVER_PORT']
356 );
357 } else {
358 $this->logger->info(
359 'logged in as ' . $user->getLogin() . ' from CLI'
360 );
361 }
362
363 // finally raise event
364 $this->ilAppEventHandler->raise(
365 'Services/Authentication',
366 'afterLogin',
367 array(
368 'username' => $user->getLogin())
369 );
370
371 return true;
372 }
373
377 protected function checkActivation(ilObjUser $user): bool
378 {
379 return $user->getActive();
380 }
381
382 protected function checkExceededLoginAttempts(ilObjUser $user): bool
383 {
384 if ($user->getId() === ANONYMOUS_USER_ID) {
385 return true;
386 }
387
388 $isInactive = !$user->getActive();
389 if (!$isInactive) {
390 return true;
391 }
392
394 $maxLoginAttempts = $security->getLoginMaxAttempts();
395
396 if (!$maxLoginAttempts) {
397 return true;
398 }
399
400 $numLoginAttempts = \ilObjUser::_getLoginAttempts($user->getId());
401
402 return $numLoginAttempts < $maxLoginAttempts;
403 }
404
408 protected function checkTimeLimit(ilObjUser $user): bool
409 {
410 return $user->checkTimeLimit();
411 }
412
416 protected function checkIp(ilObjUser $user): bool
417 {
418 $clientip = $user->getClientIP();
419 if (trim($clientip) !== "") {
420 $clientip = preg_replace("/[^0-9.?*,:]+/", "", $clientip);
421 $clientip = str_replace([".", "?", "*", ","], ["\\.", "[0-9]", "[0-9]*", "|"], $clientip);
422
423 ilLoggerFactory::getLogger('auth')->debug('Check ip ' . $clientip . ' against ' . $_SERVER['REMOTE_ADDR']);
424
425 if (!preg_match("/^" . $clientip . "$/", $_SERVER["REMOTE_ADDR"])) {
426 return false;
427 }
428 }
429 return true;
430 }
431
435 protected function checkSimultaneousLogins(ilObjUser $user): bool
436 {
437 $this->logger->debug('Setting prevent simultaneous session is: ' . $this->settings->get('ps_prevent_simultaneous_logins'));
438 return !($this->settings->get('ps_prevent_simultaneous_logins') &&
439 ilObjUser::hasActiveSession($user->getId(), $this->getAuthSession()->getId()));
440 }
441
445 protected function handleAuthenticationFail(): bool
446 {
447 $this->logger->debug('Authentication failed for all authentication methods.');
448
449 $user_id = ilObjUser::_lookupId($this->getCredentials()->getUsername());
450 if (is_int($user_id) && $user_id !== ANONYMOUS_USER_ID) {
452 $login_attempts = ilObjUser::_getLoginAttempts($user_id);
453
454 $this->logger->notice('Increased login attempts for user: ' . $this->getCredentials()->getUsername());
455
457 $max_attempts = $security->getLoginMaxAttempts();
458
459 if ($max_attempts && $login_attempts >= $max_attempts) {
460 $this->getStatus()->setReason('auth_err_login_attempts_deactivation');
461 $this->logger->warning('User account set to inactive due to exceeded login attempts.');
463 }
464 }
465 return false;
466 }
467}
Global event handler.
raise(string $a_component, string $a_event, array $a_parameter=[])
Raise an event.
const CONTEXT_ECS
Calendar authentication with auth token.
ilAppEventHandler $ilAppEventHandler
resetStatus()
Reset status.
checkActivation(ilObjUser $user)
Check activation.
checkIp(ilObjUser $user)
Check ip.
handleAuthenticationFail()
Handle failed authenication.
checkExceededLoginAttempts(ilObjUser $user)
authenticate()
Try to authenticate user.
checkTimeLimit(ilObjUser $user)
Check time limit.
handleAccountMigration(ilAuthProviderAccountMigrationInterface $provider)
Handle account migration.
migrateAccountNew()
Create new user account.
ilAuthSession $auth_session
__construct(ilAuthSession $session, ilAuthStatus $status, ilAuthCredentials $credentials, array $providers)
checkSimultaneousLogins(ilObjUser $user)
Check simultaneous logins.
ilAuthCredentials $credentials
migrateAccount(ilAuthSession $session)
Migrate Account to existing user account.
getAuthSession()
Get auth session.
getCredentials()
Get auth credentials.
getProviders()
Get providers.
handleAuthenticationSuccess(ilAuthProviderInterface $provider)
Handle successful authentication.
getUserId()
Get authenticated user id.
Auth status implementation.
const STATUS_CODE_ACTIVATION_REQUIRED
const STATUS_AUTHENTICATION_FAILED
const STATUS_ACCOUNT_MIGRATION_REQUIRED
static getType()
Get context type.
const CONTEXT_LTI_PROVIDER
static initUserAccount()
Init user with current account id.
language handling
static getLogger(string $a_component_id)
Get component logger.
Component logger with individual log levels by component id.
static _updateOldAccess(int $a_usr_id)
User class.
static _getLoginAttempts(int $a_usr_id)
static _lookupId($a_user_str)
static _incrementLoginAttempts(int $a_usr_id)
static hasActiveSession(int $a_user_id, string $a_session_id)
static _lookupLogin(int $a_user_id)
static _setUserInactive(int $a_usr_id)
static getInstanceByObjId(?int $obj_id, bool $stop_on_error=true)
get an instance of an Ilias object by object id
static addUser(int $a_user_id)
static _getInstance()
Get instance of ilSecuritySettings.
static handleLoginEvent(string $a_login, ilAuthSession $auth_session)
when current session is allowed to be created it marks it with type regarding to the sessions user co...
static get(string $a_var)
static dumpToString()
static set(string $a_var, $a_val)
Set a value.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static isProfileIncomplete(ilObjUser $a_user, bool $a_include_udf=true, bool $a_personal_data_only=true)
Check if all required personal data fields are set.
const ANONYMOUS_USER_ID
Definition: constants.php:27
global $DIC
Definition: feed.php:28
Interface of auth credentials.
getExternalAccountName()
Get external account name.
getTriggerAuthMode()
Get auth mode which triggered the account migration 2_1 for ldap account migration with server id 1 1...
getUserAuthModeName()
Get user auth mode name ldap_1 for ldap account migration with server id 1 apache for apache auth.
Standard interface for auth provider implementations.
$provider
Definition: ltitoken.php:83
$session
$_SERVER['HTTP_HOST']
Definition: raiseError.php:10