ILIAS  trunk Revision v12.0_alpha-1227-g7ff6d300864
class.ilOpenIdConnectSettingsGUI.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
25use Psr\Http\Message\ServerRequestInterface;
29
31{
32 private const STAB_SETTINGS = 'settings';
33 private const STAB_SCOPES = 'scopes';
34 private const STAB_PROFILE = 'profile';
35 private const STAB_ROLES = 'roles';
36 private const VALUE_STRING = '_value';
37 private const UPDATE_STRING = '_update';
38 private const UDF_STRING = 'udf_';
39 private const DEFAULT_CMD = 'settings';
40 private const DEFAULT_VALUES = 1;
41 private const SAVED_VALUES = 2;
42 private const POST_VALUE = 'Mode';
43 private const VIEW_TAB_PRE_FILED = 1;
44 private const VIEW_TAB_EFFECTIVE_MAPPING = 2;
45 private const URL_VALIDATION_PROVIDER_STRING = '/.well-known/openid-configuration';
47
48 private int $ref_id;
50 private $body;
52 private readonly ilLanguage $lng;
53 private readonly ilCtrl $ctrl;
54 private readonly ilLogger $logger;
55 private readonly ilAccessHandler $access;
56 private readonly ilRbacReview $review;
57 private readonly ilErrorHandling $error;
59 private readonly ilTabsGUI $tabs;
60 private readonly FileUpload $upload;
61 private readonly Profile $profile;
66 private ?array $user_defined_fields = null;
69 private ServerRequestInterface $request;
71 private Factory $ui;
73 private Services $http;
75 private \ILIAS\Refinery\Factory $refinery;
76 private string $failed_validation_messages = '';
77
78 public function __construct(int $a_ref_id)
79 {
80 global $DIC;
81
82 $this->ref_id = $a_ref_id;
83
84 $this->lng = $DIC->language();
85 $this->lng->loadLanguageModule('auth');
86
87 $this->mainTemplate = $DIC->ui()->mainTemplate();
88 $this->tabs = $DIC->tabs();
89 $this->ctrl = $DIC->ctrl();
90 $this->logger = $DIC->logger()->auth();
91 $this->access = $DIC->access();
92 $this->review = $DIC->rbac()->review();
93 $this->error = $DIC['ilErr'];
94 $this->upload = $DIC->upload();
95 $this->body = $DIC->http()->request()->getParsedBody();
97 $http_wrapper = $DIC->http()->wrapper();
98 $this->toolbar = $DIC->toolbar();
99 $refinery = $DIC->refinery();
100 $this->tpl = $DIC->ui()->mainTemplate();
101 $this->http = $DIC->http();
102 $this->ui = $DIC->ui()->factory();
103 $this->renderer = $DIC->ui()->renderer();
104 $this->refinery = $DIC->refinery();
105 $this->factory = $DIC->ui()->factory();
106 $this->request = $DIC->http()->request();
107 $this->profile = $DIC['user']->getProfile();
108 $this->attribute_mapping_template = new ilOpenIdAttributeMappingTemplate();
109
110 if ($http_wrapper->query()->has(self::POST_VALUE) && $http_wrapper->query()->retrieve(
111 self::POST_VALUE,
112 $refinery->kindlyTo()->int()
113 )) {
114 $this->mapping_template = $http_wrapper->query()->retrieve(self::POST_VALUE, $refinery->kindlyTo()->int());
115 }
116 }
117
118 private function checkAccess(string $a_permission): void
119 {
120 if (!$this->checkAccessBool($a_permission)) {
121 $this->error->raiseError($this->lng->txt('msg_no_perm_read'), $this->error->WARNING);
122 }
123 }
124
125 private function checkAccessBool(string $a_permission): bool
126 {
127 return $this->access->checkAccess($a_permission, '', $this->ref_id);
128 }
129
130 public function executeCommand(): void
131 {
132 $this->checkAccess('read');
133
134 switch ($this->ctrl->getNextClass()) {
135 default:
136 $cmd = $this->ctrl->getCmd(self::DEFAULT_CMD);
137 $this->$cmd();
138 break;
139 }
140 }
141
142 private function settings(?ilPropertyFormGUI $form = null): void
143 {
144 $this->checkAccess('read');
145
146 $this->setSubTabs(self::STAB_SETTINGS);
147
148 if (!$form instanceof ilPropertyFormGUI) {
149 $form = $this->initSettingsForm();
150 }
151
152 $this->mainTemplate->setContent($form->getHTML());
153 }
154
156 {
157 $form = new ilPropertyFormGUI();
158 $form->setTitle($this->lng->txt('auth_oidc_settings_title'));
159 $form->setFormAction($this->ctrl->getFormAction($this));
160
161 $activation = new ilCheckboxInputGUI(
162 $this->lng->txt('auth_oidc_settings_activation'),
163 'activation'
164 );
165 $activation->setChecked($this->settings->getActive());
166 $form->addItem($activation);
167
169 $this->lng->txt('auth_oidc_settings_provider'),
170 'provider'
171 );
172 $provider->setRequired(true);
173 $provider->setValue($this->settings->getProvider());
174 $form->addItem($provider);
175
177 $this->lng->txt('auth_oidc_settings_client_id'),
178 'client_id'
179 );
180 $client_id->setRequired(true);
181 $client_id->setValue($this->settings->getClientId());
182 $form->addItem($client_id);
183
184 $secret = new ilPasswordInputGUI(
185 $this->lng->txt('auth_oidc_settings_secret'),
186 'secret'
187 );
188 $secret->setSkipSyntaxCheck(true);
189 $secret->setRetype(false);
190 $secret->setRequired(false);
191 if ($this->settings->getSecret() !== '') {
192 $secret->setValue('******');
193 }
194 $form->addItem($secret);
195
196 $login_element = new ilRadioGroupInputGUI(
197 $this->lng->txt('auth_oidc_settings_le'),
198 'le'
199 );
200 $login_element->setRequired(true);
201 $login_element->setValue((string) $this->settings->getLoginElementType());
202 $form->addItem($login_element);
203
204 $text_option = new ilRadioOption(
205 $this->lng->txt('auth_oidc_settings_txt'),
207 );
208 $login_element->addOption($text_option);
209
210 $text = new ilTextInputGUI(
211 '',
212 'le_text'
213 );
214 $text->setValue($this->settings->getLoginElemenText());
215 $text->setMaxLength(120);
216 $text->setInfo($this->lng->txt('auth_oidc_settings_txt_val_info'));
217 $text_option->addSubItem($text);
218
219 $img_option = new ilRadioOption(
220 $this->lng->txt('auth_oidc_settings_img'),
222 );
223 $login_element->addOption($img_option);
224
225 $image = new ilImageFileInputGUI(
226 '',
227 'le_img'
228 );
229 $image->setAllowDeletion(false);
230
231 if ($this->settings->hasImageFile()) {
232 $image->setImage($this->settings->getImageFilePath());
233 }
234 $image->setInfo($this->lng->txt('auth_oidc_settings_img_file_info'));
235 $img_option->addSubItem($image);
236
237 $login_options = new ilRadioGroupInputGUI(
238 $this->lng->txt('auth_oidc_settings_login_options'),
239 'login_prompt'
240 );
241 $login_options->setValue((string) $this->settings->getLoginPromptType());
242
243 $enforce = new ilRadioOption(
244 $this->lng->txt('auth_oidc_settings_login_option_enforce'),
246 );
247 $enforce->setInfo($this->lng->txt('auth_oidc_settings_login_option_enforce_info'));
248 $login_options->addOption($enforce);
249
250 $default = new ilRadioOption(
251 $this->lng->txt('auth_oidc_settings_login_option_default'),
253 );
254 $default->setInfo($this->lng->txt('auth_oidc_settings_login_option_default_info'));
255 $login_options->addOption($default);
256
257 $form->addItem($login_options);
258
259 $logout_scope = new ilRadioGroupInputGUI(
260 $this->lng->txt('auth_oidc_settings_logout_scope'),
261 'logout_scope'
262 );
263 $logout_scope->setValue((string) $this->settings->getLogoutScope());
264
265 $global_scope = new ilRadioOption(
266 $this->lng->txt('auth_oidc_settings_logout_scope_global'),
268 );
269 $global_scope->setInfo($this->lng->txt('auth_oidc_settings_logout_scope_global_info'));
270 $logout_scope->addOption($global_scope);
271
272 $ilias_scope = new ilRadioOption(
273 $this->lng->txt('auth_oidc_settings_logout_scope_local'),
275 );
276 $ilias_scope->setInfo($this->lng->txt('auth_oidc_settings_logout_scope_local_info'));
277 $logout_scope->addOption($ilias_scope);
278
279 $form->addItem($logout_scope);
280
281 $use_custom_session = new ilCheckboxInputGUI(
282 $this->lng->txt('auth_oidc_settings_custom_session_duration_type'),
283 'custom_session'
284 );
285 $use_custom_session->setOptionTitle(
286 $this->lng->txt('auth_oidc_settings_custom_session_duration_option')
287 );
288 $use_custom_session->setChecked($this->settings->isCustomSession());
289 $form->addItem($use_custom_session);
290
291 $session = new ilNumberInputGUI(
292 $this->lng->txt('auth_oidc_settings_session_duration'),
293 'session_duration'
294 );
295 $session->setValue((string) $this->settings->getSessionDuration());
296 $session->setSuffix($this->lng->txt('minutes'));
297 $session->setMinValue(5);
298 $session->setMaxValue(1440);
299 $session->setRequired(true);
300 $use_custom_session->addSubItem($session);
301
302 if ($this->checkAccessBool('write')) {
303 $form->addCommandButton('saveSettings', $this->lng->txt('save'));
304 }
305
306 $user_sync = new ilFormSectionHeaderGUI();
307 $user_sync->setTitle($this->lng->txt('auth_oidc_settings_section_user_sync'));
308 $form->addItem($user_sync);
309
310 $sync = new ilCheckboxInputGUI(
311 $this->lng->txt('auth_oidc_settings_user_sync'),
312 'sync'
313 );
314 $sync->setChecked($this->settings->isSyncAllowed());
315 $sync->setInfo($this->lng->txt('auth_oidc_settings_user_sync_info'));
316 $sync->setValue('1');
317 $form->addItem($sync);
318
319 $roles = new ilSelectInputGUI(
320 $this->lng->txt('auth_oidc_settings_default_role'),
321 'role'
322 );
323 $roles->setValue((string) $this->settings->getRole());
324 $roles->setInfo($this->lng->txt('auth_oidc_settings_default_role_info'));
325 $roles->setOptions($this->prepareRoleSelection());
326 $roles->setRequired(true);
327 $sync->addSubItem($roles);
328
329 $user_attr = new ilTextInputGUI(
330 $this->lng->txt('auth_oidc_settings_user_attr'),
331 'username'
332 );
333 $user_attr->setValue($this->settings->getUidField());
334 $user_attr->setRequired(true);
335 $form->addItem($user_attr);
336
337 if (!$this->checkAccessBool('write')) {
338 foreach ($form->getItems() as $item) {
339 if ($item instanceof ilFormSectionHeaderGUI) {
340 continue;
341 }
342
343 $item->setDisabled(true);
344 }
345 }
346
347 return $form;
348 }
349
350 private function saveSettings(): void
351 {
352 $this->checkAccess('write');
353
354 $form = $this->initSettingsForm();
355 if (!$form->checkInput()) {
356 $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
357 $form->setValuesByPost();
358 $this->settings($form);
359 return;
360 }
361
362 $this->settings->setActive((bool) $form->getInput('activation'));
363 $this->settings->setProvider((string) $form->getInput('provider'));
364 $this->settings->setClientId((string) $form->getInput('client_id'));
365 if ((string) $form->getInput('secret') !== '' && strcmp($form->getInput('secret'), '******') !== 0) {
366 $this->settings->setSecret((string) $form->getInput('secret'));
367 }
368
369 $this->settings->setLoginElementType((int) $form->getInput('le'));
370 $this->settings->setLoginElementText((string) $form->getInput('le_text'));
371 $this->settings->setLoginPromptType((int) $form->getInput('login_prompt'));
372 $this->settings->setLogoutScope((int) $form->getInput('logout_scope'));
373 $this->settings->useCustomSession((bool) $form->getInput('custom_session'));
374 $this->settings->setSessionDuration((int) $form->getInput('session_duration'));
375 $this->settings->allowSync((bool) $form->getInput('sync'));
376 $this->settings->setRole((int) $form->getInput('role'));
377 $this->settings->setUidField((string) $form->getInput('username'));
378
379 $fileData = (array) $form->getInput('le_img');
380
381 if ((string) ($fileData['tmp_name'] ?? '') !== '') {
383 }
384
385 $this->settings->save();
386
387 $this->mainTemplate->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
388 $this->ctrl->redirect($this, 'settings');
389 }
390
391 private function saveImageFromHttpRequest(): void
392 {
393 try {
394 if (!$this->upload->hasBeenProcessed()) {
395 $this->upload->process();
396 }
397
398 foreach ($this->upload->getResults() as $single_file_upload) {
399 if ($single_file_upload->isOK()) {
400 $this->settings->deleteImageFile();
401 $this->upload->moveFilesTo(
403 \ILIAS\FileUpload\Location::WEB
404 );
405 $this->settings->setLoginElementImage($single_file_upload->getName());
406 }
407 }
408 } catch (\ILIAS\Filesystem\Exception\IllegalStateException $e) {
409 $this->logger->warning('Upload failed with message: ' . $e->getMessage());
410 }
411 }
412
416 private function prepareRoleSelection(bool $a_with_select_option = true): array
417 {
418 $global_roles = ilUtil::_sortIds(
419 $this->review->getGlobalRoles(),
420 'object_data',
421 'title',
422 'obj_id'
423 );
424
425 $select = [];
426 if ($a_with_select_option) {
427 $select[0] = $this->lng->txt('links_select_one');
428 }
429 foreach ($global_roles as $role_id) {
430 if ($role_id === ANONYMOUS_ROLE_ID) {
431 continue;
432 }
433 $select[(string) $role_id] = ilObject::_lookupTitle((int) $role_id);
434 }
435
436 return $select;
437 }
438
439 private function profile(): void
440 {
441 $this->checkAccess('read');
442
444
445 $this->chooseMapping();
446 $this->userMapping();
447 }
448
449 private function scopes(): void
450 {
451 $this->checkAccess('read');
452
454
455 $this->setSubTabs(self::STAB_SCOPES);
456 $url = $this->settings->getProvider();
457 if ($url !== '' && $this->checkAccessBool('write')) {
458 $this->toolbar->setFormAction($this->ctrl->getFormAction($this));
459 $this->toolbar->addFormButton($this->lng->txt('auth_oidc_discover_scopes'), 'discoverScopesFromServer');
460 }
461
462 $form = $this->initScopesForm();
463 $this->tpl->setContent($this->renderer->render($form));
464 }
465
466 private function initScopesForm(): Form
467 {
468 $this->checkAccess('read');
469
470 $ui_container = [];
471 $has_write_access = $this->checkAccessBool('write');
472 $ui_container = $this->buildScopeSelection($ui_container, $has_write_access);
473
475 $form = $this->ui->input()->container()->form()->standard(
476 $has_write_access ? $this->ctrl->getFormAction($this, 'saveScopes') : $this->ctrl->getFormAction($this, 'scopes'),
477 $ui_container
478 )->withAdditionalTransformation($this->saniziteArrayElementsTrafo());
479
480 if (!$has_write_access) {
481 $form = $form->withSubmitLabel($this->lng->txt('refresh'));
482 }
483
484 return $form;
485 }
486
487 private function discoverScopesFromServer(): void
488 {
489 $url = '';
490 $type = $this->settings->getValidateScopes();
492 $url = $this->settings->getProvider() . self::URL_VALIDATION_PROVIDER_STRING;
494 $url = $this->settings->getCustomDiscoveryUrl();
495 }
496
497 if ($url !== '') {
498 $found_scopes = $this->settings->getSupportedScopesFromUrl($url);
499 if ($found_scopes === true) {
500 $this->mainTemplate->setOnScreenMessage('success', $this->lng->txt('auth_oidc_discover_scopes_info'));
501 }
502 }
503
504 $this->scopes();
505 }
506
511 private function buildScopeSelection(array $ui_container, bool $has_write_access): array
512 {
513 $disabled_input = $this->ui
514 ->input()
515 ->field()
516 ->text($this->lng->txt('auth_oidc_settings_default_scopes'), '')
517 ->withAdditionalTransformation($this->trimIfStringTrafo())
519 ->withDedicatedName('default_scope')
520 ->withDisabled(true);
521
522 $scopeValues = $this->settings->getAdditionalScopes();
523
524 $tag_input = $this->ui
525 ->input()
526 ->field()
527 ->tag(
528 $this->lng->txt('auth_oidc_settings_additional_scopes'),
529 $scopeValues
530 )->withValue($scopeValues)
531 ->withDedicatedName('custom_scope')
532 ->withByline($this->lng->txt('auth_oidc_settings_additional_scopes_info'));
533 $group1 = $this->ui->input()->field()->group(
534 [],
535 $this->lng->txt('auth_oidc_settings_validate_scope_default')
536 );
537 $group2 = $this->ui->input()->field()->group(
538 [
539 $this->lng->txt('auth_oidc_settings_discovery_url') => $this->ui
540 ->input()
541 ->field()
542 ->text(
543 $this->lng->txt('auth_oidc_settings_discovery_url')
544 )
545 ->withAdditionalTransformation($this->trimIfStringTrafo())
546 ->withValue(
547 $this->settings->getCustomDiscoveryUrl() ?? ''
548 )
549 ],
550 $this->lng->txt('auth_oidc_settings_validate_scope_custom')
551 );
552 $group3 = $this->ui->input()->field()->group(
553 [],
554 $this->lng->txt('auth_oidc_settings_validate_scope_none')
555 );
556 $url_validation = $this->ui->input()->field()->switchableGroup(
557 [
561 ],
562 $this->lng->txt('auth_oidc_settings_validate_scopes')
563 )->withDedicatedName('validate_scopes')->withValue($this->settings->getValidateScopes());
564 $group = $this->ui->input()->field()->group(
565 [$disabled_input, $tag_input, $url_validation]
566 );
567 $ui_container[] = $group;
568
569 if (!$has_write_access) {
570 foreach ($ui_container as $key => $item) {
571 $ui_container[$key] = $item->withDisabled(true);
572 }
573 }
574
575 return $ui_container;
576 }
577
578 private function saveScopes(): void
579 {
580 $this->checkAccess('write');
581
582 $validation = false;
583 $type = null;
584 $url = null;
585 $custom_scopes = [];
586
587 $form = $this->initScopesForm();
588 if ($this->request->getMethod() === 'POST') {
589 $request_form = $form->withRequest($this->request);
590 $result = $request_form->getData();
591 if ($result === null) {
592 $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
593 $this->scopes();
594 return;
595 }
596
597 foreach ($form->getInputs() as $group => $groups) {
598 foreach ($groups->getInputs() as $key => $input) {
599 $dedicated_name = $input->getDedicatedName();
600 $result_data = $result[$group][$key];
601 if ($dedicated_name === 'validate_scopes') {
602 $type = (int) $result_data[0];
603 $url = array_pop($result_data[1]);
604 } elseif ($dedicated_name === 'custom_scope') {
605 $custom_scopes = $result_data;
606 }
607 }
608 }
609
610 if ($url === null && $type === ilOpenIdConnectSettings::URL_VALIDATION_PROVIDER) {
611 $url = $this->settings->getProvider();
612 }
613 $validation = $this->validateDiscoveryUrl($type, $url, $custom_scopes);
614 }
615
616 if ($validation) {
617 $this->settings->setAdditionalScopes((array) $custom_scopes);
618 $this->settings->setValidateScopes((int) $type);
619 if (ilOpenIdConnectSettings::URL_VALIDATION_CUSTOM === $this->settings->getValidateScopes()) {
620 $this->settings->setCustomDiscoveryUrl($url);
621 }
622 $this->settings->save();
623 $this->mainTemplate->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
624 $this->ctrl->redirect($this, 'scopes');
625 }
626
627 if ($this->failed_validation_messages !== '') {
628 $this->failed_validation_messages = $this->lng->txt(
629 'err_check_input'
631 } else {
632 $this->failed_validation_messages = $this->lng->txt('err_check_input');
633 }
634
635 $this->mainTemplate->setOnScreenMessage('failure', $this->failed_validation_messages, true);
636 $this->ctrl->redirect($this, 'scopes');
637 }
638
642 private function validateDiscoveryUrl(int $type, ?string $url, array $scopes): bool
643 {
644 try {
645 switch ($type) {
648 break;
650 $discoveryURL = $url;
651 break;
652 default:
653 $discoveryURL = null;
654 break;
655 }
656
657 $validation_result = $discoveryURL !== null ? $this->settings->validateScopes(
658 $discoveryURL,
659 $scopes
660 ) : [];
661 if (!empty($validation_result)) {
662 if (ilOpenIdConnectSettings::VALIDATION_ISSUE_INVALID_SCOPE === $validation_result[0]) {
663 $this->failed_validation_messages =
664 sprintf(
665 $this->lng->txt('auth_oidc_settings_invalid_scopes'),
666 implode(',', $validation_result[1])
667 );
668 } else {
669 $this->failed_validation_messages = sprintf(
670 $this->lng->txt('auth_oidc_settings_discovery_error'),
671 $validation_result[1]
672 );
673 }
674 $this->scopes();
675
676 return false;
677 }
678 } catch (ilCurlConnectionException $e) {
679 $this->mainTemplate->setOnScreenMessage(
680 'failure',
681 $e->getMessage(),
682 true
683 );
684 $this->failed_validation_messages = $e->getMessage();
685 $this->scopes();
686
687 return false;
688 }
689
690 return true;
691 }
692
693 private function saveProfileMapping(): void
694 {
695 $this->checkAccessBool('write');
696
697 $form = $this->initUserMappingForm();
698 if ($this->request->getMethod() === 'POST' &&
699 $this->request->getQueryParams()['opic'] === 'opic_user_data_mapping') {
700 $request_form = $form->withRequest($this->request);
701 $result = $request_form->getData();
702 if ($result === null) {
703 $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
704 $this->profile();
705 return;
706 }
707
708 foreach ($this->settings->getProfileMappingFields() as $field => $lng_key) {
709 $this->updateProfileMappingFieldValue($field);
710 }
711
712 foreach ($this->user_defined_fields as $field) {
713 $this->updateProfileMappingFieldValue(self::UDF_STRING . $field->getIdentifier());
714 }
715 }
716
717 $this->settings->save();
718
719 $this->mainTemplate->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
720 $this->ctrl->redirect($this, self::STAB_PROFILE);
721 }
722
723 private function updateProfileMappingFieldValue(string $field): void
724 {
725 $form = $this->initUserMappingForm();
726 $request_form = $form->withRequest($this->request);
727 $result = $request_form->getData();
728 foreach ($form->getInputs() as $group => $groups) {
729 foreach ($groups->getInputs() as $key => $input) {
730 $dedicated_name = $input->getDedicatedName();
731 $result_data = $result[$group][$key];
732
733 if ($dedicated_name === $field . self::VALUE_STRING) {
734 $this->settings->setProfileMappingFieldValue(
735 $field,
736 $result_data
737 );
738 } elseif ($dedicated_name === $field . self::UPDATE_STRING) {
739 $this->settings->setProfileMappingFieldUpdate(
740 $field,
741 (bool) $result_data
742 );
743 }
744 }
745 }
746 }
747
748 private function roles(?ilPropertyFormGUI $form = null): void
749 {
750 $this->checkAccess('read');
751
753
754 $this->setSubTabs(self::STAB_ROLES);
755
756 if (!$form instanceof ilPropertyFormGUI) {
757 $form = $this->initRolesForm();
758 }
759
760 $this->mainTemplate->setContent($form->getHTML());
761 }
762
764 {
765 $form = new ilPropertyFormGUI();
766 $form->setTitle($this->lng->txt('auth_oidc_role_mapping_table'));
767 $form->setFormAction($this->ctrl->getFormAction($this, self::STAB_ROLES));
768
769 foreach ($this->prepareRoleSelection(false) as $role_id => $role_title) {
770 $role_map = new ilTextInputGUI(
771 $role_title,
772 'role_map_' . $role_id
773 );
774 $role_map->setInfo($this->lng->txt('auth_oidc_role_info'));
775 $role_map->setValue($this->settings->getRoleMappingValueForId((int) $role_id));
776 $form->addItem($role_map);
777
778 $update = new ilCheckboxInputGUI(
779 '',
780 'role_map_update_' . $role_id
781 );
782 $update->setOptionTitle($this->lng->txt('auth_oidc_update_role_info'));
783 $update->setValue('1');
784 $update->setChecked(!$this->settings->getRoleMappingUpdateForId((int) $role_id));
785 $form->addItem($update);
786 }
787
788 if ($this->checkAccessBool('write')) {
789 $form->addCommandButton('saveRoles', $this->lng->txt('save'));
790 } else {
791 foreach ($form->getItems() as $item) {
792 if ($item instanceof ilFormSectionHeaderGUI) {
793 continue;
794 }
795
796 $item->setDisabled(true);
797 }
798 }
799
800 return $form;
801 }
802
803 private function saveRoles(): void
804 {
805 $this->checkAccess('write');
806
807 $form = $this->initRolesForm();
808 if ($form->checkInput()) {
809 $this->logger->dump($this->body, ilLogLevel::DEBUG);
810
811 $role_settings = [];
812 $role_valid = true;
813 foreach ($this->prepareRoleSelection(false) as $role_id => $role_title) {
814 $role_settings[(int) $role_id]['update'] = !$form->getInput('role_map_update_' . $role_id);
815 $role_settings[(int) $role_id]['value'] = '';
816
817 $input_role = trim($form->getInput('role_map_' . $role_id));
818 if ($input_role === '') {
819 continue;
820 }
821
822 $role_params = explode('::', $input_role);
823 $this->logger->dump($role_params, ilLogLevel::DEBUG);
824
825 if (count($role_params) !== 2) {
826 if ($form->getItemByPostVar('role_map_' . $role_id)) {
827 $form->getItemByPostVar('role_map_' . $role_id)->setAlert($this->lng->txt('msg_wrong_format'));
828 }
829 $role_valid = false;
830 continue;
831 }
832 $role_settings[(int) $role_id]['value'] = $input_role;
833 }
834
835 if (!$role_valid) {
836 $form->setValuesByPost();
837 $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
838 $this->roles($form);
839 return;
840 }
841
842 $this->settings->setRoleMappings($role_settings);
843 $this->settings->save();
844 $this->mainTemplate->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
845 $this->ctrl->redirect($this, 'roles');
846 }
847
848 $form->setValuesByPost();
849
850 $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
851
852 $this->roles($form);
853 }
854
855 private function setSubTabs(string $active_tab): void
856 {
857 $this->tabs->addSubTab(
858 self::STAB_SETTINGS,
859 $this->lng->txt('auth_oidc_' . self::STAB_SETTINGS),
860 $this->ctrl->getLinkTarget($this, self::STAB_SETTINGS)
861 );
862
863 $url = $this->settings->getProvider();
864 if ($url !== '') {
865 $this->tabs->addSubTab(
866 self::STAB_SCOPES,
867 $this->lng->txt('auth_oidc_' . self::STAB_SCOPES),
868 $this->ctrl->getLinkTarget($this, self::STAB_SCOPES)
869 );
870
871 $this->tabs->addSubTab(
872 self::STAB_PROFILE,
873 $this->lng->txt('auth_oidc_' . self::STAB_PROFILE),
874 $this->ctrl->getLinkTarget($this, self::STAB_PROFILE)
875 );
876 $this->tabs->addSubTab(
877 self::STAB_ROLES,
878 $this->lng->txt('auth_oidc_' . self::STAB_ROLES),
879 $this->ctrl->getLinkTarget($this, self::STAB_ROLES)
880 );
881 }
882
883 $this->tabs->activateSubTab($active_tab);
884 }
885
886 private function chooseMapping(): void
887 {
888 $this->showInfoMessage();
889
890 $this->setSubTabs(self::STAB_PROFILE);
891
892 if ((int) $this->mapping_template === self::VIEW_TAB_EFFECTIVE_MAPPING) {
893 $this->userMapping();
894 return;
895 }
896
897 $this->initAttributeMapping();
898 }
899
900 private function showInfoMessage(): void
901 {
902 if ($this->mapping_template === self::VIEW_TAB_EFFECTIVE_MAPPING) {
903 $url = $this->renderer->render(
904 $this->factory->link()->standard(
905 $this->lng->txt('auth_oidc_here'),
906 'https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims'
907 )->withOpenInNewViewport(true)
908 );
909 $message = sprintf($this->lng->txt('auth_odic_scope_tab_info'), $url);
910 } else {
911 $url = $this->renderer->render(
912 $this->factory->link()->standard(
913 $this->lng->txt('auth_oidc_here'),
914 $this->ctrl->getLinkTarget($this, self::STAB_SCOPES)
915 )
916 );
917 $tab_name = $this->lng->txt('auth_oidc_configured_scopes');
918 $message = sprintf($this->lng->txt('auth_odic_scope_info'), $url, $tab_name);
919 }
920
921 $this->mainTemplate->setOnScreenMessage('info', $message);
922 }
923
924 private function initAttributeMapping(): void
925 {
926 $mapping = $this->attribute_mapping_template->getMappingRulesByAdditionalScopes(
927 $this->settings->getAdditionalScopes()
928 );
929
930 if (count($mapping) > 0) {
931 $this->settings->clearProfileMaps();
932 }
933
934 foreach ($mapping as $field => $item) {
935 $this->settings->setProfileMappingFieldValue(
936 $field,
937 $item
938 );
939 }
940
941 $this->userMapping();
942 }
943
944 private function initUserMappingForm(): Form
945 {
946 $this->initUserDefinedFields();
947
948 $ui_container = [];
949 foreach ($this->settings->getProfileMappingFields() as $mapping => $lang) {
950 $ui_container = $this->buildUserMappingInputForUserData($lang, $mapping, $ui_container);
951 }
952
953 foreach ($this->user_defined_fields as $field) {
954 $ui_container = $this->buildUserMappingInputFormUDF($field, $ui_container);
955 }
956
957 $has_write_access = $this->checkAccessBool('write');
958 if (!$has_write_access) {
959 foreach ($ui_container as $key => $item) {
960 $ui_container[$key] = $item->withDisabled(true);
961 }
962 }
963
964 $this->ctrl->setParameter(
965 $this,
966 'opic',
967 'opic_user_data_mapping'
968 );
969
971 $form = $this->ui
972 ->input()
973 ->container()
974 ->form()
975 ->standard(
976 $has_write_access ? $this->ctrl->getFormAction($this, 'saveProfileMapping') : $this->ctrl->getFormAction($this, 'profile'),
977 $ui_container
978 )->withAdditionalTransformation($this->saniziteArrayElementsTrafo());
979
980 if (!$has_write_access) {
981 $form = $form->withSubmitLabel($this->lng->txt('refresh'));
982 }
983
984 return $form;
985 }
986
992 ILIAS\User\Profile\Fields\Field $definition,
993 array $ui_container
994 ): array {
995 $value = $this->settings->getProfileMappingFieldValue(self::UDF_STRING . $definition->getIdentifier());
996 $update = $this->settings->getProfileMappingFieldUpdate(self::UDF_STRING . $definition->getIdentifier());
997
998 $text_input = $this->ui
999 ->input()
1000 ->field()
1001 ->text($definition->getLabel($this->lng), '')
1002 ->withAdditionalTransformation($this->trimIfStringTrafo())
1003 ->withValue($value)
1004 ->withDedicatedName(self::UDF_STRING . $definition->getIdentifier() . self::VALUE_STRING);
1005 $checkbox_input = $this->ui
1006 ->input()
1007 ->field()->checkbox('', $this->lng->txt('auth_oidc_update_field_info'))
1008 ->withValue($update)
1009 ->withDedicatedName(
1010 self::UDF_STRING . $definition->getIdentifier() . self::UPDATE_STRING
1011 );
1012 $group = $this->ui->input()->field()->group(
1013 [$text_input, $checkbox_input]
1014 );
1015 $ui_container[] = $group;
1016
1017 return $ui_container;
1018 }
1019
1024 private function buildUserMappingInputForUserData(string $lang, string $mapping, array $ui_container): array
1025 {
1026 $value = $this->settings->getProfileMappingFieldValue($mapping);
1027 $update = $this->settings->getProfileMappingFieldUpdate($mapping);
1028
1029 $text_input = $this->ui
1030 ->input()
1031 ->field()
1032 ->text($lang, '')
1033 ->withAdditionalTransformation($this->trimIfStringTrafo())
1034 ->withValue($value)
1035 ->withDedicatedName($mapping . self::VALUE_STRING);
1036 $checkbox_input = $this->ui
1037 ->input()
1038 ->field()
1039 ->checkbox('', $this->lng->txt('auth_oidc_update_field_info'))
1040 ->withValue($update)
1041 ->withDedicatedName($mapping . self::UPDATE_STRING);
1042 $group = $this->ui->input()->field()->group(
1043 [
1044 $text_input,
1045 $checkbox_input
1046 ]
1047 );
1048 $ui_container[] = $group;
1049
1050 return $ui_container;
1051 }
1052
1053 private function initUserDefinedFields(): void
1054 {
1055 if ($this->user_defined_fields === null) {
1056 $this->user_defined_fields = $this->profile->getAllUserDefinedFields();
1057 }
1058 }
1059
1060 private function userMapping(): void
1061 {
1062 $form = $this->initUserMappingForm();
1063
1064 $request_wrapper = $this->http->wrapper()->query();
1065 $active = self::EFFECTIVE_ATTRIBUTE_MAPPING_TAB;
1066
1067 $target = $this->http->request()->getRequestTarget();
1068 if ($request_wrapper->has(self::POST_VALUE) && $request_wrapper->retrieve(
1069 self::POST_VALUE,
1070 $this->refinery->kindlyTo()->int()
1071 )) {
1072 $active = $request_wrapper->retrieve(self::POST_VALUE, $this->refinery->kindlyTo()->int());
1073 }
1074
1075 $actions = [
1076 $this->lng->txt('auth_oidc_saved_values') => "$target&" . self::POST_VALUE . '=' . self::SAVED_VALUES,
1077 $this->lng->txt(
1079 ) => "$target&" . self::POST_VALUE . '=' . self::DEFAULT_VALUES,
1080 ];
1081
1082 $aria_label = 'change_the_currently_displayed_mode';
1083 $active_label = $this->lng->txt('auth_oidc_saved_values');
1084 if ($active !== self::EFFECTIVE_ATTRIBUTE_MAPPING_TAB) {
1086 }
1087 $view_control = $this->factory->viewControl()->mode($actions, $aria_label)->withActive($active_label);
1088
1089 $this->tpl->setContent($this->renderer->render([$view_control, $form]));
1090 }
1091
1093 {
1094 $url = $this->settings->getProvider();
1095 if ($url === '') {
1096 $this->tpl->setOnScreenMessage(
1097 $this->tpl::MESSAGE_TYPE_FAILURE,
1098 $this->lng->txt('permission_denied'),
1099 true
1100 );
1101 $this->ctrl->redirect($this, 'settings');
1102 }
1103 }
1104
1105 private function saniziteArrayElementsTrafo(): \ILIAS\Refinery\Transformation
1106 {
1107 return $this->refinery->custom()->transformation(static function (array $values): array {
1108 return ilArrayUtil::stripSlashesRecursive($values);
1109 });
1110 }
1111
1112 private function trimIfStringTrafo(): \ILIAS\Refinery\Transformation
1113 {
1114 return $this->refinery->custom()->transformation(static function ($value) {
1115 if (is_string($value)) {
1116 $value = trim($value);
1117 }
1118
1119 return $value;
1120 });
1121 }
1122}
mainTemplate()
renderer()
factory()
Builds a Color from either hex- or rgb values.
Definition: Factory.php:31
Class Services.
Definition: Services.php:38
error(string $a_errmsg)
static stripSlashesRecursive($a_data, bool $a_strip_html=true, string $a_allow="")
This class represents a checkbox property in a property form.
Class ilCtrl provides processing control methods.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Error Handling & global info handling.
This class represents a section header in a property form.
This class represents an image file property in a property form.
language handling
Component logger with individual log levels by component id.
This class represents a number property in a property form.
static _lookupTitle(int $obj_id)
buildScopeSelection(array $ui_container, bool $has_write_access)
roles(?ilPropertyFormGUI $form=null)
ilOpenIdAttributeMappingTemplate $attribute_mapping_template
readonly ilGlobalTemplateInterface $mainTemplate
readonly ilOpenIdConnectSettings $settings
settings(?ilPropertyFormGUI $form=null)
prepareRoleSelection(bool $a_with_select_option=true)
buildUserMappingInputForUserData(string $lang, string $mapping, array $ui_container)
buildUserMappingInputFormUDF(ILIAS\User\Profile\Fields\Field $definition, array $ui_container)
validateDiscoveryUrl(int $type, ?string $url, array $scopes)
This class represents a password property in a property form.
This class represents a property form user interface.
This class represents a property in a property form.
This class represents an option in a radio group.
class ilRbacReview Contains Review functions of core Rbac.
This class represents a selection list property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This class represents a text property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _sortIds(array $a_ids, string $a_table, string $a_field, string $a_id_name)
Function that sorts ids by a given table field using WHERE IN E.g: __sort(array(6,...
const ANONYMOUS_ROLE_ID
Definition: constants.php:28
This describes inputs that can be used in forms.
Definition: FormInput.php:33
This describes commonalities between all forms.
Definition: Form.php:34
This is how the factory for UI elements looks.
Definition: Factory.php:38
An entity that renders components to a string output.
Definition: Renderer.php:31
Interface ilAccessHandler This interface combines all available interfaces which can be called via gl...
$client_id
Definition: ltiauth.php:67
$scopes
Definition: ltitoken.php:96
$provider
Definition: ltitoken.php:80
static http()
Fetches the global http state from ILIAS.
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.
global $DIC
Definition: shib_login.php:26
$url
Definition: shib_logout.php:70
$text
Definition: xapiexit.php:21