19declare(strict_types=1);
53 $this->
lng = $DIC->language();
54 $this->
profile = $DIC[
'user']->getProfile();
56 if (
null === $a_idp_id || 0 === $a_idp_id) {
71 !array_key_exists($this->idp->getUidClaim(), $this->attributes) ||
72 !is_array($this->attributes[$this->idp->getUidClaim()]) ||
73 !array_key_exists(0, $this->attributes[$this->idp->getUidClaim()]) ||
74 $this->attributes[$this->idp->getUidClaim()][0] ===
''
77 'Could not find unique SAML attribute for the configured identifier: %s',
78 print_r($this->idp->getUidClaim(),
true)
82 $this->uid = $this->attributes[$this->idp->getUidClaim()][0];
87 if (!$this->idp->isActive()) {
89 'SAML IdP with id {idp_id} is not active.',
90 [
'idp_id' => $this->idp->getIdpId()]
97 if ([] === $this->attributes) {
98 $this->
getLogger()->warning(
'Could not parse any attributes from SAML response.');
108 }
catch (Exception
$e) {
109 $this->
getLogger()->warning($e->getMessage());
118 $update_auth_mode =
false;
121 'Login observer called for SAML authentication request of ext_account "%s" and auth_mode "%s".',
127 'Trying to find ext_account "%s" for auth_mode "%s".',
138 if (!is_string($internal_account) || $internal_account ===
'') {
139 $update_auth_mode =
true;
142 'Could not find ext_account "%s" for auth_mode "%s".',
147 $fallback_auth_mode =
'local';
149 'Trying to find ext_account "%s" for auth_mode "%s".',
156 if (
$GLOBALS[
'DIC'][
'ilSetting']->
get(
'auth_mode')) {
157 $defaultAuth =
$GLOBALS[
'DIC'][
'ilSetting']->get(
'auth_mode');
161 (!is_string($internal_account) || $internal_account ===
'') &&
165 'Could not find ext_account "%s" for auth_mode "%s".',
170 $fallback_auth_mode =
'default';
172 'Trying to find ext_account "%s" for auth_mode "%s".',
180 if (is_string($internal_account) && $internal_account !==
'') {
182 'Found user "%s" for ext_account "%s" in ILIAS database.',
187 if ($this->idp->isSynchronizationEnabled()) {
189 'SAML user synchronisation is enabled, so update existing user "%s" with ext_account "%s".',
193 $internal_account = $this->
importUser($internal_account, $this->uid, $this->attributes);
196 if ($update_auth_mode) {
201 'SAML Switched auth_mode of user with login "%s" and ext_account "%s" to "%s".',
208 'SAML Could not switch auth_mode of user with login "%s" and ext_account "%s" to "%s".',
217 'Authentication succeeded: Found internal login "%s for ext_account "%s" and auth_mode "%s".',
231 'Could not find an existing user for ext_account "%s" for any relevant auth_mode.',
234 if ($this->idp->isSynchronizationEnabled()) {
236 'SAML user synchronisation is enabled, so determine action for ext_account "%s" and auth_mode "%s".',
240 if (!$this->force_new_account && $this->idp->isAccountMigrationEnabled()) {
245 'Account migration is enabled, so redirecting ext_account "%s" to account migration screen.',
255 $new_name = $this->
importUser(
null, $this->uid, $this->attributes);
257 'Created new user account with login "%s" and ext_account "%s".',
289 $this->
getLogger()->warning(
'Cannot find user id for external account: ' . $this->
getCredentials()->getUsername());
296 $this->return_to = (string)
ilSession::get(self::SESSION_TMP_RETURN_TO);
298 $this->force_new_account =
true;
305 $this->migration_account = $a_name;
320 return 'saml_' . $this->idp->getIdpId();
323 private function importUser(?
string $a_internal_login,
string $a_external_account, array $a_user_data = []): string
328 $xml_writer->xmlStartTag(
'Users');
329 if (
null === $a_internal_login) {
330 $login = $a_user_data[$this->idp->getLoginClaim()][0];
333 $xml_writer->xmlStartTag(
336 'Action' =>
'Insert',
337 'Language' => $this->
lng->getDefaultLanguage()
340 $xml_writer->xmlElement(
'Login', [], $login);
342 $xml_writer->xmlElement(
'Role', [
343 'Id' => $this->idp->getDefaultRoleId(),
348 $xml_writer->xmlElement(
'Active', [],
"true");
350 $xml_writer->xmlElement(
'TimeLimitUnlimited', [], 1);
351 $xml_writer->xmlElement(
'TimeLimitFrom', [], time());
352 $xml_writer->xmlElement(
'TimeLimitUntil', [], time());
353 $xml_writer->xmlElement(
358 $xml_writer->xmlElement(
'ExternalAccount', [], $a_external_account);
362 $login = $a_internal_login;
365 $xml_writer->xmlStartTag(
'User', [
'Action' =>
'Update',
'Id' => $usr_id]);
367 $loginClaim = $a_user_data[$this->idp->getLoginClaim()][0];
370 $xml_writer->xmlElement(
'Login', [], $login);
376 foreach ($mapping as $rule) {
379 $value = $attributeValueParser->parse();
382 $this->
getLogger()->warning($e->getMessage());
387 $xml_writer->xmlEndTag(
'User');
388 $xml_writer->xmlEndTag(
'Users');
391 'Started import of user "%s" with ext_account "%s" and auth_mode "%s".',
397 $importParser->setXMLContent($xml_writer->xmlDumpMem(
false));
398 $importParser->setRoleAssignment([
399 $this->idp->getDefaultRoleId() => $this->idp->getDefaultRoleId(),
403 $importParser->startParsing();
413 switch (strtolower($rule->getAttribute())) {
415 $gender_attr =
'Gender';
416 match (strtolower($value)) {
417 'n',
'neutral' => $xml_writer->
xmlElement($gender_attr, [],
'n'),
418 'm',
'male' => $xml_writer->
xmlElement($gender_attr, [],
'm'),
420 default => $xml_writer->
xmlElement($gender_attr, [],
'f'),
425 $xml_writer->
xmlElement(
'Firstname', [], $value);
429 $xml_writer->
xmlElement(
'Lastname', [], $value);
437 $xml_writer->
xmlElement(
'SecondEmail', [], $value);
441 $xml_writer->
xmlElement(
'Institution', [], $value);
445 $xml_writer->
xmlElement(
'Department', [], $value);
457 $xml_writer->
xmlElement(
'Street', [], $value);
465 $xml_writer->
xmlElement(
'PostalCode', [], $value);
469 $xml_writer->
xmlElement(
'Country', [], $value);
473 $xml_writer->
xmlElement(
'PhoneOffice', [], $value);
477 $xml_writer->
xmlElement(
'PhoneHome', [], $value);
481 $xml_writer->
xmlElement(
'PhoneMobile', [], $value);
488 case 'referral_comment':
489 $xml_writer->
xmlElement(
'Comment', [], $value);
492 case 'matriculation':
493 $xml_writer->
xmlElement(
'Matriculation', [], $value);
497 $xml_writer->
xmlElement(
'Birthday', [], $value);
506 if (!isset($udf_data[1])) {
511 $field = $this->user_defined_fields[$udf_data[1]] ??
null;
512 if ($field ===
null) {
514 "Invalid/Orphaned UD field mapping detected: %s",
522 [
'Id' => $field->getIdentifier(),
'Name' => $field->getLabel($this->lng)],
531 if ($this->user_defined_fields ===
null) {
532 $this->user_defined_fields = $this->
profile->getAllUserDefinedFields();
createNewAccount(ilAuthStatus $status)
Create new ILIAS account for external_account.
importUser(?string $a_internal_login, string $a_external_account, array $a_user_data=[])
setExternalAccountName(string $a_name)
const string ERR_WRONG_LOGIN
buildUserAttributeXml(ilXmlWriter $xml_writer, ilExternalAuthUserAttributeMappingRule $rule, string $value)
handleSamlAuth(ilAuthStatus $status)
const string ERR_PROVIDER_INACTIVE
const string LOG_COMPONENT
determineUidFromAttributes()
string $migration_account
__construct(ilAuthCredentials $credentials, ?int $a_idp_id=null)
getExternalAccountName()
Get external account name.
getUserAuthModeName()
Get user auth mode name ldap_1 for ldap account migration with server id 1 apache for apache auth.
migrateAccount(ilAuthStatus $status)
Create new account.
const string SESSION_TMP_RETURN_TO
const string SESSION_TMP_ATTRIBUTES
doAuthentication(ilAuthStatus $status)
readonly Profile $profile
getTriggerAuthMode()
Get auth mode which triggered the account migration 2_1 for ldap account migration with server id 1 1...
array $user_defined_fields
handleAuthenticationFail(ilAuthStatus $status, string $a_reason)
ilAuthCredentials $credentials
setTranslatedReason(string $a_reason)
Set translated reason.
const int STATUS_AUTHENTICATION_FAILED
const int STATUS_ACCOUNT_MIGRATION_REQUIRED
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
Base class for ILIAS Exception handling.
static getLogger(string $a_component_id)
Get component logger.
static _lookupId(string|array $a_user_str)
static _writeAuthMode(int $a_usr_id, string $a_auth_mode)
static _checkExternalAuthAccount(string $a_auth, string $a_account, bool $tryFallback=true)
check whether external account and authentication method matches with a user
static _loginExists(string $a_login, int $a_user_id=0)
static getInstanceByIdpId(int $a_idp_id)
static getFirstActiveIdp()
static get(string $a_var)
static set(string $a_var, $a_val)
Set a value.
static strToLower(string $a_string)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
xmlElement(string $tag, $attrs=null, $data=null, $encode=true, $escape=true)
Writes a basic element (no children, just textual content)
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc