ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
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 return $form;
338 }
339
340 private function saveSettings(): void
341 {
342 $this->checkAccess('write');
343
344 $form = $this->initSettingsForm();
345 if (!$form->checkInput()) {
346 $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
347 $form->setValuesByPost();
348 $this->settings($form);
349 return;
350 }
351
352 $this->settings->setActive((bool) $form->getInput('activation'));
353 $this->settings->setProvider((string) $form->getInput('provider'));
354 $this->settings->setClientId((string) $form->getInput('client_id'));
355 if ((string) $form->getInput('secret') !== '' && strcmp($form->getInput('secret'), '******') !== 0) {
356 $this->settings->setSecret((string) $form->getInput('secret'));
357 }
358
359 $this->settings->setLoginElementType((int) $form->getInput('le'));
360 $this->settings->setLoginElementText((string) $form->getInput('le_text'));
361 $this->settings->setLoginPromptType((int) $form->getInput('login_prompt'));
362 $this->settings->setLogoutScope((int) $form->getInput('logout_scope'));
363 $this->settings->useCustomSession((bool) $form->getInput('custom_session'));
364 $this->settings->setSessionDuration((int) $form->getInput('session_duration'));
365 $this->settings->allowSync((bool) $form->getInput('sync'));
366 $this->settings->setRole((int) $form->getInput('role'));
367 $this->settings->setUidField((string) $form->getInput('username'));
368
369 $fileData = (array) $form->getInput('le_img');
370
371 if ((string) ($fileData['tmp_name'] ?? '') !== '') {
373 }
374
375 $this->settings->save();
376
377 $this->mainTemplate->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
378 $this->ctrl->redirect($this, 'settings');
379 }
380
381 private function saveImageFromHttpRequest(): void
382 {
383 try {
384 if (!$this->upload->hasBeenProcessed()) {
385 $this->upload->process();
386 }
387
388 foreach ($this->upload->getResults() as $single_file_upload) {
389 if ($single_file_upload->isOK()) {
390 $this->settings->deleteImageFile();
391 $this->upload->moveFilesTo(
393 \ILIAS\FileUpload\Location::WEB
394 );
395 $this->settings->setLoginElementImage($single_file_upload->getName());
396 }
397 }
398 } catch (\ILIAS\Filesystem\Exception\IllegalStateException $e) {
399 $this->logger->warning('Upload failed with message: ' . $e->getMessage());
400 }
401 }
402
406 private function prepareRoleSelection(bool $a_with_select_option = true): array
407 {
408 $global_roles = ilUtil::_sortIds(
409 $this->review->getGlobalRoles(),
410 'object_data',
411 'title',
412 'obj_id'
413 );
414
415 $select = [];
416 if ($a_with_select_option) {
417 $select[0] = $this->lng->txt('links_select_one');
418 }
419 foreach ($global_roles as $role_id) {
420 if ($role_id === ANONYMOUS_ROLE_ID) {
421 continue;
422 }
423 $select[(string) $role_id] = ilObject::_lookupTitle((int) $role_id);
424 }
425
426 return $select;
427 }
428
429 private function profile(): void
430 {
431 $this->checkAccess('read');
432
434
435 $this->chooseMapping();
436 $this->userMapping();
437 }
438
439 private function scopes(): void
440 {
441 $this->checkAccess('read');
442
444
445 $this->setSubTabs(self::STAB_SCOPES);
446 $url = $this->settings->getProvider();
447 if ($url !== '') {
448 $this->toolbar->setFormAction($this->ctrl->getFormAction($this));
449 $this->toolbar->addFormButton($this->lng->txt('auth_oidc_discover_scopes'), 'discoverScopesFromServer');
450 }
451
452 $form = $this->initScopesForm();
453 $this->tpl->setContent($this->renderer->render($form));
454 }
455
456 private function initScopesForm(): Form
457 {
458 $this->checkAccess('read');
459
460 $ui_container = [];
461 $ui_container = $this->buildScopeSelection($ui_container);
462
464 $form = $this->ui->input()->container()->form()->standard(
465 $this->ctrl->getFormAction($this, 'saveScopes'),
466 $ui_container
467 )->withAdditionalTransformation($this->saniziteArrayElementsTrafo());
468
469 return $form;
470 }
471
472 private function discoverScopesFromServer(): void
473 {
474 $url = '';
475 $type = $this->settings->getValidateScopes();
477 $url = $this->settings->getProvider() . self::URL_VALIDATION_PROVIDER_STRING;
479 $url = $this->settings->getCustomDiscoveryUrl();
480 }
481
482 if ($url !== '') {
483 $found_scopes = $this->settings->getSupportedScopesFromUrl($url);
484 if ($found_scopes === true) {
485 $this->mainTemplate->setOnScreenMessage('success', $this->lng->txt('auth_oidc_discover_scopes_info'));
486 }
487 }
488
489 $this->scopes();
490 }
491
496 private function buildScopeSelection(array $ui_container): array
497 {
498 $disabled_input = $this->ui
499 ->input()
500 ->field()
501 ->text($this->lng->txt('auth_oidc_settings_default_scopes'), '')
502 ->withAdditionalTransformation($this->trimIfStringTrafo())
504 ->withDedicatedName('default_scope')
505 ->withDisabled(true);
506
507 $scopeValues = $this->settings->getAdditionalScopes();
508
509 $tag_input = $this->ui
510 ->input()
511 ->field()
512 ->tag(
513 $this->lng->txt('auth_oidc_settings_additional_scopes'),
514 $scopeValues
515 )->withValue($scopeValues)
516 ->withDedicatedName('custom_scope')
517 ->withByline($this->lng->txt('auth_oidc_settings_additional_scopes_info'));
518 $group1 = $this->ui->input()->field()->group(
519 [],
520 $this->lng->txt('auth_oidc_settings_validate_scope_default')
521 );
522 $group2 = $this->ui->input()->field()->group(
523 [
524 $this->lng->txt('auth_oidc_settings_discovery_url') => $this->ui
525 ->input()
526 ->field()
527 ->text(
528 $this->lng->txt('auth_oidc_settings_discovery_url')
529 )
530 ->withAdditionalTransformation($this->trimIfStringTrafo())
531 ->withValue(
532 $this->settings->getCustomDiscoveryUrl() ?? ''
533 )
534 ],
535 $this->lng->txt('auth_oidc_settings_validate_scope_custom')
536 );
537 $group3 = $this->ui->input()->field()->group(
538 [],
539 $this->lng->txt('auth_oidc_settings_validate_scope_none')
540 );
541 $url_validation = $this->ui->input()->field()->switchableGroup(
542 [
546 ],
547 $this->lng->txt('auth_oidc_settings_validate_scopes')
548 )->withDedicatedName('validate_scopes')->withValue($this->settings->getValidateScopes());
549 $group = $this->ui->input()->field()->group(
550 [$disabled_input, $tag_input, $url_validation]
551 );
552 $ui_container[] = $group;
553
554 return $ui_container;
555 }
556
557 private function saveScopes(): void
558 {
559 $this->checkAccess('write');
560
561 $validation = false;
562 $type = null;
563 $url = null;
564 $custom_scopes = [];
565
566 $form = $this->initScopesForm();
567 if ($this->request->getMethod() === 'POST') {
568 $request_form = $form->withRequest($this->request);
569 $result = $request_form->getData();
570 if ($result === null) {
571 $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
572 $this->scopes();
573 return;
574 }
575
576 foreach ($form->getInputs() as $group => $groups) {
577 foreach ($groups->getInputs() as $key => $input) {
578 $dedicated_name = $input->getDedicatedName();
579 $result_data = $result[$group][$key];
580 if ($dedicated_name === 'validate_scopes') {
581 $type = (int) $result_data[0];
582 $url = array_pop($result_data[1]);
583 } elseif ($dedicated_name === 'custom_scope') {
584 $custom_scopes = $result_data;
585 }
586 }
587 }
588
589 if ($url === null && $type === ilOpenIdConnectSettings::URL_VALIDATION_PROVIDER) {
590 $url = $this->settings->getProvider();
591 }
592 $validation = $this->validateDiscoveryUrl($type, $url, $custom_scopes);
593 }
594
595 if ($validation) {
596 $this->settings->setAdditionalScopes((array) $custom_scopes);
597 $this->settings->setValidateScopes((int) $type);
598 if (ilOpenIdConnectSettings::URL_VALIDATION_CUSTOM === $this->settings->getValidateScopes()) {
599 $this->settings->setCustomDiscoveryUrl($url);
600 }
601 $this->settings->save();
602 $this->mainTemplate->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
603 $this->ctrl->redirect($this, 'scopes');
604 }
605
606 if ($this->failed_validation_messages !== '') {
607 $this->failed_validation_messages = $this->lng->txt(
608 'err_check_input'
610 } else {
611 $this->failed_validation_messages = $this->lng->txt('err_check_input');
612 }
613
614 $this->mainTemplate->setOnScreenMessage('failure', $this->failed_validation_messages, true);
615 $this->ctrl->redirect($this, 'scopes');
616 }
617
621 private function validateDiscoveryUrl(int $type, ?string $url, array $scopes): bool
622 {
623 try {
624 switch ($type) {
627 break;
629 $discoveryURL = $url;
630 break;
631 default:
632 $discoveryURL = null;
633 break;
634 }
635
636 $validation_result = $discoveryURL !== null ? $this->settings->validateScopes(
637 $discoveryURL,
638 $scopes
639 ) : [];
640 if (!empty($validation_result)) {
641 if (ilOpenIdConnectSettings::VALIDATION_ISSUE_INVALID_SCOPE === $validation_result[0]) {
642 $this->failed_validation_messages =
643 sprintf(
644 $this->lng->txt('auth_oidc_settings_invalid_scopes'),
645 implode(',', $validation_result[1])
646 );
647 } else {
648 $this->failed_validation_messages = sprintf(
649 $this->lng->txt('auth_oidc_settings_discovery_error'),
650 $validation_result[1]
651 );
652 }
653 $this->scopes();
654
655 return false;
656 }
657 } catch (ilCurlConnectionException $e) {
658 $this->mainTemplate->setOnScreenMessage(
659 'failure',
660 $e->getMessage(),
661 true
662 );
663 $this->failed_validation_messages = $e->getMessage();
664 $this->scopes();
665
666 return false;
667 }
668
669 return true;
670 }
671
672 private function saveProfileMapping(): void
673 {
674 $this->checkAccessBool('write');
675
676 $form = $this->initUserMappingForm();
677 if ($this->request->getMethod() === 'POST' &&
678 $this->request->getQueryParams()['opic'] === 'opic_user_data_mapping') {
679 $request_form = $form->withRequest($this->request);
680 $result = $request_form->getData();
681 if ($result === null) {
682 $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
683 $this->profile();
684 return;
685 }
686
687 foreach ($this->settings->getProfileMappingFields() as $field => $lng_key) {
688 $this->updateProfileMappingFieldValue($field);
689 }
690
691 foreach ($this->user_defined_fields as $field) {
692 $field = self::UDF_STRING . $field->getIdentifier();
693 $this->updateProfileMappingFieldValue($field->getIdentifier());
694 }
695 }
696
697 $this->settings->save();
698
699 $this->mainTemplate->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
700 $this->ctrl->redirect($this, self::STAB_PROFILE);
701 }
702
703 private function updateProfileMappingFieldValue(string $field): void
704 {
705 $form = $this->initUserMappingForm();
706 $request_form = $form->withRequest($this->request);
707 $result = $request_form->getData();
708 foreach ($form->getInputs() as $group => $groups) {
709 foreach ($groups->getInputs() as $key => $input) {
710 $dedicated_name = $input->getDedicatedName();
711 $result_data = $result[$group][$key];
712
713 if ($dedicated_name === $field . self::VALUE_STRING) {
714 $this->settings->setProfileMappingFieldValue(
715 $field,
716 $result_data
717 );
718 } elseif ($dedicated_name === $field . self::UPDATE_STRING) {
719 $this->settings->setProfileMappingFieldUpdate(
720 $field,
721 (bool) $result_data
722 );
723 }
724 }
725 }
726 }
727
728 private function roles(?ilPropertyFormGUI $form = null): void
729 {
730 $this->checkAccess('read');
731
733
734 $this->setSubTabs(self::STAB_ROLES);
735
736 if (!$form instanceof ilPropertyFormGUI) {
737 $form = $this->initRolesForm();
738 }
739
740 $this->mainTemplate->setContent($form->getHTML());
741 }
742
744 {
745 $form = new ilPropertyFormGUI();
746 $form->setTitle($this->lng->txt('auth_oidc_role_mapping_table'));
747 $form->setFormAction($this->ctrl->getFormAction($this, self::STAB_ROLES));
748
749 foreach ($this->prepareRoleSelection(false) as $role_id => $role_title) {
750 $role_map = new ilTextInputGUI(
751 $role_title,
752 'role_map_' . $role_id
753 );
754 $role_map->setInfo($this->lng->txt('auth_oidc_role_info'));
755 $role_map->setValue($this->settings->getRoleMappingValueForId((int) $role_id));
756 $form->addItem($role_map);
757
758 $update = new ilCheckboxInputGUI(
759 '',
760 'role_map_update_' . $role_id
761 );
762 $update->setOptionTitle($this->lng->txt('auth_oidc_update_role_info'));
763 $update->setValue('1');
764 $update->setChecked(!$this->settings->getRoleMappingUpdateForId((int) $role_id));
765 $form->addItem($update);
766 }
767
768 if ($this->checkAccessBool('write')) {
769 $form->addCommandButton('saveRoles', $this->lng->txt('save'));
770 }
771
772 return $form;
773 }
774
775 private function saveRoles(): void
776 {
777 $this->checkAccess('write');
778
779 $form = $this->initRolesForm();
780 if ($form->checkInput()) {
781 $this->logger->dump($this->body, ilLogLevel::DEBUG);
782
783 $role_settings = [];
784 $role_valid = true;
785 foreach ($this->prepareRoleSelection(false) as $role_id => $role_title) {
786 $role_settings[(int) $role_id]['update'] = !$form->getInput('role_map_update_' . $role_id);
787 $role_settings[(int) $role_id]['value'] = '';
788
789 $input_role = trim($form->getInput('role_map_' . $role_id));
790 if ($input_role === '') {
791 continue;
792 }
793
794 $role_params = explode('::', $input_role);
795 $this->logger->dump($role_params, ilLogLevel::DEBUG);
796
797 if (count($role_params) !== 2) {
798 if ($form->getItemByPostVar('role_map_' . $role_id)) {
799 $form->getItemByPostVar('role_map_' . $role_id)->setAlert($this->lng->txt('msg_wrong_format'));
800 }
801 $role_valid = false;
802 continue;
803 }
804 $role_settings[(int) $role_id]['value'] = $input_role;
805 }
806
807 if (!$role_valid) {
808 $form->setValuesByPost();
809 $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
810 $this->roles($form);
811 return;
812 }
813
814 $this->settings->setRoleMappings($role_settings);
815 $this->settings->save();
816 $this->mainTemplate->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
817 $this->ctrl->redirect($this, 'roles');
818 }
819
820 $form->setValuesByPost();
821
822 $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
823
824 $this->roles($form);
825 }
826
827 private function setSubTabs(string $active_tab): void
828 {
829 $this->tabs->addSubTab(
830 self::STAB_SETTINGS,
831 $this->lng->txt('auth_oidc_' . self::STAB_SETTINGS),
832 $this->ctrl->getLinkTarget($this, self::STAB_SETTINGS)
833 );
834
835 $url = $this->settings->getProvider();
836 if ($url !== '') {
837 $this->tabs->addSubTab(
838 self::STAB_SCOPES,
839 $this->lng->txt('auth_oidc_' . self::STAB_SCOPES),
840 $this->ctrl->getLinkTarget($this, self::STAB_SCOPES)
841 );
842
843 $this->tabs->addSubTab(
844 self::STAB_PROFILE,
845 $this->lng->txt('auth_oidc_' . self::STAB_PROFILE),
846 $this->ctrl->getLinkTarget($this, self::STAB_PROFILE)
847 );
848 $this->tabs->addSubTab(
849 self::STAB_ROLES,
850 $this->lng->txt('auth_oidc_' . self::STAB_ROLES),
851 $this->ctrl->getLinkTarget($this, self::STAB_ROLES)
852 );
853 }
854
855 $this->tabs->activateSubTab($active_tab);
856 }
857
858 private function chooseMapping(): void
859 {
860 $this->showInfoMessage();
861
862 $this->setSubTabs(self::STAB_PROFILE);
863
864 if ((int) $this->mapping_template === self::VIEW_TAB_EFFECTIVE_MAPPING) {
865 $this->userMapping();
866 return;
867 }
868
869 $this->initAttributeMapping();
870 }
871
872 private function showInfoMessage(): void
873 {
874 if ($this->mapping_template === self::VIEW_TAB_EFFECTIVE_MAPPING) {
875 $url = $this->renderer->render(
876 $this->factory->link()->standard(
877 $this->lng->txt('auth_oidc_here'),
878 'https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims'
879 )->withOpenInNewViewport(true)
880 );
881 $message = sprintf($this->lng->txt('auth_odic_scope_tab_info'), $url);
882 } else {
883 $url = $this->renderer->render(
884 $this->factory->link()->standard(
885 $this->lng->txt('auth_oidc_here'),
886 $this->ctrl->getLinkTarget($this, self::STAB_SCOPES)
887 )
888 );
889 $tab_name = $this->lng->txt('auth_oidc_configured_scopes');
890 $message = sprintf($this->lng->txt('auth_odic_scope_info'), $url, $tab_name);
891 }
892
893 $this->mainTemplate->setOnScreenMessage('info', $message);
894 }
895
896 private function initAttributeMapping(): void
897 {
898 $mapping = $this->attribute_mapping_template->getMappingRulesByAdditionalScopes(
899 $this->settings->getAdditionalScopes()
900 );
901
902 if (count($mapping) > 0) {
903 $this->settings->clearProfileMaps();
904 }
905
906 foreach ($mapping as $field => $item) {
907 $this->settings->setProfileMappingFieldValue(
908 $field,
909 $item
910 );
911 }
912
913 $this->userMapping();
914 }
915
916 private function initUserMappingForm(): Form
917 {
918 $this->initUserDefinedFields();
919
920 $ui_container = [];
921 foreach ($this->settings->getProfileMappingFields() as $mapping => $lang) {
922 $ui_container = $this->buildUserMappingInputForUserData($lang, $mapping, $ui_container);
923 }
924
925 foreach ($this->user_defined_fields as $field) {
926 $ui_container = $this->buildUserMappingInputFormUDF($field, $ui_container);
927 }
928
929 $this->ctrl->setParameter(
930 $this,
931 'opic',
932 'opic_user_data_mapping'
933 );
934
936 $form = $this->ui
937 ->input()
938 ->container()
939 ->form()
940 ->standard(
941 $this->ctrl->getFormAction($this, 'saveProfileMapping'),
942 $ui_container
943 )->withAdditionalTransformation($this->saniziteArrayElementsTrafo());
944
945 return $form;
946 }
947
953 private function buildUserMappingInputFormUDF($definition, array $ui_container): array
954 {
955 $value = $this->settings->getProfileMappingFieldValue(self::UDF_STRING . $definition->getIdentifier());
956 $update = $this->settings->getProfileMappingFieldUpdate(self::UDF_STRING . $definition->getIdentifier());
957
958 $text_input = $this->ui
959 ->input()
960 ->field()
961 ->text($definition->getLabel(), '')
962 ->withAdditionalTransformation($this->trimIfStringTrafo())
963 ->withValue($value)
964 ->withDedicatedName(self::UDF_STRING . $definition->getIdentifier() . self::VALUE_STRING);
965 $checkbox_input = $this->ui
966 ->input()
967 ->field()->checkbox('', $this->lng->txt('auth_oidc_update_field_info'))
968 ->withValue($update)
969 ->withDedicatedName(
970 self::UDF_STRING . $definition->getIdentifier() . self::UPDATE_STRING
971 );
972 $group = $this->ui->input()->field()->group(
973 [$text_input, $checkbox_input]
974 );
975 $ui_container[] = $group;
976
977 return $ui_container;
978 }
979
984 private function buildUserMappingInputForUserData(string $lang, string $mapping, array $ui_container): array
985 {
986 $value = $this->settings->getProfileMappingFieldValue($mapping);
987 $update = $this->settings->getProfileMappingFieldUpdate($mapping);
988
989 $text_input = $this->ui
990 ->input()
991 ->field()
992 ->text($lang, '')
993 ->withAdditionalTransformation($this->trimIfStringTrafo())
994 ->withValue($value)
995 ->withDedicatedName($mapping . self::VALUE_STRING);
996 $checkbox_input = $this->ui
997 ->input()
998 ->field()
999 ->checkbox('', $this->lng->txt('auth_oidc_update_field_info'))
1000 ->withValue($update)
1001 ->withDedicatedName($mapping . self::UPDATE_STRING);
1002 $group = $this->ui->input()->field()->group(
1003 [
1004 $text_input,
1005 $checkbox_input
1006 ]
1007 );
1008 $ui_container[] = $group;
1009
1010 return $ui_container;
1011 }
1012
1013 private function initUserDefinedFields(): void
1014 {
1015 if ($this->user_defined_fields === null) {
1016 $this->user_defined_fields = $this->profile->getAllUserDefinedFields();
1017 }
1018 }
1019
1020 private function userMapping(): void
1021 {
1022 $form = $this->initUserMappingForm();
1023
1024 $request_wrapper = $this->http->wrapper()->query();
1026
1027 $target = $this->http->request()->getRequestTarget();
1028 if ($request_wrapper->has(self::POST_VALUE) && $request_wrapper->retrieve(
1029 self::POST_VALUE,
1030 $this->refinery->kindlyTo()->int()
1031 )) {
1032 $active = $request_wrapper->retrieve(self::POST_VALUE, $this->refinery->kindlyTo()->int());
1033 }
1034
1035 $actions = [
1036 $this->lng->txt('auth_oidc_saved_values') => "$target&" . self::POST_VALUE . '=' . self::SAVED_VALUES,
1037 $this->lng->txt(
1039 ) => "$target&" . self::POST_VALUE . '=' . self::DEFAULT_VALUES,
1040 ];
1041
1042 $aria_label = 'change_the_currently_displayed_mode';
1043 $active_label = $this->lng->txt('auth_oidc_saved_values');
1044 if ($active !== self::EFFECTIVE_ATTRIBUTE_MAPPING_TAB) {
1046 }
1047 $view_control = $this->factory->viewControl()->mode($actions, $aria_label)->withActive($active_label);
1048
1049 $this->tpl->setContent($this->renderer->render([$view_control, $form]));
1050 }
1051
1053 {
1054 $url = $this->settings->getProvider();
1055 if ($url === '') {
1056 $this->tpl->setOnScreenMessage(
1057 $this->tpl::MESSAGE_TYPE_FAILURE,
1058 $this->lng->txt('permission_denied'),
1059 true
1060 );
1061 $this->ctrl->redirect($this, 'settings');
1062 }
1063 }
1064
1065 private function saniziteArrayElementsTrafo(): \ILIAS\Refinery\Transformation
1066 {
1067 return $this->refinery->custom()->transformation(static function (array $values): array {
1068 return ilArrayUtil::stripSlashesRecursive($values);
1069 });
1070 }
1071
1072 private function trimIfStringTrafo(): \ILIAS\Refinery\Transformation
1073 {
1074 return $this->refinery->custom()->transformation(static function ($value) {
1075 if (is_string($value)) {
1076 $value = trim($value);
1077 }
1078
1079 return $value;
1080 });
1081 }
1082}
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)
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)
buildUserMappingInputFormUDF($definition, array $ui_container)
buildUserMappingInputForUserData(string $lang, string $mapping, 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:33
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:68
$lang
Definition: xapiexit.php:25
$message
Definition: xapiexit.php:31