ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilSamlSettingsGUI.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
21use ILIAS\Refinery\Factory as Refinery;
28
30{
31 private const int VIEW_MODE_GLOBAL = 1;
32 private const int VIEW_MODE_SINGLE = 2;
33
34 public const string DEFAULT_CMD = self::CMD_LIST_IDPS;
35
36 private const string PERMISSION_WRITE = 'write';
37
38 private const string REQUEST_PARAM_SAML_IDP_ID = 'saml_idp_id';
39 private const string REQUEST_PARAM_SAML_IDP_IDS = 'saml_idp_ids';
40
41 private const string MESSAGE_TYPE_FAILURE = 'failure';
42 private const string MESSAGE_TYPE_SUCCESS = 'success';
43
44 private const string LNG_SAVED_SUCCESSFULLY = 'saved_successfully';
45 private const string LNG_AUTH_SAML_USER_MAPPING = 'auth_saml_user_mapping';
46 private const string LNG_LOGIN_FORM = 'login_form';
47 private const string LNG_CANCEL = 'cancel';
48 private const string LNG_SAVE = 'save';
49
50 private const string PROP_UPDATE_SUFFIX = '_update';
51
52 private const string METADATA_STORAGE_KEY = 'metadata';
53 private const string METADATA_ENTITY_ID = 'entity_id';
54
56 private const array IGNORED_USER_FIELDS = [
57 'mail_incoming_mail',
58 'preferences',
59 'hide_own_online_status',
60 'show_users_online',
61 'roles',
62 'upload',
63 'password',
64 'username',
65 'language',
66 'skin_style',
67 'interests_general',
68 'interests_help_offered',
69 'interests_help_looking',
70 'bs_allow_to_contact_me',
71 'chat_osc_accept_msg',
72 'chat_broadcast_typing',
73 ];
74
75 private readonly ilCtrlInterface $ctrl;
76 private readonly ilLanguage $lng;
78 private readonly RBACServices $rbac;
80 private readonly ilTabsGUI $tabs;
81 private readonly ilToolbarGUI $toolbar;
82 private readonly GlobalHttpState $http_state;
83 private readonly Refinery $refinery;
84 private readonly ilHelpGUI $help;
86 private ?ilSamlIdp $idp = null;
87 private ?ilSamlAuth $saml_auth = null;
88 private readonly \ILIAS\UI\Factory $ui_factory;
89 private readonly \ILIAS\UI\Renderer $ui_renderer;
90 private readonly Profile $profile;
91
92 public function __construct(private readonly int $ref_id)
93 {
94 global $DIC;
95
96 $this->ctrl = $DIC->ctrl();
97 $this->tpl = $DIC->ui()->mainTemplate();
98 $this->lng = $DIC->language();
99 $this->rbac = $DIC->rbac();
100 $this->error_handler = $DIC['ilErr'];
101 $this->tabs = $DIC->tabs();
102 $this->toolbar = $DIC['ilToolbar'];
103 $this->help = $DIC['ilHelp'];
104 $this->http_state = $DIC->http();
105 $this->refinery = $DIC->refinery();
106 $this->ui_factory = $DIC->ui()->factory();
107 $this->ui_renderer = $DIC->ui()->renderer();
108 $this->profile = $DIC['user']->getProfile();
109
110 $this->lng->loadLanguageModule('auth');
111 }
112
113 private function ensureAccess(string $operation): void
114 {
115 if (!$this->rbac->system()->checkAccess($operation, $this->ref_id)) {
116 $this->error_handler->raiseError($this->lng->txt('msg_no_perm_read'), $this->error_handler->WARNING);
117 }
118 }
119
120 public function getUnsafeGetCommands(): array
121 {
122 return [
124 ];
125 }
126
127 public function getSafePostCommands(): array
128 {
129 return [];
130 }
131
132 private function ensureWriteAccess(): void
133 {
134 $this->ensureAccess(self::PERMISSION_WRITE);
135 }
136
137 private function ensureReadAccess(): void
138 {
139 $this->ensureAccess('read');
140 }
141
142 public function getRefId(): int
143 {
144 return $this->ref_id;
145 }
146
147 private function getIdpIdOrZero(): int
148 {
149 $idpId = 0;
150 if ($this->http_state->wrapper()->query()->has(self::REQUEST_PARAM_SAML_IDP_ID)) {
151 $idpId = $this->http_state->wrapper()->query()->retrieve(
152 self::REQUEST_PARAM_SAML_IDP_ID,
153 $this->refinery->kindlyTo()->int()
154 );
155 } elseif ($this->http_state->wrapper()->post()->has(self::REQUEST_PARAM_SAML_IDP_ID)) {
156 $idpId = $this->http_state->wrapper()->post()->retrieve(
157 self::REQUEST_PARAM_SAML_IDP_ID,
158 $this->refinery->kindlyTo()->int()
159 );
160 }
161
162 if ($this->getTableAction() && $this->http_state->wrapper()->query()->has('saml_idps_idp_id')) {
163 $idpIds = $this->http_state->wrapper()->query()->retrieve(
164 'saml_idps_idp_id',
165 $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->int())
166 );
167 if (count($idpIds) === 1) {
168 $idpId = current($idpIds);
169 }
170 }
171
172 if ($this->http_state->wrapper()->post()->has(self::REQUEST_PARAM_SAML_IDP_IDS)) {
173 $idpIds = $this->http_state->wrapper()->post()->retrieve(
174 self::REQUEST_PARAM_SAML_IDP_IDS,
175 $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->int())
176 );
177 if (count($idpIds) === 1) {
178 $idpId = current($idpIds);
179 }
180 }
181
182 return $idpId;
183 }
184
185 private function initIdp(): void
186 {
187 try {
188 $this->idp = ilSamlIdp::getInstanceByIdpId($this->getIdpIdOrZero());
189 } catch (Exception) {
190 $this->tpl->setOnScreenMessage(self::MESSAGE_TYPE_FAILURE, $this->lng->txt('auth_saml_unknow_idp'), true);
191 $this->ctrl->setParameter($this, self::REQUEST_PARAM_SAML_IDP_ID, null);
192 $this->ctrl->redirect($this, self::DEFAULT_CMD);
193 }
194 }
195
196 public function executeCommand(): void
197 {
198 $this->ensureReadAccess();
199
200 try {
201 $factory = new ilSamlAuthFactory();
202 $this->saml_auth = $factory->auth();
203 } catch (Throwable $e) {
204 if ($e->getMessage() === 'Database error: could not find driver') {
205 $this->tpl->setOnScreenMessage(
206 self::MESSAGE_TYPE_FAILURE,
207 $this->lng->txt('auth_saml_err_sqlite_driver')
208 );
209 } else {
210 $this->tpl->setOnScreenMessage(self::MESSAGE_TYPE_FAILURE, $e->getMessage());
211 }
212 }
213
214 $this->help->setScreenIdComponent('auth');
215
216 $cmd = $this->ctrl->getCmd();
217 if ($cmd === null || $cmd === '' || !method_exists($this, $cmd . 'Command')) {
218 $cmd = self::DEFAULT_CMD;
219 }
220 $verified_command = $cmd . 'Command';
221
222 $idp_id = $this->getIdpIdOrZero();
223
224 if ($idp_id > 0) {
225 $this->ctrl->setParameter($this, self::REQUEST_PARAM_SAML_IDP_ID, $idp_id);
226 }
227
228 if (!in_array(strtolower($cmd), array_map('strtolower', self::GLOBAL_COMMANDS), true)) {
229 if ($idp_id === 0) {
230 $this->ctrl->redirect($this, self::DEFAULT_CMD);
231 }
232
233 $this->initIdp();
235 }
236
237 if ($this->shouldRenderGlobalCommandSubTabs($cmd)) {
238 $this->setSubTabs(self::VIEW_MODE_GLOBAL);
239 } else {
240 $this->setSubTabs(self::VIEW_MODE_SINGLE);
241 }
242
243 $this->$verified_command();
244 }
245
246 private function shouldRenderGlobalCommandSubTabs(string $cmd): bool
247 {
248 $is_global_command = in_array(strtolower($cmd), array_map('strtolower', self::GLOBAL_COMMANDS), true);
249 $is_global_entity_command = in_array(
250 strtolower($cmd),
251 array_map('strtolower', self::GLOBAL_ENTITY_COMMANDS),
252 true
253 );
254
255 $is_global_table_action = in_array(
256 strtolower($this->getTableAction() ?? ''),
257 array_map('strtolower', self::GLOBAL_ENTITY_TABLE_ACTIONS),
258 true
259 );
260
261 return $is_global_command || $is_global_entity_command || $is_global_table_action;
262 }
263
264 private function listIdpsCommand(): void
265 {
266 if ($this->saml_auth && $this->rbac->system()->checkAccess(self::PERMISSION_WRITE, $this->ref_id)) {
267 $this->toolbar->addStickyItem(
268 $this->ui_factory->button()->standard(
269 $this->lng->txt('auth_saml_add_idp_btn'),
270 $this->ctrl->getLinkTarget($this, self::CMD_SHOW_NEW_IDP_FORM)
271 )
272 );
273 }
274
275 $federation_md_url = rtrim(
276 ILIAS_HTTP_PATH,
277 '/'
278 ) . '/metadata.php?client_id=' . CLIENT_ID;
279 $info = $this->ui_factory->messageBox()->info(
280 sprintf(
281 $this->lng->txt('auth_saml_idps_info'),
282 'auth/saml/config/config.php',
283 'auth/saml/config/authsources.php',
284 $this->ui_renderer->render(
285 $this->ui_factory->link()->standard(
286 'https://simplesamlphp.org/docs/stable/simplesamlphp-sp',
287 'https://simplesamlphp.org/docs/stable/simplesamlphp-sp'
288 )
289 ),
290 $this->ui_renderer->render($this->ui_factory->link()->standard($federation_md_url, $federation_md_url))
291 )
292 );
293
294 $table = new ilSamlIdpTableGUI(
295 $this,
296 $this->ui_factory,
297 $this->ui_renderer,
298 $this->lng,
299 $this->ctrl,
300 $this->http_state->request(),
301 new Factory(),
302 self::CMD_TABLE_ACTIONS,
303 $this->rbac->system()->checkAccess(self::PERMISSION_WRITE, $this->ref_id)
304 );
305 $this->tpl->setContent($this->ui_renderer->render([$info, $table->get()]));
306 }
307
308 private function getTableAction(): ?string
309 {
310 return $this->http_state->wrapper()->query()->retrieve(
311 'saml_idps_table_action',
312 $this->refinery->byTrying([
313 $this->refinery->kindlyTo()->string(),
314 $this->refinery->always(null)
315 ])
316 );
317 }
318
319 private function handleTableActionsCommand(): void
320 {
321 match ($this->getTableAction()) {
322 self::TABLE_ACTION_SHOW_IDP_SETTINGS => $this->ctrl->redirect($this, self::CMD_SHOW_IDP_SETTINGS),
323 self::TABLE_ACTION_ACTIVATE_IDP => $this->activateIdp(),
324 self::TABLE_ACTION_DEACTIVATE_IDP => $this->deactivateIdp(),
325 self::TABLE_ACTION_CONFIRM_DELETE_IDP => $this->confirmDeleteIdp(),
326 default => $this->ctrl->redirect($this, self::DEFAULT_CMD),
327 };
328 }
329
330 private function deactivateIdp(): void
331 {
332 $this->ensureWriteAccess();
333
334 $this->idp->setActive(false);
335 $this->idp->persist();
336
337 $this->tpl->setOnScreenMessage(self::MESSAGE_TYPE_SUCCESS, $this->lng->txt(self::LNG_SAVED_SUCCESSFULLY), true);
338 $this->ctrl->redirect($this, self::DEFAULT_CMD);
339 }
340
341 private function activateIdp(): void
342 {
343 $this->ensureWriteAccess();
344
345 $this->idp->setActive(true);
346 $this->idp->persist();
347
348 $this->tpl->setOnScreenMessage(self::MESSAGE_TYPE_SUCCESS, $this->lng->txt(self::LNG_SAVED_SUCCESSFULLY), true);
349 $this->ctrl->redirect($this, self::DEFAULT_CMD);
350 }
351
352 private function setSubTabs(int $a_view_mode): void
353 {
354 switch ($a_view_mode) {
356 $this->tabs->addSubTabTarget(
357 'auth_saml_idps',
358 $this->ctrl->getLinkTarget($this, self::DEFAULT_CMD),
359 array_merge(
360 self::GLOBAL_ENTITY_COMMANDS,
361 [self::DEFAULT_CMD, self::CMD_SHOW_NEW_IDP_FORM, self::CMD_SAVE_NEW_IDP]
362 ),
363 self::class,
364 '',
365 ($this->getTableAction() === self::TABLE_ACTION_CONFIRM_DELETE_IDP)
366 );
367
368 $this->tabs->addSubTabTarget(
369 'settings',
370 $this->ctrl->getLinkTarget($this, self::CMD_SHOW_SETTINGS),
371 [self::CMD_SHOW_SETTINGS, self::CMD_SAVE_SETTINGS],
372 self::class
373 );
374 break;
375
377 $this->tabs->clearTargets();
378 $this->tabs->setBackTarget(
379 $this->lng->txt('back'),
380 $this->ctrl->getLinkTarget($this, self::DEFAULT_CMD)
381 );
382
383 $this->tabs->addSubTabTarget(
384 'auth_saml_idp_settings',
385 $this->ctrl->getLinkTarget($this, self::CMD_SHOW_IDP_SETTINGS),
386 [self::CMD_SHOW_IDP_SETTINGS, self::CMD_SAVE_IDP_SETTINGS],
387 self::class
388 );
389
390 $this->tabs->addSubTabTarget(
391 self::LNG_AUTH_SAML_USER_MAPPING,
392 $this->ctrl->getLinkTarget($this, self::CMD_SHOW_USER_ATTRIBUTE_MAPPING_FORM),
393 [self::CMD_SHOW_USER_ATTRIBUTE_MAPPING_FORM, self::CMD_SAVE_USER_ATTRIBUTE_MAPPING],
394 self::class
395 );
396 break;
397 }
398 }
399
400 private function initUserAttributeMapping(): void
401 {
402 $this->mapping = new ilExternalAuthUserAttributeMapping('saml', $this->idp->getIdpId());
403 }
404
406 {
407 $form = new ilPropertyFormGUI();
408 $form->setFormAction($this->ctrl->getFormAction($this, self::CMD_SAVE_USER_ATTRIBUTE_MAPPING));
409 $form->setTitle($this->lng->txt(self::LNG_AUTH_SAML_USER_MAPPING));
410
411 foreach ($this->profile->getFields() as $field) {
412 if (in_array($field->getIdentifier(), self::IGNORED_USER_FIELDS, true)) {
413 continue;
414 }
415
416 $id = $field->getIdentifier();
417 if ($field->isCustom()) {
418 $id = "udf_{$id}";
419 }
420
421 $this->addAttributeRuleFieldToForm($form, $field->getLabel($this->lng), $id);
422 }
423
424 if ($this->rbac->system()->checkAccess(self::PERMISSION_WRITE, $this->ref_id)) {
425 $form->addCommandButton(self::CMD_SAVE_USER_ATTRIBUTE_MAPPING, $this->lng->txt(self::LNG_SAVE));
426 } else {
427 foreach ($form->getItems() as $item) {
428 $item->setDisabled(true);
429 }
430 }
431
432 return $form;
433 }
434
436 ilPropertyFormGUI $form,
437 string $field_label,
438 string $field_name
439 ): void {
440 $field = new ilTextInputGUI($field_label, $field_name);
441 $form->addItem($field);
442
443 $update_automatically = new ilCheckboxInputGUI('', $field_name . self::PROP_UPDATE_SUFFIX);
444 $update_automatically->setOptionTitle($this->lng->txt('auth_saml_update_field_info'));
445 $update_automatically->setValue('1');
446 $form->addItem($update_automatically);
447 }
448
449 private function saveUserAttributeMappingCommand(): void
450 {
451 $this->ensureWriteAccess();
452
453 $form = $this->getUserAttributeMappingForm();
454 if ($form->checkInput()) {
455 $this->mapping->delete();
456
457 foreach ($this->profile->getFields() as $field) {
458 if (in_array($field->getIdentifier(), self::IGNORED_USER_FIELDS, true)) {
459 continue;
460 }
461
462 $id = $field->getIdentifier();
463 if ($field->isCustom()) {
464 $id = "udf_{$id}";
465 }
466
467 $rule = $this->mapping->getEmptyRule();
468 $rule->setAttribute($id);
469 $rule->setExternalAttribute((string) $form->getInput($rule->getAttribute()));
470 $rule->updateAutomatically((bool) $form->getInput($rule->getAttribute() . self::PROP_UPDATE_SUFFIX));
471 $this->mapping[$rule->getAttribute()] = $rule;
472 }
473
474 $this->mapping->save();
475
476 $this->tpl->setOnScreenMessage(self::MESSAGE_TYPE_SUCCESS, $this->lng->txt(self::LNG_SAVED_SUCCESSFULLY));
477 }
478
479 $form->setValuesByPost();
480
481 $this->showUserAttributeMappingFormCommand($form);
482 }
483
484 private function showUserAttributeMappingFormCommand(?ilPropertyFormGUI $form = null): void
485 {
486 $this->tabs->setSubTabActive(self::LNG_AUTH_SAML_USER_MAPPING);
487
488 if (!($form instanceof ilPropertyFormGUI)) {
489 $form = $this->getUserAttributeMappingForm();
490 $data = [];
491 foreach ($this->mapping as $rule) {
492 $data[$rule->getAttribute()] = $rule->getExternalAttribute();
493 $data[$rule->getAttribute() . self::PROP_UPDATE_SUFFIX] = $rule->isAutomaticallyUpdated();
494 }
495 $form->setValuesByArray($data);
496 }
497
498 $this->tpl->setContent($form->getHTML());
499 }
500
504 private function getSettingsForm(array $values = []): StandardForm
505 {
506 $access = $this->rbac->system()->checkAccess(self::PERMISSION_WRITE, $this->ref_id);
507 $form = $this->ui_factory->input()->container()->form()->standard(
508 $this->ctrl->getFormAction($this, $access ? self::CMD_SAVE_SETTINGS : self::CMD_SHOW_SETTINGS),
509 [
510 self::LNG_LOGIN_FORM => $this->ui_factory
511 ->input()
512 ->field()
513 ->checkbox(
514 $this->lng->txt('auth_saml_login_form'),
515 $this->lng->txt('auth_saml_login_form_info')
516 )
517 ->withValue((bool) ($values[self::LNG_LOGIN_FORM] ?? true))
518 ->withDisabled(!$access),
519 ]
520 );
521
522 if (!$access) {
523 $form = $form->withSubmitLabel($this->lng->txt('refresh'));
524 }
525
526 return $form;
527 }
528
532 private function prepareRoleSelection(): array
533 {
534 $select = [];
535 $global_roles = array_map(
536 intval(...),
538 $this->rbac->review()->getGlobalRoles(),
539 'object_data',
540 'title',
541 'obj_id'
542 )
543 );
544
545 $select[0] = $this->lng->txt('links_select_one');
546 foreach ($global_roles as $role_id) {
547 $select[$role_id] = ilObject::_lookupTitle($role_id);
548 }
549
550 return $select;
551 }
552
553 private function saveSettingsCommand(): void
554 {
555 $this->ensureWriteAccess();
556
557 $form = $this->getSettingsForm()->withRequest($this->http_state->request());
558 if (!$form->getError()) {
559 $data = $form->getData();
560 ilSamlSettings::getInstance()->setLoginFormStatus($data[self::LNG_LOGIN_FORM]);
561 $this->tpl->setOnScreenMessage(self::MESSAGE_TYPE_SUCCESS, $this->lng->txt(self::LNG_SAVED_SUCCESSFULLY));
562 }
563
564 $this->showSettingsCommand($form);
565 }
566
567 private function showSettingsCommand(?StandardForm $form = null): void
568 {
569 if (!$form) {
570 $form = $this->getSettingsForm([
571 self::LNG_LOGIN_FORM => ilSamlSettings::getInstance()->isDisplayedOnLoginPage()
572 ]);
573 }
574
575 $title = $this->ui_factory->item()->standard($this->lng->txt('auth_saml_configure'));
576 $this->tpl->setContent($this->ui_renderer->render([
577 $title,
578 $form
579 ]));
580 }
581
583 ?string &$medadata_entity_id = null
584 ): \ILIAS\Refinery\Constraint {
585 $xml_parser_error = null;
586
587 return $this->refinery->custom()->constraint(
588 function (string $value) use (&$xml_parser_error, &$medadata_entity_id): bool {
589 try {
590 $parser = new ilSamlIdpXmlMetadataParser(
591 new Factory(),
593 );
594
595 $result = $parser->parse($value);
596 if ($result->isError()) {
597 $xml_parser_error = $result->error();
598 return false;
599 }
600
601 $medadata_entity_id = $result->value();
602
603 return true;
604 } catch (Throwable) {
605 $xml_parser_error = $this->lng->txt('auth_saml_add_idp_md_error');
606 return false;
607 }
608 },
609 implode(' ', [$this->lng->txt('auth_saml_add_idp_md_error'), $xml_parser_error])
610 );
611 }
612
613 private function getIdpSettingsForm(array $values = []): StandardForm
614 {
615 $ui_field = $this->ui_factory->input()->field();
616 $metadata_entity_id = $values[self::METADATA_ENTITY_ID] ?? null;
617
619 $inputs = [
620 $ui_field->text(
621 $this->lng->txt('auth_saml_idp')
622 )->withValue($values[self::METADATA_ENTITY_ID] ?? '')->withDisabled(true),
623 self::METADATA_STORAGE_KEY => $ui_field
624 ->textarea(
625 $this->lng->txt('auth_saml_add_idp_md_label'),
626 $this->lng->txt('auth_saml_add_idp_md_info')
627 )
628 ->withValue($values[self::METADATA_STORAGE_KEY] ?? '')
629 ->withRequired(true)
630 ->withoutStripTags()
631 ->withDedicatedName(self::METADATA_STORAGE_KEY)
632 ->withAdditionalTransformation($this->metadataValidationConstraint($metadata_entity_id)),
633 'allow_local_auth' => $ui_field->checkbox(
634 $this->lng->txt('auth_allow_local'),
635 $this->lng->txt('auth_allow_local_info')
636 )->withValue((bool) ($values['allow_local_auth'] ?? true)),
637 'uid_claim' => $ui_field->text(
638 $this->lng->txt('auth_saml_uid_claim'),
639 $this->lng->txt('auth_saml_uid_claim_info')
640 )->withValue($values['uid_claim'] ?? '')->withRequired(true),
641 'sync_status' => $ui_field->optionalGroup(
642 [
643 'login_claim' => $ui_field->text(
644 $this->lng->txt('auth_saml_username_claim'),
645 $this->lng->txt('auth_saml_username_claim_info')
646 )->withRequired(true),
647 'default_role_id' => $ui_field->select(
648 $this->lng->txt('auth_saml_role_select'),
649 $this->prepareRoleSelection()
650 )->withRequired(true),
651 'account_migr_status' => $ui_field->checkbox(
652 $this->lng->txt('auth_saml_migration'),
653 $this->lng->txt('auth_saml_migration_info')
654 )
655 ],
656 $this->lng->txt('auth_saml_sync'),
657 $this->lng->txt('auth_saml_sync_info')
658 )->withValue(
659 (isset($values['sync_status']) && $values['sync_status'])
660 ? [
661 'login_claim' => $values['login_claim'] ?? '',
662 'default_role_id' => $values['default_role_id'] ?? array_key_first($this->prepareRoleSelection()),
663 'account_migr_status' => (bool) ($values['account_migr_status'] ?? true)
664 ]
665 : null
666 )
667 ];
668
669 $write_access = $this->rbac->system()->checkAccess(self::PERMISSION_WRITE, $this->ref_id);
670 $inputs = array_map(static function (FormInput $input) use ($write_access) {
671 if (!$write_access) {
672 $input = $input->withDisabled(true);
673 }
674
675 return $input;
676 }, $inputs);
677
678 $this->ctrl->setParameter($this, self::REQUEST_PARAM_SAML_IDP_ID, $this->idp->getIdpId());
679
680 return $this->ui_factory->input()->container()->form()->standard(
681 $this->ctrl->getFormAction($this, self::CMD_SAVE_IDP_SETTINGS),
682 $inputs
683 );
684 }
685
686 private function showIdpSettingsCommand(?StandardForm $form = null): void
687 {
688 $this->tabs->setSubTabActive('auth_saml_idp_settings');
689
690 if (!$form) {
691 $data = $this->idp->toArray();
692 $this->populateWithMetadata($this->idp, $data);
693 $form = $this->getIdpSettingsForm($data);
694 }
695
696 $this->help->setSubScreenId('edit_idp');
697
698 $title = $this->ui_factory->item()->standard(
699 sprintf($this->lng->txt('auth_saml_configure_idp'), $this->idp->getEntityId())
700 );
701
702 $this->tpl->setContent($this->ui_renderer->render([
703 $title,
704 $form
705 ]));
706 }
707
708 private function saveIdpSettingsCommand(): void
709 {
710 $this->ensureWriteAccess();
711
712 $form = $this->getIdpSettingsForm()->withRequest($this->http_state->request());
713
714 if (!$form->getError()) {
715 $this->idp->bindForm($form);
716 $this->idp->persist();
717
718 $this->storeMetadata($this->idp, $form->getData()[self::METADATA_STORAGE_KEY] ?? '');
719 $this->tpl->setOnScreenMessage(
720 self::MESSAGE_TYPE_SUCCESS,
721 $this->lng->txt(self::LNG_SAVED_SUCCESSFULLY),
722 true
723 );
724 }
725
726 $this->ctrl->redirect($this, self::CMD_SHOW_IDP_SETTINGS);
727 }
728
729 private function getIdpForm(): StandardForm
730 {
731 $medadata_entity_id = '';
732
733 return $this->ui_factory->input()->container()->form()->standard(
734 $this->ctrl->getFormAction($this, self::CMD_SAVE_NEW_IDP),
735 [
736 self::METADATA_STORAGE_KEY => $this->ui_factory
737 ->input()
738 ->field()
739 ->textarea(
740 $this->lng->txt('auth_saml_add_idp_md_label'),
741 $this->lng->txt('auth_saml_add_idp_md_info')
742 )
743 ->withValue($values[self::METADATA_STORAGE_KEY] ?? '')
744 ->withRequired(true)
745 ->withoutStripTags()
746 ->withDedicatedName(self::METADATA_STORAGE_KEY)
747 ->withAdditionalTransformation($this->metadataValidationConstraint($medadata_entity_id)),
748 self::METADATA_ENTITY_ID => $this->ui_factory
749 ->input()
750 ->field()
751 ->hidden()
752 ->withAdditionalTransformation(
753 $this->refinery->custom()->transformation(
754 static function (string $value) use (&$medadata_entity_id): string {
755 $sanitized_value = ilUtil::stripSlashes(trim($medadata_entity_id));
756 if ($sanitized_value !== $medadata_entity_id) {
757 $sanitized_value = ilUtil::stripSlashes(str_replace('<', '< ', $medadata_entity_id));
758 }
759
760 return trim($sanitized_value);
761 }
762 )
763 )
764 ]
765 );
766 }
767
768 private function saveNewIdpCommand(): void
769 {
770 $this->ensureWriteAccess();
771
772 $form = $this->getIdpForm()->withRequest($this->http_state->request());
773 if (!$form->getError()) {
774 $idp = new ilSamlIdp();
775 $idp->bindForm($form);
776 $idp->persist();
777 $this->storeMetadata($idp, $form->getData()[self::METADATA_STORAGE_KEY] ?? '');
778
779 $this->tpl->setOnScreenMessage(
780 self::MESSAGE_TYPE_SUCCESS,
781 $this->lng->txt(self::LNG_SAVED_SUCCESSFULLY),
782 true
783 );
784 $this->ctrl->setParameter($this, self::REQUEST_PARAM_SAML_IDP_ID, $idp->getIdpId());
785 $this->ctrl->redirect($this, self::TABLE_ACTION_SHOW_IDP_SETTINGS);
786 }
787
788 $this->showNewIdpFormCommand($form);
789 }
790
791 private function showNewIdpFormCommand(?StandardForm $form = null): void
792 {
793 $this->ensureWriteAccess();
794
795 if ($form === null) {
796 $form = $this->getIdpForm();
797 } else {
798 $form = $form->withRequest($this->http_state->request());
799 }
800
801 $this->help->setSubScreenId('create_idp');
802
803 $title = $this->ui_factory->item()->standard($this->lng->txt('auth_saml_add_idp_btn'));
804 $this->tpl->setContent($this->ui_renderer->render([
805 $title,
806 $form
807 ]));
808 }
809
810 private function populateWithMetadata(ilSamlIdp $idp, array &$data): void
811 {
812 $idp_disco = $this->saml_auth->getIdpDiscovery();
813
814 $data[self::METADATA_STORAGE_KEY] = $idp_disco->fetchIdpMetadata($idp->getIdpId());
815 }
816
817 private function storeMetadata(ilSamlIdp $idp, string $metadata): void
818 {
819 $idp_disco = $this->saml_auth->getIdpDiscovery();
820 $idp_disco->storeIdpMetadata($idp->getIdpId(), $metadata);
821 }
822
823 private function confirmDeleteIdp(): void
824 {
825 $this->ensureWriteAccess();
826
827 $confirmation = new ilConfirmationGUI();
828 $confirmation->setFormAction($this->ctrl->getFormAction($this, self::CMD_DELETE_IDP));
829 $confirmation->setConfirm($this->lng->txt('confirm'), self::CMD_DELETE_IDP);
830 $confirmation->setCancel($this->lng->txt(self::LNG_CANCEL), self::DEFAULT_CMD);
831 $confirmation->setHeaderText($this->lng->txt('auth_saml_sure_delete_idp'));
832 $confirmation->addItem(
833 self::REQUEST_PARAM_SAML_IDP_IDS,
834 (string) $this->idp->getIdpId(),
835 $this->idp->getEntityId()
836 );
837
838 $this->tpl->setContent($confirmation->getHTML());
839 }
840
841 private function deleteIdpCommand(): void
842 {
843 $this->ensureWriteAccess();
844
845 $idp_disco = $this->saml_auth->getIdpDiscovery();
846 $idp_disco->deleteIdpMetadata($this->idp->getIdpId());
847
848 $this->idp->delete();
849
850 $this->tpl->setOnScreenMessage(self::MESSAGE_TYPE_SUCCESS, $this->lng->txt('auth_saml_deleted_idp'), true);
851
852 $this->ctrl->setParameter($this, self::REQUEST_PARAM_SAML_IDP_ID, null);
853 $this->ctrl->redirect($this, self::DEFAULT_CMD);
854 }
855}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
Provides fluid interface to RBAC services.
Builds data types.
Definition: Factory.php:36
This class represents a checkbox property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Error Handling & global info handling.
Help GUI class.
language handling
static _lookupTitle(int $obj_id)
This class represents a property form user interface.
setValuesByArray(array $a_values, bool $a_restrict_to_value_keys=false)
getInput(string $a_post_var, bool $ensureValidation=true)
Returns the input of an item, if item provides getInput method and as fallback the value of the HTTP-...
bindForm(StandardForm $form)
static getInstanceByIdpId(int $a_idp_id)
shouldRenderGlobalCommandSubTabs(string $cmd)
readonly ilHelpGUI $help
addAttributeRuleFieldToForm(ilPropertyFormGUI $form, string $field_label, string $field_name)
populateWithMetadata(ilSamlIdp $idp, array &$data)
setSubTabs(int $a_view_mode)
const string LNG_AUTH_SAML_USER_MAPPING
getUnsafeGetCommands()
This method must return a list of unsafe GET commands.
showIdpSettingsCommand(?StandardForm $form=null)
getSettingsForm(array $values=[])
readonly ilToolbarGUI $toolbar
readonly ilCtrlInterface $ctrl
readonly ILIAS UI Factory $ui_factory
getSafePostCommands()
This method must return a list of safe POST commands.
showNewIdpFormCommand(?StandardForm $form=null)
readonly RBACServices $rbac
readonly ilLanguage $lng
readonly ILIAS UI Renderer $ui_renderer
const string LNG_SAVED_SUCCESSFULLY
storeMetadata(ilSamlIdp $idp, string $metadata)
readonly Refinery $refinery
ensureAccess(string $operation)
readonly ilErrorHandling $error_handler
showSettingsCommand(?StandardForm $form=null)
readonly GlobalHttpState $http_state
readonly ilTabsGUI $tabs
showUserAttributeMappingFormCommand(?ilPropertyFormGUI $form=null)
metadataValidationConstraint(?string &$medadata_entity_id=null)
__construct(private readonly int $ref_id)
const string REQUEST_PARAM_SAML_IDP_ID
ilExternalAuthUserAttributeMapping $mapping
const string REQUEST_PARAM_SAML_IDP_IDS
readonly ilGlobalTemplateInterface $tpl
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 stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
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 CLIENT_ID
Definition: constants.php:41
$info
Definition: entry_point.php:21
Interface GlobalHttpState.
This describes inputs that can be used in forms.
Definition: FormInput.php:33
withDisabled(bool $is_disabled)
Get an input like this, but set it to a disabled state.
This describes a standard form.
Definition: Standard.php:29
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const string CMD_TABLE_ACTIONS
$ref_id
Definition: ltiauth.php:66
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.
global $DIC
Definition: shib_login.php:26