ILIAS  release_8 Revision v8.19
All Data Structures Namespaces Files Functions Variables Modules Pages
class.ilOpenIdConnectSettingsGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
28 {
29  private const STAB_SETTINGS = 'settings';
30  private const STAB_PROFILE = 'profile';
31  private const STAB_ROLES = 'roles';
32 
33  private const DEFAULT_CMD = 'settings';
34  private int $ref_id;
36  private $body;
38  private ilLanguage $lng;
39  private ilCtrl $ctrl;
40  private ilLogger $logger;
45  private ilTabsGUI $tabs;
47 
48  public function __construct(int $a_ref_id)
49  {
50  global $DIC;
51 
52  $this->ref_id = $a_ref_id;
53 
54  $this->lng = $DIC->language();
55  $this->lng->loadLanguageModule('auth');
56 
57  $this->mainTemplate = $DIC->ui()->mainTemplate();
58  $this->tabs = $DIC->tabs();
59  $this->ctrl = $DIC->ctrl();
60  $this->logger = $DIC->logger()->auth();
61 
62  $this->access = $DIC->access();
63  $this->review = $DIC->rbac()->review();
64  $this->error = $DIC['ilErr'];
65  $this->upload = $DIC->upload();
66  $this->body = $DIC->http()->request()->getParsedBody();
68  }
69 
70  protected function checkAccess(string $a_permission): void
71  {
72  if (!$this->checkAccessBool($a_permission)) {
73  $this->error->raiseError($this->lng->txt('msg_no_perm_read'), $this->error->WARNING);
74  }
75  }
76 
77  protected function checkAccessBool(string $a_permission): bool
78  {
79  return $this->access->checkAccess($a_permission, '', $this->ref_id);
80  }
81 
82  public function executeCommand(): void
83  {
84  $this->checkAccess('read');
85 
86  switch ($this->ctrl->getNextClass()) {
87  default:
88  $cmd = $this->ctrl->getCmd(self::DEFAULT_CMD);
89  $this->$cmd();
90  break;
91  }
92  }
93 
94  protected function settings(ilPropertyFormGUI $form = null): void
95  {
96  $this->checkAccess('read');
97  $this->setSubTabs(self::STAB_SETTINGS);
98 
99 
100  if (!$form instanceof ilPropertyFormGUI) {
101  $form = $this->initSettingsForm();
102  }
103 
104  $this->mainTemplate->setContent($form->getHTML());
105  }
106 
107  protected function initSettingsForm(): ilPropertyFormGUI
108  {
109  $form = new ilPropertyFormGUI();
110  $form->setTitle($this->lng->txt('auth_oidc_settings_title'));
111  $form->setFormAction($this->ctrl->getFormAction($this));
112 
113  // activation
114  $activation = new ilCheckboxInputGUI(
115  $this->lng->txt('auth_oidc_settings_activation'),
116  'activation'
117  );
118  $activation->setChecked($this->settings->getActive());
119  $form->addItem($activation);
120 
121  // provider
123  $this->lng->txt('auth_oidc_settings_provider'),
124  'provider'
125  );
126  $provider->setRequired(true);
127  $provider->setValue($this->settings->getProvider());
128  $form->addItem($provider);
129 
131  $this->lng->txt('auth_oidc_settings_client_id'),
132  'client_id'
133  );
134  $client_id->setRequired(true);
135  $client_id->setValue($this->settings->getClientId());
136  $form->addItem($client_id);
137 
138  // secret
140  $this->lng->txt('auth_oidc_settings_secret'),
141  'secret'
142  );
143  $secret->setSkipSyntaxCheck(true);
144  $secret->setRetype(false);
145  $secret->setRequired(false);
146  if ($this->settings->getSecret() !== '') {
147  $secret->setValue('******');
148  }
149  $form->addItem($secret);
150 
151  $default_scope = new ilTextInputGUI(
152  $this->lng->txt('auth_oidc_settings_additional_scopes'),
153  "default_scope"
154  );
155  $default_scope->setValue(ilOpenIdConnectSettings::DEFAULT_SCOPE);
156  $default_scope->setDisabled(true);
157  $form->addItem($default_scope);
158 
159  $scopes = new ilTextInputGUI(
160  "",
161  "scopes"
162  );
163  $scopes->setMulti(true);
164  $scopeValues = $this->settings->getAdditionalScopes();
165  if (isset($scopeValues[0])) {
166  $scopes->setValue($scopeValues[0]);
167  }
168  $scopes->setMultiValues($scopeValues);
169  $form->addItem($scopes);
170 
171 
172  // validation options
173  $validation_options = new ilRadioGroupInputGUI(
174  $this->lng->txt('auth_oidc_settings_validate_scopes'),
175  'validate_scopes'
176  );
177  $validation_options->setValue((string) $this->settings->getValidateScopes());
178  $form->addItem($validation_options);
179 
180  $base_valid_url_option = new ilRadioOption(
181  $this->lng->txt('auth_oidc_settings_validate_scope_default'),
183  );
184 
185  $validation_options->addOption($base_valid_url_option);
186 
187  $custom_validation_url = new ilTextInputGUI(
188  '',
189  'custom_discovery_url'
190  );
191 
192  $custom_valid_url_option = new ilRadioOption(
193  $this->lng->txt('auth_oidc_settings_validate_scope_custom'),
195  );
196  $validation_options->addOption($custom_valid_url_option);
197  $custom_validation_url->setValue($this->settings->getCustomDiscoveryUrl() ?? '');
198  $custom_validation_url->setMaxLength(120);
199  $custom_validation_url->setInfo($this->lng->txt('auth_oidc_settings_discovery_url'));
200  $custom_valid_url_option->addSubItem($custom_validation_url);
201  $no_validation_option = new ilRadioOption(
202  $this->lng->txt('auth_oidc_settings_validate_scope_none'),
204  );
205  $validation_options->addOption($no_validation_option);
206 
207  // login element
208  $login_element = new ilRadioGroupInputGUI(
209  $this->lng->txt('auth_oidc_settings_le'),
210  'le'
211  );
212  $login_element->setRequired(true);
213  $login_element->setValue((string) $this->settings->getLoginElementType());
214  $form->addItem($login_element);
215 
216  // le -> type text
217  $text_option = new ilRadioOption(
218  $this->lng->txt('auth_oidc_settings_txt'),
220  );
221  $login_element->addOption($text_option);
222 
223  // le -> type text -> text
224  $text = new ilTextInputGUI(
225  '',
226  'le_text'
227  );
228  $text->setValue($this->settings->getLoginElemenText());
229  $text->setMaxLength(120);
230  $text->setInfo($this->lng->txt('auth_oidc_settings_txt_val_info'));
231  $text_option->addSubItem($text);
232 
233  // le -> type img
234  $img_option = new ilRadioOption(
235  $this->lng->txt('auth_oidc_settings_img'),
237  );
238  $login_element->addOption($img_option);
239 
240  $image = new ilImageFileInputGUI(
241  '',
242  'le_img'
243  );
244  $image->setAllowDeletion(false);
245 
246  if ($this->settings->hasImageFile()) {
247  $image->setImage($this->settings->getImageFilePath());
248  }
249  $image->setInfo($this->lng->txt('auth_oidc_settings_img_file_info'));
250  $img_option->addSubItem($image);
251 
252  // login options
253  $login_options = new ilRadioGroupInputGUI(
254  $this->lng->txt('auth_oidc_settings_login_options'),
255  'login_prompt'
256  );
257  $login_options->setValue((string) $this->settings->getLoginPromptType());
258 
259  // enforce login
260  $enforce = new ilRadioOption(
261  $this->lng->txt('auth_oidc_settings_login_option_enforce'),
263  );
264  $enforce->setInfo($this->lng->txt('auth_oidc_settings_login_option_enforce_info'));
265  $login_options->addOption($enforce);
266 
267  // default login
268  $default = new ilRadioOption(
269  $this->lng->txt('auth_oidc_settings_login_option_default'),
271  );
272  $default->setInfo($this->lng->txt('auth_oidc_settings_login_option_default_info'));
273  $login_options->addOption($default);
274 
275  $form->addItem($login_options);
276 
277  // logout scope
278  $logout_scope = new ilRadioGroupInputGUI(
279  $this->lng->txt('auth_oidc_settings_logout_scope'),
280  'logout_scope'
281  );
282  $logout_scope->setValue((string) $this->settings->getLogoutScope());
283 
284  // scope global
285  $global_scope = new ilRadioOption(
286  $this->lng->txt('auth_oidc_settings_logout_scope_global'),
288  );
289  $global_scope->setInfo($this->lng->txt('auth_oidc_settings_logout_scope_global_info'));
290  $logout_scope->addOption($global_scope);
291 
292  // ilias scope
293  $ilias_scope = new ilRadioOption(
294  $this->lng->txt('auth_oidc_settings_logout_scope_local'),
296  );
297  $ilias_scope->setInfo($this->lng->txt('auth_oidc_settings_logout_scope_local_info'));
298  $logout_scope->addOption($ilias_scope);
299 
300  $form->addItem($logout_scope);
301 
302  $use_custom_session = new ilCheckboxInputGUI(
303  $this->lng->txt('auth_oidc_settings_custom_session_duration_type'),
304  'custom_session'
305  );
306  $use_custom_session->setOptionTitle(
307  $this->lng->txt('auth_oidc_settings_custom_session_duration_option')
308  );
309  $use_custom_session->setChecked($this->settings->isCustomSession());
310  $form->addItem($use_custom_session);
311 
312  // session duration
314  $this->lng->txt('auth_oidc_settings_session_duration'),
315  'session_duration'
316  );
317  $session->setValue((string) $this->settings->getSessionDuration());
318  $session->setSuffix($this->lng->txt('minutes'));
319  $session->setMinValue(5);
320  $session->setMaxValue(1440);
321  $session->setRequired(true);
322  $use_custom_session->addSubItem($session);
323 
324  if ($this->checkAccessBool('write')) {
325  // save button
326  $form->addCommandButton('saveSettings', $this->lng->txt('save'));
327  }
328 
329  // User sync settings --------------------------------------------------------------
330  $user_sync = new ilFormSectionHeaderGUI();
331  $user_sync->setTitle($this->lng->txt('auth_oidc_settings_section_user_sync'));
332  $form->addItem($user_sync);
333 
334  $sync = new ilCheckboxInputGUI(
335  $this->lng->txt('auth_oidc_settings_user_sync'),
336  'sync'
337  );
338  $sync->setChecked($this->settings->isSyncAllowed());
339  $sync->setInfo($this->lng->txt('auth_oidc_settings_user_sync_info'));
340  $sync->setValue("1");
341  $form->addItem($sync);
342 
343  $roles = new ilSelectInputGUI(
344  $this->lng->txt('auth_oidc_settings_default_role'),
345  'role'
346  );
347  $roles->setValue($this->settings->getRole());
348  $roles->setInfo($this->lng->txt('auth_oidc_settings_default_role_info'));
349  $roles->setOptions($this->prepareRoleSelection());
350  $roles->setRequired(true);
351  $sync->addSubItem($roles);
352 
353  $user_attr = new ilTextInputGUI(
354  $this->lng->txt('auth_oidc_settings_user_attr'),
355  'username'
356  );
357  $user_attr->setValue($this->settings->getUidField());
358  $user_attr->setRequired(true);
359  $form->addItem($user_attr);
360 
361  return $form;
362  }
363 
364  protected function saveSettings(): void
365  {
366  $this->checkAccess('write');
367 
368  $form = $this->initSettingsForm();
369  if (!$form->checkInput()) {
370  $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
371  $form->setValuesByPost();
372  $this->settings($form);
373  return;
374  }
375 
376  $scopes = [];
377  if (!empty($form->getInput('scopes'))) {
378  $scopes = $form->getInput('scopes');
379  foreach ($scopes as $key => $value) {
380  if (empty($value)) {
381  array_splice($scopes, $key, 1);
382  }
383  }
384  }
385 
386  try {
387  switch ((int) $form->getInput('validate_scopes')) {
389  $discoveryURL = $form->getInput('provider') . '/.well-known/openid-configuration';
390  break;
392  $discoveryURL = $form->getInput('custom_discovery_url');
393  break;
394  default:
395  $discoveryURL = null;
396  break;
397  }
398  $validation_result = !is_null($discoveryURL) ? $this->settings->validateScopes($discoveryURL, (array) $scopes) : [];
399 
400  if (!empty($validation_result)) {
401  if (ilOpenIdConnectSettings::VALIDATION_ISSUE_INVALID_SCOPE === $validation_result[0]) {
402  $this->mainTemplate->setOnScreenMessage(
403  'failure',
404  sprintf($this->lng->txt('auth_oidc_settings_invalid_scopes'), implode(",", $validation_result[1]))
405  );
406  } else {
407  $this->mainTemplate->setOnScreenMessage(
408  'failure',
409  sprintf($this->lng->txt('auth_oidc_settings_discovery_error'), $validation_result[1])
410  );
411  }
412  $form->setValuesByPost();
413  $this->settings($form);
414  return;
415  }
416  } catch (ilCurlConnectionException $e) {
417  $this->mainTemplate->setOnScreenMessage(
418  'failure',
419  $e->getMessage()
420  );
421  $form->setValuesByPost();
422  $this->settings($form);
423  return;
424  }
425 
426  $this->settings->setActive((bool) $form->getInput('activation'));
427  $this->settings->setProvider((string) $form->getInput('provider'));
428  $this->settings->setClientId((string) $form->getInput('client_id'));
429  if ((string) $form->getInput('secret') !== '' && strcmp($form->getInput('secret'), '******') !== 0) {
430  $this->settings->setSecret((string) $form->getInput('secret'));
431  }
432  $this->settings->setAdditionalScopes((array) $scopes);
433  $this->settings->setLoginElementType((int) $form->getInput('le'));
434  $this->settings->setLoginElementText((string) $form->getInput('le_text'));
435  $this->settings->setLoginPromptType((int) $form->getInput('login_prompt'));
436  $this->settings->setLogoutScope((int) $form->getInput('logout_scope'));
437  $this->settings->useCustomSession((bool) $form->getInput('custom_session'));
438  $this->settings->setSessionDuration((int) $form->getInput('session_duration'));
439  $this->settings->allowSync((bool) $form->getInput('sync'));
440  $this->settings->setRole((int) $form->getInput('role'));
441  $this->settings->setUidField((string) $form->getInput('username'));
442 
443  $fileData = (array) $form->getInput('le_img');
444 
445  if ((string) ($fileData['tmp_name'] ?? '') !== '') {
446  $this->saveImageFromHttpRequest();
447  }
448 
449  $this->settings->setValidateScopes((int) $form->getInput('validate_scopes'));
450  if (ilOpenIdConnectSettings::URL_VALIDATION_CUSTOM === $this->settings->getValidateScopes()) {
451  $this->settings->setCustomDiscoveryUrl($form->getInput('custom_discovery_url'));
452  }
453  $this->settings->save();
454 
455  $this->mainTemplate->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
456  $this->ctrl->redirect($this, 'settings');
457  }
458 
459  protected function saveImageFromHttpRequest(): void
460  {
461  try {
462  if (!$this->upload->hasBeenProcessed()) {
463  $this->upload->process();
464  }
465  foreach ($this->upload->getResults() as $single_file_upload) {
466  if ($single_file_upload->isOK()) {
467  $this->settings->deleteImageFile();
468  $this->upload->moveFilesTo(
470  \ILIAS\FileUpload\Location::WEB
471  );
472  $this->settings->setLoginElementImage($single_file_upload->getName());
473  }
474  }
475  } catch (\ILIAS\Filesystem\Exception\IllegalStateException $e) {
476  $this->logger->warning('Upload failed with message: ' . $e->getMessage());
477  }
478  }
479 
484  protected function prepareRoleSelection(bool $a_with_select_option = true): array
485  {
486  $global_roles = ilUtil::_sortIds(
487  $this->review->getGlobalRoles(),
488  'object_data',
489  'title',
490  'obj_id'
491  );
492 
493  $select = [];
494  if ($a_with_select_option) {
495  $select[0] = $this->lng->txt('links_select_one');
496  }
497  foreach ($global_roles as $role_id) {
498  if ($role_id === ANONYMOUS_ROLE_ID) {
499  continue;
500  }
501  $select[(string) $role_id] = ilObject::_lookupTitle((int) $role_id);
502  }
503 
504  return $select;
505  }
506 
507  protected function profile(ilPropertyFormGUI $form = null): void
508  {
509  $this->checkAccess('read');
510  $this->setSubTabs(self::STAB_PROFILE);
511 
512  if (!$form instanceof ilPropertyFormGUI) {
513  $form = $this->initProfileForm();
514  }
515  $this->mainTemplate->setContent($form->getHTML());
516  }
517 
518  protected function initProfileForm(): ilPropertyFormGUI
519  {
520  $form = new ilPropertyFormGUI();
521  $form->setTitle($this->lng->txt('auth_oidc_mapping_table'));
522  $form->setFormAction($this->ctrl->getFormAction($this, 'saveProfile'));
523 
524  foreach ($this->settings->getProfileMappingFields() as $field => $lng_key) {
525  $text_form = new ilTextInputGUI($this->lng->txt($lng_key));
526  $text_form->setPostVar($field . "_value");
527  $text_form->setValue($this->settings->getProfileMappingFieldValue($field));
528  $form->addItem($text_form);
529 
530  $checkbox_form = new ilCheckboxInputGUI('');
531  $checkbox_form->setValue("1");
532  $checkbox_form->setPostVar($field . "_update");
533  $checkbox_form->setChecked($this->settings->getProfileMappingFieldUpdate($field));
534  $checkbox_form->setOptionTitle($this->lng->txt('auth_oidc_update_field_info'));
535  $form->addItem($checkbox_form);
536  }
537 
538  if ($this->checkAccessBool('write')) {
539  $form->addCommandButton('saveProfile', $this->lng->txt('save'));
540  }
541 
542  return $form;
543  }
544 
545  protected function saveProfile(): void
546  {
547  $this->checkAccessBool('write');
548 
549  $form = $this->initProfileForm();
550  if (!$form->checkInput()) {
551  $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
552  $form->setValuesByPost();
553  $this->profile($form);
554  return;
555  }
556 
557  foreach ($this->settings->getProfileMappingFields() as $field => $lng_key) {
558  $this->settings->setProfileMappingFieldValue(
559  $field,
560  $form->getInput($field . '_value')
561  );
562  $this->settings->setProfileMappingFieldUpdate(
563  $field,
564  (bool) $form->getInput($field . '_update')
565  );
566  }
567  $this->settings->save();
568  $this->mainTemplate->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
569  $this->ctrl->redirect($this, self::STAB_PROFILE);
570  }
571 
572  protected function roles(ilPropertyFormGUI $form = null): void
573  {
574  $this->checkAccess('read');
575  $this->setSubTabs(self::STAB_ROLES);
576 
577  if (!$form instanceof ilPropertyFormGUI) {
578  $form = $this->initRolesForm();
579  }
580  $this->mainTemplate->setContent($form->getHTML());
581  }
582 
583  protected function initRolesForm(): ilPropertyFormGUI
584  {
585  $form = new ilPropertyFormGUI();
586  $form->setTitle($this->lng->txt('auth_oidc_role_mapping_table'));
587  $form->setFormAction($this->ctrl->getFormAction($this, self::STAB_ROLES));
588 
589  foreach ($this->prepareRoleSelection(false) as $role_id => $role_title) {
590  $role_map = new ilTextInputGUI(
591  $role_title,
592  'role_map_' . $role_id
593  );
594  $role_map->setInfo($this->lng->txt('auth_oidc_role_info'));
595  $role_map->setValue($this->settings->getRoleMappingValueForId((int) $role_id));
596  $form->addItem($role_map);
597 
599  '',
600  'role_map_update_' . $role_id
601  );
602  $update->setOptionTitle($this->lng->txt('auth_oidc_update_role_info'));
603  $update->setValue("1");
604  $update->setChecked(!$this->settings->getRoleMappingUpdateForId((int) $role_id));
605  $form->addItem($update);
606  }
607 
608  if ($this->checkAccessBool('write')) {
609  $form->addCommandButton('saveRoles', $this->lng->txt('save'));
610  }
611  return $form;
612  }
613 
614  protected function saveRoles(): void
615  {
616  $this->checkAccess('write');
617  $form = $this->initRolesForm();
618  if ($form->checkInput()) {
619  $this->logger->dump($this->body, ilLogLevel::DEBUG);
620 
621 
622  $role_settings = [];
623  $role_valid = true;
624  foreach ($this->prepareRoleSelection(false) as $role_id => $role_title) {
625  $role_settings[(int) $role_id]['update'] = !$form->getInput('role_map_update_' . $role_id);
626  $role_settings[(int) $role_id]['value'] = '';
627 
628  $input_role = trim($form->getInput('role_map_' . $role_id));
629  if ($input_role === '') {
630  continue;
631  }
632 
633  $role_params = explode('::', $input_role);
634  $this->logger->dump($role_params, ilLogLevel::DEBUG);
635 
636  if (count($role_params) !== 2) {
637  if ($form->getItemByPostVar('role_map_' . $role_id)) {
638  $form->getItemByPostVar('role_map_' . $role_id)->setAlert($this->lng->txt('msg_wrong_format'));
639  }
640  $role_valid = false;
641  continue;
642  }
643  $role_settings[(int) $role_id]['value'] = $input_role;
644  }
645 
646  if (!$role_valid) {
647  $form->setValuesByPost();
648  $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
649  $this->roles($form);
650  return;
651  }
652 
653  $this->settings->setRoleMappings($role_settings);
654  $this->settings->save();
655  $this->mainTemplate->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
656  $this->ctrl->redirect($this, 'roles');
657  }
658 
659  $form->setValuesByPost();
660  $this->mainTemplate->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
661  $this->roles($form);
662  }
663 
664  protected function setSubTabs(string $active_tab): void
665  {
666  $this->tabs->addSubTab(
667  self::STAB_SETTINGS,
668  $this->lng->txt('auth_oidc_' . self::STAB_SETTINGS),
669  $this->ctrl->getLinkTarget($this, self::STAB_SETTINGS)
670  );
671  $this->tabs->addSubTab(
672  self::STAB_PROFILE,
673  $this->lng->txt('auth_oidc_' . self::STAB_PROFILE),
674  $this->ctrl->getLinkTarget($this, self::STAB_PROFILE)
675  );
676  $this->tabs->addSubTab(
677  self::STAB_ROLES,
678  $this->lng->txt('auth_oidc_' . self::STAB_ROLES),
679  $this->ctrl->getLinkTarget($this, self::STAB_ROLES)
680  );
681 
682  $this->tabs->activateSubTab($active_tab);
683  }
684 }
settings(ilPropertyFormGUI $form=null)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class ilOpenIdConnectSettingsGUI.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
prepareRoleSelection(bool $a_with_select_option=true)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class ChatMainBarProvider .
$scopes
Definition: ltitoken.php:99
$session
This class represents a checkbox property in a property form.
$update
Definition: imgupload.php:92
string $secret
Shared secret.
Definition: System.php:43
global $DIC
Definition: feed.php:28
$provider
Definition: ltitoken.php:83
This class represents a property in a property form.
static _lookupTitle(int $obj_id)
This class represents a number property in a property form.
string $key
Consumer key/client ID value.
Definition: System.php:193
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class FileUpload.
Definition: FileUpload.php:34
setRequired(bool $a_required)
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,7),&#39;usr_data&#39;,&#39;lastname&#39;,&#39;usr_id&#39;) => sorts by lastname.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const ANONYMOUS_ROLE_ID
Definition: constants.php:28
Error Handling & global info handling uses PEAR error class.
$client_id
Definition: ltiauth.php:68
setOptionTitle(string $a_optiontitle)
Class FlySystemFileAccessTest disabled disabled disabled.