├── .github ├── PULL_REQUEST_TEMPLATE.txt └── workflows │ └── ci.yml ├── .gitlab-ci.yml ├── LICENSE ├── README.md ├── SECURITY.md ├── auth.php ├── binding_username_claim.php ├── change_binding_username_claim_tool.php ├── classes ├── adminsetting │ ├── auth_oidc_admin_setting_iconselect.php │ ├── auth_oidc_admin_setting_label.php │ ├── auth_oidc_admin_setting_loginflow.php │ ├── auth_oidc_admin_setting_redirecturi.php │ └── iconselect.css ├── event │ ├── action_failed.php │ ├── user_authed.php │ ├── user_connected.php │ ├── user_created.php │ ├── user_disconnected.php │ ├── user_loggedin.php │ └── user_rename_attempt.php ├── form │ ├── application.php │ ├── binding_username_claim.php │ ├── change_binding_username_claim_tool_form1.php │ ├── change_binding_username_claim_tool_form2.php │ └── disconnect.php ├── httpclient.php ├── httpclientinterface.php ├── jwt.php ├── loginflow │ ├── authcode.php │ ├── base.php │ └── rocreds.php ├── observers.php ├── oidcclient.php ├── preview.php ├── privacy │ └── provider.php ├── process.php ├── task │ ├── cleanup_oidc_sid.php │ └── cleanup_oidc_state_and_token.php ├── tests │ ├── mockhttpclient.php │ └── mockoidcclient.php ├── upload_process_tracker.php └── utils.php ├── cleanupoidctokens.php ├── db ├── access.php ├── events.php ├── install.php ├── install.xml ├── tasks.php └── upgrade.php ├── example.csv ├── index.php ├── js └── module.js ├── lang ├── cs │ └── auth_oidc.php ├── de │ └── auth_oidc.php ├── en │ └── auth_oidc.php ├── es │ └── auth_oidc.php ├── fi │ └── auth_oidc.php ├── fr │ └── auth_oidc.php ├── it │ └── auth_oidc.php ├── ja │ └── auth_oidc.php ├── nl │ └── auth_oidc.php ├── pl │ └── auth_oidc.php └── pt_br │ └── auth_oidc.php ├── lib.php ├── logout.php ├── manageapplication.php ├── pix └── o365.png ├── settings.php ├── styles.css ├── tests ├── jwt_test.php ├── oidcclient_test.php └── privacy_provider_test.php ├── ucp.php └── version.php /.github/PULL_REQUEST_TEMPLATE.txt: -------------------------------------------------------------------------------- 1 | *** PLEASE DO NOT OPEN PULL REQUESTS IN THIS REPO *** 2 | 3 | This is a read-only repository for Moodle plugins directory release process. All developments are carried out in the main project repository at https://github.com/microsoft/o365-moodle. Please create your pull requests there. 4 | 5 | Thank you. 6 | 7 | -- -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Moodle Plugin CI for auth_oidc 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | push: 9 | branches: 10 | - 'MOODLE_*_STABLE' 11 | pull_request: 12 | 13 | jobs: 14 | check: 15 | runs-on: ubuntu-latest 16 | 17 | services: 18 | postgres: 19 | image: postgres:13 20 | env: 21 | POSTGRES_USER: 'postgres' 22 | POSTGRES_HOST_AUTH_METHOD: 'trust' 23 | ports: 24 | - 5432:5432 25 | options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 26 | 27 | mariadb: 28 | image: mariadb:10 29 | env: 30 | MYSQL_USER: 'root' 31 | MYSQL_ALLOW_EMPTY_PASSWORD: "true" 32 | MYSQL_CHARACTER_SET_SERVER: "utf8mb4" 33 | MYSQL_COLLATION_SERVER: "utf8mb4_unicode_ci" 34 | MYSQL_INNODB_FILE_PER_TABLE: "1" 35 | MYSQL_INNODB_FILE_FORMAT: "Barracuda" 36 | ports: 37 | - 3306:3306 38 | options: --health-cmd="mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 3 39 | 40 | strategy: 41 | fail-fast: false 42 | matrix: 43 | moodle-branch: ['MOODLE_405_STABLE'] 44 | php: [8.1, 8.2, 8.3] 45 | database: [pgsql, mariadb] 46 | 47 | steps: 48 | - name: Check out repository code 49 | uses: actions/checkout@v4 50 | with: 51 | path: plugin 52 | 53 | - name: Setup PHP ${{ matrix.php }} 54 | uses: shivammathur/setup-php@v2 55 | with: 56 | php-version: ${{ matrix.php }} 57 | ini-values: max_input_vars=5000 58 | coverage: none 59 | 60 | - name: Initialise moodle-plugin-ci 61 | run: | 62 | composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^4 63 | echo $(cd ci/bin; pwd) >> $GITHUB_PATH 64 | echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH 65 | sudo locale-gen en_AU.UTF-8 66 | echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV 67 | 68 | - name: Install moodle-plugin-ci 69 | run: | 70 | moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1 71 | env: 72 | DB: ${{ matrix.database }} 73 | MOODLE_BRANCH: ${{ matrix.moodle-branch }} 74 | SHELLOPTS: errexit:nounset:xtrace 75 | 76 | - name: PHP Lint 77 | if: ${{ !cancelled() }} 78 | run: moodle-plugin-ci phplint 79 | 80 | - name: PHP Mess Detector 81 | continue-on-error: true 82 | if: ${{ !cancelled() }} 83 | run: moodle-plugin-ci phpmd 84 | 85 | - name: Moodle Code Checker 86 | if: ${{ !cancelled() }} 87 | run: moodle-plugin-ci phpcs --max-warnings 0 88 | 89 | - name: Moodle PHPDoc Checker 90 | if: ${{ !cancelled() }} 91 | run: moodle-plugin-ci phpdoc --max-warnings 0 92 | 93 | - name: Validating 94 | if: ${{ !cancelled() }} 95 | run: moodle-plugin-ci validate 96 | 97 | - name: Check upgrade savepoints 98 | if: ${{ !cancelled() }} 99 | run: moodle-plugin-ci savepoints 100 | 101 | - name: Mustache Lint 102 | if: ${{ !cancelled() }} 103 | run: moodle-plugin-ci mustache 104 | 105 | - name: Grunt 106 | if: ${{ !cancelled() }} 107 | run: moodle-plugin-ci grunt --max-lint-warnings 0 108 | 109 | - name: PHPUnit tests 110 | if: ${{ !cancelled() }} 111 | run: moodle-plugin-ci phpunit 112 | 113 | - name: Behat features 114 | id: behat 115 | if: ${{ !cancelled() }} 116 | run: moodle-plugin-ci behat --profile chrome 117 | 118 | - name: Cleanup after behat 119 | if: ${{ always() }} 120 | run: | 121 | sudo pkill -f chrome 122 | sudo pkill -f chromedriver 123 | 124 | - name: Mark cancelled jobs as failed. 125 | if: ${{ cancelled() }} 126 | run: exit 1 -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | services: 2 | - name: selenium/standalone-chrome:3 3 | alias: behat 4 | - name: mysql:8.0 5 | alias: db 6 | command: 7 | - '--character-set-server=utf8mb4' 8 | - '--collation-server=utf8mb4_unicode_ci' 9 | - '--innodb_file_per_table=On' 10 | - '--wait-timeout=28800' 11 | - '--skip-log-bin' 12 | 13 | cache: 14 | paths: 15 | - .cache 16 | 17 | variables: 18 | DEBIAN_FRONTEND: 'noninteractive' 19 | COMPOSER_ALLOW_SUPERUSER: 1 20 | COMPOSER_CACHE_DIR: "$CI_PROJECT_DIR/.cache/composer" 21 | NPM_CONFIG_CACHE: "$CI_PROJECT_DIR/.cache/npm" 22 | CI_BUILD_DIR: '/tmp/plugin' 23 | MOODLE_BRANCH: 'MOODLE_405_STABLE' 24 | MOODLE_BEHAT_WWWROOT: 'http://localhost:8000' 25 | MOODLE_BEHAT_WDHOST: 'http://behat:4444/wd/hub' 26 | MOODLE_START_BEHAT_SERVERS: 'no' 27 | MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' 28 | DB: 'mysqli' 29 | 30 | stages: 31 | - moodle-plugin-ci 32 | 33 | .setupandruncheck: &setupandruncheck 34 | stage: moodle-plugin-ci 35 | before_script: 36 | - mkdir -pv "$CI_BUILD_DIR" 37 | - cp -ru "$CI_PROJECT_DIR/"* "$CI_BUILD_DIR" 38 | - mkdir -p /usr/share/man/man1 /usr/share/man/man3 /usr/share/man/man7 39 | - apt-get -qq update 40 | - apt-get -yqq install --no-install-suggests default-jre-headless default-mysql-client 41 | - 'curl -sS https://raw.githubusercontent.com/creationix/nvm/v0.39.3/install.sh | bash' 42 | - . ~/.bashrc 43 | - nvm install --default --latest-npm lts/gallium 44 | - 'curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer' 45 | - composer create-project -n --no-dev --no-progress --no-ansi moodlehq/moodle-plugin-ci /opt/mci ^4 46 | - export PATH="/opt/mci/bin:/opt/mci/vendor/bin:$PATH" 47 | - moodle-plugin-ci install --db-host db --db-name moodle 48 | - '{ php -S 0.0.0.0:8000 -t "$CI_PROJECT_DIR/moodle" >/dev/null 2>&1 & }' 49 | - TXT_RED="\e[31m" 50 | 51 | script: 52 | - errors=() 53 | - moodle-plugin-ci phplint || errors+=("phplint") 54 | - moodle-plugin-ci phpmd || errors+=("phpmd") 55 | - moodle-plugin-ci codechecker --max-warnings 0 || errors+=("codechecker") 56 | - moodle-plugin-ci phpdoc --max-warnings 0 || errors+=("phpdoc") 57 | - moodle-plugin-ci validate || errors+=("validate") 58 | - moodle-plugin-ci savepoints || errors+=("savepoints") 59 | - moodle-plugin-ci mustache || errors+=("mustache") 60 | - moodle-plugin-ci grunt --max-lint-warnings 0 || errors+=("grunt") 61 | - moodle-plugin-ci phpunit || errors+=("phpunit") 62 | - moodle-plugin-ci behat --auto-rerun 0 --profile chrome || errors+=("behat") 63 | - |- 64 | if [ ${#errors[@]} -ne 0 ]; then 65 | echo -e "${TXT_RED}Check errors: ${errors[@]}"; 66 | exit 1; 67 | fi 68 | 69 | php81: 70 | tags: 71 | - docker 72 | image: moodlehq/moodle-php-apache:8.1 73 | <<: *setupandruncheck 74 | 75 | php82: 76 | tags: 77 | - docker 78 | image: moodlehq/moodle-php-apache:8.2 79 | <<: *setupandruncheck 80 | 81 | php83: 82 | tags: 83 | - docker 84 | image: moodlehq/moodle-php-apache:8.3 85 | <<: *setupandruncheck 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Microsoft 365 and Microsoft Entra ID Plugins for Moodle 2 | 3 | ## OpenID Connect Authentication Plugin. 4 | 5 | The OpenID Connect plugin provides single-sign-on functionality using configurable identity providers. 6 | 7 | This is part of the suite of Microsoft 365 plugins for Moodle. 8 | 9 | This repository is updated with stable releases. To follow active development, see: https://github.com/Microsoft/o365-moodle 10 | 11 | ## Installation 12 | 13 | 1. Unpack the plugin into /auth/oidc within your Moodle install. 14 | 2. From the Moodle Administration block, expand Site Administration and click "Notifications". 15 | 3. Follow the on-screen instuctions to install the plugin. 16 | 4. To configure the plugin, from the Moodle Administration block, go to Site Administration > Plugins > Authentication > Manage Authentication. 17 | 5. Click the icon to enable the plugin, then visit the settings page to configure the plugin. Follow the directions below each setting. 18 | 19 | For more documentation, visit https://docs.moodle.org/34/en/Office365 20 | 21 | For more information including support and instructions on how to contribute, please see: https://github.com/Microsoft/o365-moodle/blob/master/README.md 22 | 23 | ## Issues and Contributing 24 | Please post issues for this plugin to: https://github.com/Microsoft/o365-moodle/issues/ 25 | Pull requests for this plugin should be submitted against our main repository: https://github.com/Microsoft/o365-moodle 26 | 27 | ## Copyright 28 | 29 | © Microsoft, Inc. Code for this plugin is licensed under the GPLv3 license. 30 | 31 | Any Microsoft trademarks and logos included in these plugins are property of Microsoft and should not be reused, redistributed, modified, repurposed, or otherwise altered or used outside of this plugin. 32 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /binding_username_claim.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Manage binding username claim page. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2023 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | use auth_oidc\form\binding_username_claim; 27 | 28 | require_once(dirname(__FILE__) . '/../../config.php'); 29 | require_once($CFG->libdir . '/adminlib.php'); 30 | require_once($CFG->dirroot . '/auth/oidc/lib.php'); 31 | 32 | require_login(); 33 | 34 | $url = new moodle_url('/auth/oidc/binding_username_claim.php'); 35 | $PAGE->set_url($url); 36 | $PAGE->set_context(context_system::instance()); 37 | $PAGE->set_pagelayout('admin'); 38 | $PAGE->set_heading(get_string('settings_page_binding_username_claim', 'auth_oidc')); 39 | $PAGE->set_title(get_string('settings_page_binding_username_claim', 'auth_oidc')); 40 | 41 | admin_externalpage_setup('auth_oidc_binding_username_claim'); 42 | 43 | require_admin(); 44 | 45 | $form = new binding_username_claim(null); 46 | $formdata = []; 47 | 48 | // Validate auth_oidc_binding_username_claim settings. 49 | $predefinedbindingclaims = ['auto', 'preferred_username', 'email', 'upn', 'unique_name', 'sub', 'oid', 'samaccountname']; 50 | 51 | $oidcconfig = get_config('auth_oidc'); 52 | if (!isset($oidcconfig->bindingusernameclaim)) { 53 | // Bindingusernameclaim is not set, set default value. 54 | $formdata['bindingusernameclaim'] = 'auto'; 55 | $formdata['customclaimname'] = ''; 56 | set_config('bindingusernameclaim', 'auto', 'auth_oidc'); 57 | } else if (!$oidcconfig->bindingusernameclaim) { 58 | $formdata['bindingusernameclaim'] = 'auto'; 59 | $formdata['customclaimname'] = ''; 60 | } else if (in_array($oidcconfig->bindingusernameclaim, $predefinedbindingclaims)) { 61 | $formdata['bindingusernameclaim'] = $oidcconfig->bindingusernameclaim; 62 | $formdata['customclaimname'] = ''; 63 | } else { 64 | $formdata['bindingusernameclaim'] = 'custom'; 65 | $formdata['customclaimname'] = $oidcconfig->bindingusernameclaim; 66 | } 67 | 68 | $form->set_data($formdata); 69 | 70 | if ($form->is_cancelled()) { 71 | redirect($url); 72 | } else if ($fromform = $form->get_data()) { 73 | $configstosave = ['bindingusernameclaim', 'customclaimname']; 74 | 75 | $configchanged = false; 76 | 77 | foreach ($configstosave as $config) { 78 | if (isset($fromform->$config)) { 79 | $existingsetting = $oidcconfig->$config; 80 | if ($fromform->$config != $existingsetting) { 81 | $configchanged = true; 82 | set_config($config, $fromform->$config, 'auth_oidc'); 83 | add_to_config_log($config, $existingsetting, $fromform->$config, 'auth_oidc'); 84 | } 85 | } 86 | } 87 | 88 | if ($configchanged) { 89 | redirect($url, get_string('binding_username_claim_updated', 'auth_oidc')); 90 | } else { 91 | redirect($url); 92 | } 93 | } 94 | 95 | $existingclaims = auth_oidc_get_existing_claims(); 96 | 97 | echo $OUTPUT->header(); 98 | 99 | echo $OUTPUT->heading(get_string('binding_username_claim_heading', 'auth_oidc')); 100 | $bindingusernametoolurl = new moodle_url('/auth/oidc/change_binding_username_claim_tool.php'); 101 | echo html_writer::tag('p', get_string('binding_username_claim_description', 'auth_oidc', $bindingusernametoolurl->out())); 102 | if ($existingclaims) { 103 | echo html_writer::tag('p', get_string('binding_username_claim_description_existing_claims', 'auth_oidc', 104 | implode(' / ', $existingclaims))); 105 | } 106 | 107 | $form->display(); 108 | 109 | echo $OUTPUT->footer(); 110 | -------------------------------------------------------------------------------- /change_binding_username_claim_tool.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Change binding username claim tool page. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2023 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | use auth_oidc\form\change_binding_username_claim_tool_form1; 27 | use auth_oidc\form\change_binding_username_claim_tool_form2; 28 | use auth_oidc\preview; 29 | use auth_oidc\process; 30 | 31 | require_once(dirname(__FILE__) . '/../../config.php'); 32 | require_once($CFG->libdir . '/adminlib.php'); 33 | require_once($CFG->libdir . '/csvlib.class.php'); 34 | 35 | require_login(); 36 | 37 | $url = new moodle_url('/auth/oidc/change_binding_username_claim_tool.php'); 38 | $PAGE->set_url($url); 39 | $PAGE->set_context(context_system::instance()); 40 | $PAGE->set_pagelayout('admin'); 41 | $PAGE->set_heading(get_string('settings_page_change_binding_username_claim_tool', 'auth_oidc')); 42 | $PAGE->set_title(get_string('settings_page_change_binding_username_claim_tool', 'auth_oidc')); 43 | 44 | admin_externalpage_setup('auth_oidc_change_binding_username_claim_tool'); 45 | 46 | require_admin(); 47 | 48 | $iid = optional_param('iid', '', PARAM_INT); 49 | $previewrows = optional_param('previewrows', 10, PARAM_INT); 50 | 51 | core_php_time_limit::raise(60 * 60); // 1 hour should be enough. 52 | raise_memory_limit(MEMORY_HUGE); 53 | 54 | if (empty($iid)) { 55 | $form1 = new change_binding_username_claim_tool_form1(); 56 | if ($formdata = $form1->get_data()) { 57 | $iid = csv_import_reader::get_new_iid('changebindingusernameclaimtool'); 58 | $cir = new csv_import_reader($iid, 'changebindingusernameclaimtool'); 59 | 60 | $content = $form1->get_file_content('usernamefile'); 61 | 62 | $readcount = $cir->load_csv_content($content, $formdata->encoding, $formdata->delimiter_name); 63 | $csvloaderror = $cir->get_error(); 64 | unset($content); 65 | 66 | if (!is_null($csvloaderror)) { 67 | throw new moodle_exception('csvloaderror', '', $url, $csvloaderror); 68 | } 69 | } else { 70 | echo $OUTPUT->header(); 71 | 72 | echo $OUTPUT->heading(get_string('change_binding_username_claim_tool', 'auth_oidc')); 73 | $bindingusernameclaimurl = new moodle_url('/auth/oidc/binding_username_claim.php'); 74 | echo html_writer::tag('p', get_string('change_binding_username_claim_tool_description', 'auth_oidc', 75 | $bindingusernameclaimurl->out())); 76 | 77 | $form1->display(); 78 | 79 | echo $OUTPUT->footer(); 80 | exit; 81 | } 82 | } else { 83 | $cir = new csv_import_reader($iid, 'changebindingusernameclaimtool'); 84 | } 85 | 86 | // Test if columns ok. 87 | $process = new process($cir); 88 | $filecolumns = $process->get_file_columns(); 89 | 90 | $mform2 = new change_binding_username_claim_tool_form2(null, 91 | ['columns' => $filecolumns, 'data' => ['iid' => $iid, 'previewrows' => $previewrows]]); 92 | 93 | // If a file has been uploaded, then process it. 94 | if ($mform2->is_cancelled()) { 95 | $cir->cleanup(true); 96 | redirect($url); 97 | } else if ($formdata = $mform2->get_data()) { 98 | // Print the header. 99 | echo $OUTPUT->header(); 100 | echo $OUTPUT->heading(get_string('change_binding_username_claim_tool_result', 'auth_oidc')); 101 | 102 | $process->set_form_data($formdata); 103 | $process->process(); 104 | 105 | echo $OUTPUT->box_start('boxwidthnarrow boxaligncenter generalbox', 'uploadresults'); 106 | echo html_writer::tag('p', join('
', $process->get_stats())); 107 | echo $OUTPUT->box_end(); 108 | 109 | echo $OUTPUT->footer(); 110 | exit; 111 | } 112 | 113 | // Print the header. 114 | echo $OUTPUT->header(); 115 | 116 | echo $OUTPUT->heading(get_string('change_binding_username_claim_tool', 'auth_oidc')); 117 | 118 | $table = new preview($cir, $filecolumns, $previewrows); 119 | 120 | echo html_writer::tag('div', html_writer::table($table), ['class' => 'flexible-wrap']); 121 | 122 | if ($table->get_no_error()) { 123 | $mform2->display(); 124 | } 125 | 126 | echo $OUTPUT->footer(); 127 | 128 | exit; 129 | -------------------------------------------------------------------------------- /classes/adminsetting/auth_oidc_admin_setting_iconselect.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Definition of an icon selector admin setting control. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\adminsetting; 27 | 28 | /** 29 | * Choose an icon for the identity provider entry on the login page. 30 | */ 31 | class auth_oidc_admin_setting_iconselect extends \admin_setting { 32 | /** @var array The stock icons. */ 33 | protected $choices = []; 34 | 35 | /** 36 | * Constructor. 37 | * 38 | * @param string $name Name of the setting. 39 | * @param string $visiblename Visible name of the setting. 40 | * @param string $description Description of the setting. 41 | * @param array $defaultsetting Default value. 42 | * @param array $choices Array of icon choices. 43 | */ 44 | public function __construct($name, $visiblename, $description, $defaultsetting, $choices) { 45 | $this->choices = $choices; 46 | parent::__construct($name, $visiblename, $description, $defaultsetting, $choices); 47 | } 48 | 49 | /** 50 | * Return the setting 51 | * 52 | * @return mixed returns config if successful else null 53 | */ 54 | public function get_setting() { 55 | return $this->config_read($this->name); 56 | } 57 | 58 | /** 59 | * Save a setting 60 | * 61 | * @param string $data 62 | * 63 | * @return string empty of error string 64 | */ 65 | public function write_setting($data) { 66 | // Validate incoming data. 67 | $found = false; 68 | foreach ($this->choices as $icon) { 69 | $id = $icon['component'] . ':' . $icon['pix']; 70 | if ($data === $id) { 71 | $found = true; 72 | break; 73 | } 74 | } 75 | 76 | // Invalid value received, ignore it. 77 | if ($found !== true) { 78 | return ''; 79 | } 80 | 81 | return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 82 | } 83 | 84 | /** 85 | * Get admin setting HTML. 86 | * 87 | * @param mixed $data Saved data. 88 | * @param string $query 89 | * 90 | * @return string The setting HTML. 91 | */ 92 | public function output_html($data, $query = '') { 93 | global $CFG, $OUTPUT; 94 | $attrs = ['type' => 'text/css', 'rel' => 'stylesheet', 95 | 'href' => new \moodle_url('/auth/oidc/classes/adminsetting/iconselect.css')]; 96 | $html = \html_writer::empty_tag('link', $attrs); 97 | $html .= \html_writer::start_tag('div', ['style' => 'max-width: 390px']); 98 | $selected = (!empty($data)) ? $data : $this->defaultsetting; 99 | foreach ($this->choices as $icon) { 100 | $id = $icon['component'] . ':' . $icon['pix']; 101 | $iconhtml = $OUTPUT->image_icon($icon['pix'], $icon['alt'], $icon['component']); 102 | $inputattrs = [ 103 | 'type' => 'radio', 104 | 'id' => $id, 105 | 'name' => $this->get_full_name(), 106 | 'value' => $id, 107 | 'class' => 'iconselect', 108 | ]; 109 | 110 | if ($id === $selected) { 111 | $inputattrs['checked'] = 'checked'; 112 | } 113 | $html .= \html_writer::empty_tag('input', $inputattrs); 114 | $labelattrs = [ 115 | 'class' => 'iconselect', 116 | ]; 117 | $html .= \html_writer::label($iconhtml, $id, true, $labelattrs); 118 | } 119 | $html .= \html_writer::end_tag('div'); 120 | 121 | return format_admin_setting($this, $this->visiblename, $html, $this->description, true, '', null, $query); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /classes/adminsetting/auth_oidc_admin_setting_label.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Definition of a label admin setting control. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2021 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\adminsetting; 27 | 28 | use admin_setting; 29 | 30 | /** 31 | * Display a static text. 32 | */ 33 | class auth_oidc_admin_setting_label extends admin_setting { 34 | /** 35 | * @var string $label The label for display purposes. 36 | */ 37 | private $label; 38 | 39 | /** 40 | * Constructor. 41 | * 42 | * @param string $name The setting name. 43 | * @param string $label The label to display. 44 | * @param string $visiblename The visible name for the setting. 45 | * @param string $description A description of the setting. 46 | */ 47 | public function __construct($name, $label, $visiblename, $description) { 48 | parent::__construct($name, $visiblename, $description, ''); 49 | $this->label = $label; 50 | } 51 | 52 | /** 53 | * No settings to get. 54 | * 55 | * @return bool 56 | */ 57 | public function get_setting() { 58 | return true; 59 | } 60 | 61 | /** 62 | * Nothing to write. 63 | * 64 | * @param mixed $data 65 | * 66 | * @return string 67 | */ 68 | public function write_setting($data) { 69 | return ''; 70 | } 71 | 72 | /** 73 | * Output the setting. 74 | * 75 | * @param mixed $data 76 | * @param string $query 77 | * 78 | * @return string 79 | */ 80 | public function output_html($data, $query = '') { 81 | return format_admin_setting($this, $this->label, $this->visiblename, $this->description, false); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /classes/adminsetting/auth_oidc_admin_setting_loginflow.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Definition of login flow selector admin setting control. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\adminsetting; 27 | 28 | /** 29 | * Displays the redirect URI for easier config. 30 | */ 31 | class auth_oidc_admin_setting_loginflow extends \admin_setting { 32 | /** @var array Array of valid login flow types. */ 33 | protected $flowtypes = ['authcode', 'rocreds']; 34 | 35 | /** 36 | * Return the setting 37 | * 38 | * @return mixed returns config if successful else null 39 | */ 40 | public function get_setting() { 41 | return $this->config_read($this->name); 42 | } 43 | 44 | /** 45 | * Save a setting 46 | * 47 | * @param string $data 48 | * @return string empty of error string 49 | */ 50 | public function write_setting($data) { 51 | if (!in_array($data, $this->flowtypes)) { 52 | // Ignore invalid settings. 53 | return ''; 54 | } 55 | 56 | return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin')); 57 | } 58 | 59 | /** 60 | * Returns XHTML select field and wrapping div(s) 61 | * 62 | * @see output_select_html() 63 | * 64 | * @param string $data the option to show as selected 65 | * @param string $query 66 | * @return string XHTML field and wrapping div 67 | */ 68 | public function output_html($data, $query = '') { 69 | $html = ''; 70 | $baseid = $this->get_id(); 71 | $inputname = $this->get_full_name(); 72 | 73 | foreach ($this->flowtypes as $flowtype) { 74 | $html .= \html_writer::start_div(); 75 | $flowtypeid = $baseid.'_'.$flowtype; 76 | $radioattrs = [ 77 | 'type' => 'radio', 78 | 'name' => $inputname, 79 | 'id' => $flowtypeid, 80 | 'value' => $flowtype, 81 | ]; 82 | if ($data === $flowtype || (empty($data) && $flowtype === $this->get_defaultsetting())) { 83 | $radioattrs['checked'] = 'checked'; 84 | } 85 | $typename = get_string('cfg_loginflow_'.$flowtype, 'auth_oidc'); 86 | $typedesc = get_string('cfg_loginflow_'.$flowtype.'_desc', 'auth_oidc'); 87 | $html .= \html_writer::empty_tag('input', $radioattrs); 88 | $html .= \html_writer::label($typename, $flowtypeid, false); 89 | $html .= '
'; 90 | $html .= \html_writer::span($typedesc); 91 | $html .= '

'; 92 | $html .= \html_writer::end_div(); 93 | } 94 | 95 | return format_admin_setting($this, $this->visiblename, $html, $this->description, true, '', null, $query); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /classes/adminsetting/auth_oidc_admin_setting_redirecturi.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Definition of a redirect URL admin setting control. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\adminsetting; 27 | 28 | use auth_oidc\utils; 29 | 30 | /** 31 | * Displays the redirect URI for easier config. 32 | */ 33 | class auth_oidc_admin_setting_redirecturi extends \admin_setting { 34 | /** 35 | * @var string $url The redirect URL for the configuration. 36 | */ 37 | private $url; 38 | 39 | /** 40 | * Constructor. 41 | * 42 | * @param string $name The setting name. 43 | * @param string $heading The setting heading. 44 | * @param string $description The setting description. 45 | * @param string $url The redirect URL. 46 | */ 47 | public function __construct($name, $heading, $description, $url) { 48 | $this->nosave = true; 49 | $this->url = $url; 50 | parent::__construct($name, $heading, $description, ''); 51 | } 52 | 53 | /** 54 | * Always returns true because we have no real setting. 55 | * 56 | * @return bool Always returns true 57 | */ 58 | public function get_setting() { 59 | return true; 60 | } 61 | 62 | /** 63 | * Always returns true because we have no real setting. 64 | * 65 | * @return bool Always returns true 66 | */ 67 | public function get_defaultsetting() { 68 | return true; 69 | } 70 | 71 | /** 72 | * Never write settings. 73 | * 74 | * @param mixed $data 75 | * @return string Always returns an empty string. 76 | */ 77 | public function write_setting($data) { 78 | return ''; 79 | } 80 | 81 | /** 82 | * Returns an HTML string for the redirect uri display. 83 | * 84 | * @param mixed $data 85 | * @param string $query 86 | * @return string Returns an HTML string. 87 | */ 88 | public function output_html($data, $query = '') { 89 | $redirecturl = utils::get_redirecturl(); 90 | $redirecturl = $this->url; 91 | $html = \html_writer::tag('h5', $redirecturl); 92 | return format_admin_setting($this, $this->visiblename, $html, $this->description, true, '', null, $query); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /classes/adminsetting/iconselect.css: -------------------------------------------------------------------------------- 1 | label.iconselect { 2 | display: inline-block !important; 3 | padding: 0 !important; 4 | margin: 5px; 5 | } 6 | label.iconselect img { 7 | width: 25px; 8 | height: 25px; 9 | padding: 10px; 10 | } 11 | input.iconselect { 12 | display: none; 13 | } 14 | input[type="radio"].iconselect:checked + label.iconselect { 15 | outline: 1px solid #007fec; 16 | } 17 | body.ie input.iconselect { 18 | display: inline-block; 19 | } 20 | body.ie label.iconselect { 21 | margin-left: 0; 22 | margin-right: 20px; 23 | } 24 | body.ie label.iconselect img { 25 | padding: 5px; 26 | } -------------------------------------------------------------------------------- /classes/event/action_failed.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * An event when something wrong happened, and debug message needs to be logged. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\event; 27 | 28 | /** 29 | * Event fired whenever we need to record a debug message. 30 | */ 31 | class action_failed extends \core\event\base { 32 | /** 33 | * Return localised event name. 34 | * 35 | * @return string 36 | */ 37 | public static function get_name() { 38 | return get_string('event_debug', 'auth_oidc'); 39 | } 40 | 41 | /** 42 | * Returns non-localised event description with id's for admin use only. 43 | * 44 | * @return string 45 | */ 46 | public function get_description() { 47 | return $this->data['other']; 48 | } 49 | 50 | /** 51 | * Init method. 52 | * 53 | * @return void 54 | */ 55 | protected function init() { 56 | $this->context = \context_system::instance(); 57 | $this->data['crud'] = 'r'; 58 | $this->data['edulevel'] = self::LEVEL_OTHER; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /classes/event/user_authed.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * A user authenticated with IODC event. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\event; 27 | 28 | /** 29 | * Event fired when a user authenticated with OIDC, but does not log in. 30 | */ 31 | class user_authed extends \core\event\base { 32 | /** 33 | * Return localised event name. 34 | * 35 | * @return string 36 | */ 37 | public static function get_name() { 38 | return get_string('eventuserauthed', 'auth_oidc'); 39 | } 40 | 41 | /** 42 | * Returns non-localised event description with id's for admin use only. 43 | * 44 | * @return string 45 | */ 46 | public function get_description() { 47 | return "A user authorized with OpenID Connect, but did not associate with a user account."; 48 | } 49 | 50 | /** 51 | * Init method. 52 | * 53 | * @return void 54 | */ 55 | protected function init() { 56 | $this->context = \context_system::instance(); 57 | $this->data['crud'] = 'r'; 58 | $this->data['edulevel'] = self::LEVEL_OTHER; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /classes/event/user_connected.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * A user ocnnects to OpenID Connect event. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\event; 27 | 28 | /** 29 | * Fired when a user connects to OpenID Connect. 30 | */ 31 | class user_connected extends \core\event\base { 32 | /** 33 | * Return localised event name. 34 | * 35 | * @return string 36 | */ 37 | public static function get_name() { 38 | return get_string('eventuserconnected', 'auth_oidc'); 39 | } 40 | 41 | /** 42 | * Returns non-localised event description with id's for admin use only. 43 | * 44 | * @return string 45 | */ 46 | public function get_description() { 47 | return "The user with id '$this->userid' has switched to using OpenID Connect (auth plugin 'auth_oidc')."; 48 | } 49 | 50 | /** 51 | * Init method. 52 | * 53 | * @return void 54 | */ 55 | protected function init() { 56 | $this->context = \context_system::instance(); 57 | $this->data['crud'] = 'r'; 58 | $this->data['edulevel'] = self::LEVEL_OTHER; 59 | $this->data['objecttable'] = 'user'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /classes/event/user_created.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * OIDC user created event. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\event; 27 | 28 | /** 29 | * Event fired when OIDC creates a new user. 30 | */ 31 | class user_created extends \core\event\base { 32 | /** 33 | * Return localised event name. 34 | * 35 | * @return string 36 | */ 37 | public static function get_name() { 38 | return get_string('eventusercreated', 'auth_oidc'); 39 | } 40 | 41 | /** 42 | * Returns non-localised event description with id's for admin use only. 43 | * 44 | * @return string 45 | */ 46 | public function get_description() { 47 | return "A user (user id '{$this->userid}') was creatd using the OpenID Connect authentication plugin."; 48 | } 49 | 50 | /** 51 | * Init method. 52 | * 53 | * @return void 54 | */ 55 | protected function init() { 56 | $this->context = \context_system::instance(); 57 | $this->data['crud'] = 'c'; 58 | $this->data['edulevel'] = self::LEVEL_OTHER; 59 | $this->data['objecttable'] = 'user'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /classes/event/user_disconnected.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * A user disconnected from OpenID Connect event. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\event; 27 | 28 | /** 29 | * Fired when a user disconnects from OpenID Connect. 30 | */ 31 | class user_disconnected extends \core\event\base { 32 | /** 33 | * Return localised event name. 34 | * 35 | * @return string 36 | */ 37 | public static function get_name() { 38 | return get_string('eventuserdisconnected', 'auth_oidc'); 39 | } 40 | 41 | /** 42 | * Returns non-localised event description with id's for admin use only. 43 | * 44 | * @return string 45 | */ 46 | public function get_description() { 47 | return "The user with id '$this->userid' has disconnected from OpenID Connect (auth plugin 'auth_oidc')."; 48 | } 49 | 50 | /** 51 | * Init method. 52 | * 53 | * @return void 54 | */ 55 | protected function init() { 56 | $this->context = \context_system::instance(); 57 | $this->data['crud'] = 'r'; 58 | $this->data['edulevel'] = self::LEVEL_OTHER; 59 | $this->data['objecttable'] = 'user'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /classes/event/user_loggedin.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * A user uses OIDC logged in event. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\event; 27 | 28 | /** 29 | * Fired when a user uses OIDC to log in. 30 | */ 31 | class user_loggedin extends \core\event\base { 32 | /** 33 | * Return localised event name. 34 | * 35 | * @return string 36 | */ 37 | public static function get_name() { 38 | return get_string('eventuserloggedin', 'auth_oidc'); 39 | } 40 | 41 | /** 42 | * Returns non-localised event description with id's for admin use only. 43 | * 44 | * @return string 45 | */ 46 | public function get_description() { 47 | return "The user with id '$this->userid' has logged in using OpenID Connect (auth plugin 'auth_oidc')."; 48 | } 49 | 50 | /** 51 | * Init method. 52 | * 53 | * @return void 54 | */ 55 | protected function init() { 56 | $this->context = \context_system::instance(); 57 | $this->data['crud'] = 'r'; 58 | $this->data['edulevel'] = self::LEVEL_OTHER; 59 | $this->data['objecttable'] = 'user'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /classes/event/user_rename_attempt.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * A Moodle user rename attempt event. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\event; 27 | 28 | use context_system; 29 | use core\event\base; 30 | 31 | /** 32 | * Fired when a user attempts to change their username from the auth_oidc plugin. 33 | */ 34 | class user_rename_attempt extends base { 35 | /** 36 | * Return localised event name. 37 | * 38 | * @return string 39 | */ 40 | public static function get_name() { 41 | return get_string('eventuserrenameattempt', 'auth_oidc'); 42 | } 43 | 44 | /** 45 | * Returns non-localised event description with id's for admin use only. 46 | * 47 | * @return string 48 | */ 49 | public function get_description() { 50 | return "The auth_oidc plugin attempts to change the username of the user with id '$this->userid'."; 51 | } 52 | 53 | /** 54 | * Init method. 55 | * 56 | * @return void 57 | */ 58 | protected function init() { 59 | $this->context = context_system::instance(); 60 | $this->data['crud'] = 'u'; 61 | $this->data['edulevel'] = self::LEVEL_OTHER; 62 | $this->data['objecttable'] = 'user'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /classes/form/binding_username_claim.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Manage binding username claim form. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2022 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\form; 27 | 28 | use moodle_exception; 29 | use moodleform; 30 | 31 | defined('MOODLE_INTERNAL') || die(); 32 | 33 | require_once($CFG->dirroot . '/auth/oidc/lib.php'); 34 | 35 | /** 36 | * Class bindingusernameclaim represents the form on the binding username claim configuration page. 37 | */ 38 | class binding_username_claim extends moodleform { 39 | /** 40 | * Option for setting a non-Microsoft IdP. 41 | */ 42 | const OPTION_SET_NON_MS_IDP = 1; 43 | 44 | /** 45 | * Option for setting a Microsoft IdP without user sync. 46 | */ 47 | const OPTION_SET_MS_NO_USER_SYNC = 2; 48 | 49 | /** 50 | * Option for setting a Microsoft IdP with user sync enabled. 51 | */ 52 | const OPTION_SET_MS_WITH_USER_SYNC = 3; 53 | 54 | /** @var int */ 55 | private $optionset = 0; 56 | 57 | /** 58 | * Form definition. 59 | * 60 | * @return void 61 | */ 62 | protected function definition() { 63 | $mform =& $this->_form; 64 | 65 | // Binding username claim. 66 | $idptype = get_config('auth_oidc', 'idptype'); 67 | $bindingusernameoptions = []; 68 | switch ($idptype) { 69 | case AUTH_OIDC_IDP_TYPE_OTHER: 70 | $this->optionset = self::OPTION_SET_NON_MS_IDP; 71 | $descriptionidentifier = 'binding_username_claim_help_non_ms'; 72 | $bindingusernameoptions = [ 73 | 'auto' => get_string('binding_username_auto', 'auth_oidc'), // Use default logic. 74 | 'preferred_username' => 'preferred_username', 75 | 'email' => 'email', 76 | 'unique_name' => 'unique_name', 77 | 'sub' => 'sub', 78 | 'samaccountname' => 'samaccountname', 79 | 'custom' => get_string('binding_username_custom', 'auth_oidc'), // Custom value. 80 | ]; 81 | break; 82 | case AUTH_OIDC_IDP_TYPE_MICROSOFT_IDENTITY_PLATFORM: 83 | case AUTH_OIDC_IDP_TYPE_MICROSOFT_ENTRA_ID: 84 | if (auth_oidc_is_local_365_installed() && auth_oidc_is_user_sync_enabled()) { 85 | $this->optionset = self::OPTION_SET_MS_WITH_USER_SYNC; 86 | $descriptionidentifier = 'binding_username_claim_help_ms_with_user_sync'; 87 | $bindingusernameoptions = [ 88 | 'auto' => get_string('binding_username_auto', 'auth_oidc'), // Use default logic. 89 | 'email' => 'email', 90 | 'upn' => 'upn', 91 | 'oid' => 'oid', 92 | 'samaccountname' => 'samaccountname', 93 | ]; 94 | } else { 95 | $this->optionset = self::OPTION_SET_MS_NO_USER_SYNC; 96 | $descriptionidentifier = 'binding_username_claim_help_ms_no_user_sync'; 97 | $bindingusernameoptions = [ 98 | 'auto' => get_string('binding_username_auto', 'auth_oidc'), // Use default logic. 99 | 'preferred_username' => 'preferred_username', 100 | 'email' => 'email', 101 | 'upn' => 'upn', 102 | 'unique_name' => 'unique_name', 103 | 'oid' => 'oid', 104 | 'sub' => 'sub', 105 | 'samaccountname' => 'samaccountname', 106 | 'custom' => get_string('binding_username_custom', 'auth_oidc'), // Custom value. 107 | ]; 108 | } 109 | break; 110 | } 111 | 112 | if (empty($bindingusernameoptions)) { 113 | throw new moodle_exception('missing_idp_type', 'auth_oidc'); 114 | } 115 | 116 | $mform->addElement( 117 | 'select', 118 | 'bindingusernameclaim', 119 | auth_oidc_config_name_in_form('bindingusernameclaim'), 120 | $bindingusernameoptions 121 | ); 122 | $mform->setDefault('bindingusernameclaim', 'auto'); 123 | $mform->addElement('static', 'bindingusernameclaim_description', '', get_string($descriptionidentifier, 'auth_oidc')); 124 | 125 | // Custom claim name. 126 | if ($this->optionset == self::OPTION_SET_NON_MS_IDP || $this->optionset == self::OPTION_SET_MS_NO_USER_SYNC) { 127 | $mform->addElement('text', 'customclaimname', auth_oidc_config_name_in_form('customclaimname'), ['size' => 40]); 128 | $mform->setType('customclaimname', PARAM_TEXT); 129 | $mform->disabledIf('customclaimname', 'bindingusernameclaim', 'neq', 'custom'); // Enable only if "Custom" is selected. 130 | 131 | // Custom claim name description. 132 | $mform->addElement('static', 'customclaimname_description', '', get_string('customclaimname_description', 'auth_oidc')); 133 | } 134 | 135 | // Save buttons. 136 | $this->add_action_buttons(); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /classes/form/change_binding_username_claim_tool_form1.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Change binding username claim tool form 1. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2023 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\form; 27 | 28 | use core_text; 29 | use csv_import_reader; 30 | use html_writer; 31 | use moodle_url; 32 | use moodleform; 33 | 34 | /** 35 | * Class change_binding_username_claim_tool_form1 represents the form on the change binding username claim tool page. 36 | */ 37 | class change_binding_username_claim_tool_form1 extends moodleform { 38 | /** 39 | * Form definition. 40 | * 41 | * @return void 42 | */ 43 | protected function definition() { 44 | $mform =& $this->_form; 45 | 46 | $url = new moodle_url('/auth/oidc/example.csv'); 47 | $link = html_writer::link($url, 'example.csv'); 48 | $mform->addElement('static', 'example.csv', get_string('examplecsv', 'auth_oidc'), $link); 49 | 50 | $mform->addElement('filepicker', 'usernamefile', get_string('usernamefile', 'auth_oidc')); 51 | $mform->addRule('usernamefile', null, 'required', null, 'client'); 52 | 53 | $choices = csv_import_reader::get_delimiter_list(); 54 | $mform->addElement('select', 'delimiter_name', get_string('csvdelimiter', 'auth_oidc'), $choices); 55 | if (array_key_exists('cfg', $choices)) { 56 | $mform->setDefault('delimiter_name', 'cfg'); 57 | } else if (get_string('listsep', 'langconfig') == ';') { 58 | $mform->setDefault('delimiter_name', 'semicolon'); 59 | } else { 60 | $mform->setDefault('delimiter_name', 'comma'); 61 | } 62 | 63 | $choices = core_text::get_encodings(); 64 | $mform->addElement('select', 'encoding', get_string('encoding', 'auth_oidc'), $choices); 65 | $mform->setDefault('encoding', 'UTF-8'); 66 | 67 | $choices = ['10' => 10, '20' => 20, '100' => 100, '1000' => 1000, '100000' => 100000]; 68 | $mform->addElement('select', 'previewrowsl', get_string('rowpreviewnum', 'auth_oidc'), $choices); 69 | $mform->setDefault('previewrowsl', 10); 70 | 71 | $this->add_action_buttons(false, get_string('upload_usernames', 'auth_oidc')); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /classes/form/change_binding_username_claim_tool_form2.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Change binding username claim tool form 2. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2023 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\form; 27 | 28 | use moodleform; 29 | 30 | /** 31 | * Class change_binding_username_claim_tool_form2 represents the form on the change binding username claim tool page. 32 | */ 33 | class change_binding_username_claim_tool_form2 extends moodleform { 34 | /** 35 | * Form definition. 36 | * 37 | * @return void 38 | */ 39 | public function definition() { 40 | $mform =& $this->_form; 41 | $data = $this->_customdata['data']; 42 | 43 | $mform->addElement('hidden', 'iid'); 44 | $mform->setType('iid', PARAM_INT); 45 | 46 | $mform->addElement('hidden', 'previewrows'); 47 | $mform->setType('previewrows', PARAM_INT); 48 | 49 | $this->add_action_buttons(true, get_string('upload_usernames', 'auth_oidc')); 50 | 51 | $this->set_data($data); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /classes/form/disconnect.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * OIDC disconnect form. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\form; 27 | 28 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | require_once($CFG->dirroot.'/lib/formslib.php'); 31 | 32 | /** 33 | * OIDC Disconnect Form. 34 | */ 35 | class disconnect extends \moodleform { 36 | /** 37 | * Form definition. 38 | */ 39 | protected function definition() { 40 | global $USER, $DB; 41 | 42 | if (!empty($this->_customdata['userid'])) { 43 | $userrec = $DB->get_record('user', ['id' => $this->_customdata['userid']]); 44 | } else { 45 | $userrec = $DB->get_record('user', ['id' => $USER->id]); 46 | } 47 | 48 | $authconfig = get_config('auth_oidc'); 49 | $opname = (!empty($authconfig->opname)) ? $authconfig->opname : get_string('pluginname', 'auth_oidc'); 50 | 51 | $mform =& $this->_form; 52 | $mform->addElement('html', \html_writer::tag('h4', get_string('ucp_disconnect_title', 'auth_oidc', $opname))); 53 | $mform->addElement('html', \html_writer::div(get_string('ucp_disconnect_details', 'auth_oidc', $opname))); 54 | $mform->addElement('html', '
'); 55 | $mform->addElement('hidden', 'redirect', $this->_customdata['redirect']); 56 | $mform->setType('redirect', PARAM_URL); 57 | $mform->addElement('hidden', 'donotremovetokens', $this->_customdata['donotremovetokens']); 58 | $mform->setType('donotremovetokens', PARAM_BOOL); 59 | 60 | $mform->addElement('header', 'userdetails', get_string('userdetails')); 61 | 62 | $newmethod = []; 63 | $attributes = []; 64 | $manualenabled = (is_enabled_auth('manual') === true) ? true : false; 65 | if ($manualenabled === true) { 66 | $newmethod[] =& $mform->createElement('radio', 'newmethod', '', 'manual', 'manual', $attributes); 67 | } 68 | if (!empty($this->_customdata['prevmethod'])) { 69 | $prevmethod = $this->_customdata['prevmethod']; 70 | $newmethod[] =& $mform->createElement('radio', 'newmethod', '', $prevmethod, $prevmethod, $attributes); 71 | } 72 | $mform->addGroup($newmethod, 'newmethodar', get_string('errorauthdisconnectnewmethod', 'auth_oidc'), [' '], false); 73 | if (!empty($this->_customdata['prevmethod'])) { 74 | $mform->setDefault('newmethod', $this->_customdata['prevmethod']); 75 | } else if ($manualenabled === true) { 76 | $mform->setDefault('newmethod', 'manual'); 77 | } 78 | 79 | if ($manualenabled === true) { 80 | $mform->addElement('html', \html_writer::div(get_string('errorauthdisconnectifmanual', 'auth_oidc'))); 81 | $mform->addElement('text', 'username', get_string('username')); 82 | $mform->addElement('passwordunmask', 'password', get_string('password')); 83 | $mform->setType('username', PARAM_USERNAME); 84 | $mform->disabledIf('username', 'newmethod', 'neq', 'manual'); 85 | $mform->disabledIf('password', 'newmethod', 'neq', 'manual'); 86 | 87 | // If the user cannot choose a username, set it to their current username and freeze. 88 | if (isset($this->_customdata['canchooseusername']) && $this->_customdata['canchooseusername'] == false) { 89 | $mform->setDefault('username', $userrec->username); 90 | $element = $mform->getElement('username'); 91 | $element->freeze(); 92 | } 93 | } 94 | 95 | $this->add_action_buttons(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /classes/httpclient.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * HTTP clinet. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc; 27 | 28 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | require_once($CFG->dirroot . '/lib/filelib.php'); 31 | 32 | /** 33 | * Implementation of \auth_oidc\httpclientinterface using Moodle CURL. 34 | */ 35 | class httpclient extends \curl implements \auth_oidc\httpclientinterface { 36 | /** 37 | * Generate a client tag. 38 | * 39 | * @return string A client tag. 40 | */ 41 | protected function get_clienttag_headers() { 42 | global $CFG; 43 | 44 | $iid = sha1($CFG->wwwroot); 45 | $mdlver = $this->get_moodle_version(); 46 | $ostype = php_uname('s'); 47 | $osver = php_uname('r'); 48 | $arch = php_uname('m'); 49 | $ver = $this->get_plugin_version(); 50 | 51 | $params = "lang=PHP; os={$ostype}; os_version={$osver}; arch={$arch}; version={$ver}; MoodleInstallId={$iid}"; 52 | $clienttag = "Moodle/{$mdlver} ({$params})"; 53 | return [ 54 | 'User-Agent: '.$clienttag, 55 | 'X-ClientService-ClientTag: '.$clienttag, 56 | ]; 57 | } 58 | 59 | /** 60 | * Get the current plugin version. 61 | * 62 | * @return string The current plugin version. 63 | */ 64 | protected function get_plugin_version() { 65 | global $CFG; 66 | $plugin = new \stdClass; 67 | require_once($CFG->dirroot.'/auth/oidc/version.php'); 68 | return (isset($plugin->release)) ? $plugin->release : 'unknown'; 69 | } 70 | 71 | /** 72 | * Get the current Moodle version. 73 | * 74 | * @return string The current Moodle version. 75 | */ 76 | protected function get_moodle_version() { 77 | global $CFG; 78 | return $CFG->release; 79 | } 80 | 81 | /** 82 | * Single HTTP Request 83 | * 84 | * @param string $url The URL to request 85 | * @param array $options 86 | * @return bool 87 | */ 88 | protected function request($url, $options = []) { 89 | $this->setHeader($this->get_clienttag_headers()); 90 | $result = parent::request($url, $options); 91 | $this->resetHeader(); 92 | return $result; 93 | } 94 | 95 | /** 96 | * HTTP POST method. 97 | * 98 | * @param string $url 99 | * @param array|string $params 100 | * @param array $options 101 | * @return bool 102 | */ 103 | public function post($url, $params = '', $options = []) { 104 | // Encode data to disable uploading files when values are prefixed @. 105 | if (is_array($params)) { 106 | $params = http_build_query($params, '', '&'); 107 | } 108 | return parent::post($url, $params, $options); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /classes/httpclientinterface.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * HTTP client interface. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc; 27 | 28 | /** 29 | * Interface defining an HTTP client. 30 | */ 31 | interface httpclientinterface { 32 | /** 33 | * HTTP POST method 34 | * 35 | * @param string $url 36 | * @param array|string $params 37 | * @param array $options 38 | * @return bool 39 | */ 40 | public function post($url, $params = '', $options = []); 41 | } 42 | -------------------------------------------------------------------------------- /classes/jwt.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * JWT token. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc; 27 | 28 | use moodle_exception; 29 | 30 | /** 31 | * Class for working with JWTs. 32 | */ 33 | class jwt { 34 | /** @var array Array of JWT header parameters. */ 35 | protected $header = []; 36 | 37 | /** @var array Array of JWT claims. */ 38 | protected $claims = []; 39 | 40 | /** 41 | * Decode an encoded JWT. 42 | * 43 | * @param string $encoded Encoded JWT. 44 | * @return array Array of arrays of header and body parameters. 45 | * @throws moodle_exception 46 | */ 47 | public static function decode($encoded) { 48 | if (empty($encoded) || !is_string($encoded)) { 49 | throw new moodle_exception('errorjwtempty', 'auth_oidc'); 50 | } 51 | 52 | // Separate JWT into parts. 53 | $jwtparts = explode('.', $encoded); 54 | if (count($jwtparts) !== 3) { 55 | throw new moodle_exception('errorjwtmalformed', 'auth_oidc'); 56 | } 57 | 58 | // Process header. 59 | $header = base64_decode($jwtparts[0]); 60 | if (!empty($header)) { 61 | $header = @json_decode($header, true); 62 | } 63 | if (empty($header) || !is_array($header)) { 64 | throw new moodle_exception('errorjwtcouldnotreadheader', 'auth_oidc'); 65 | } 66 | if (!isset($header['alg'])) { 67 | throw new moodle_exception('errorjwtinvalidheader', 'auth_oidc'); 68 | } 69 | 70 | // Process payload. 71 | $jwsalgs = ['HS256', 'HS384', 'HS512', 'RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'PS256', 'none']; 72 | if (in_array($header['alg'], $jwsalgs, true) === true) { 73 | $body = static::decode_jws($jwtparts[1]); 74 | } else { 75 | throw new moodle_exception('errorjwtunsupportedalg', 'auth_oidc'); 76 | } 77 | 78 | if (empty($body) || !is_array($body)) { 79 | throw new moodle_exception('errorjwtbadpayload', 'auth_oidc'); 80 | } 81 | 82 | return [$header, $body]; 83 | } 84 | 85 | /** 86 | * Decode the payload of a JWS. 87 | * 88 | * @param string $jwtpayload JWT body part. 89 | * @return array|null An array of payload claims, or null if there was a problem decoding. 90 | */ 91 | public static function decode_jws(string $jwtpayload) { 92 | $body = strtr($jwtpayload, '-_', '+/'); 93 | $body = base64_decode($body); 94 | if (!empty($body)) { 95 | $body = @json_decode($body, true); 96 | } 97 | return (!empty($body) && is_array($body)) ? $body : null; 98 | } 99 | 100 | /** 101 | * Create an instance of the class from an encoded JWT string. 102 | * 103 | * @param string $encoded The encoded JWT. 104 | * @return jwt A JWT instance. 105 | * @throws moodle_exception 106 | */ 107 | public static function instance_from_encoded($encoded) { 108 | [$header, $body] = static::decode($encoded); 109 | $jwt = new static; 110 | $jwt->set_header($header); 111 | $jwt->set_claims($body); 112 | return $jwt; 113 | } 114 | 115 | /** 116 | * Set the JWT header. 117 | * 118 | * @param array $params The header params to set. Note, this will overwrite the existing header completely. 119 | */ 120 | public function set_header(array $params) { 121 | $this->header = $params; 122 | } 123 | 124 | /** 125 | * Set claims in the object. 126 | * 127 | * @param array $params An array of claims to set. This will be appended to existing claims. Claims with the same keys will be 128 | * overwritten. 129 | */ 130 | public function set_claims(array $params) { 131 | $this->claims = array_merge($this->claims, $params); 132 | } 133 | 134 | /** 135 | * Get the value of a claim. 136 | * 137 | * @param string $claim The name of the claim to get. 138 | * @return mixed The value of the claim. 139 | */ 140 | public function claim($claim) { 141 | return (isset($this->claims[$claim])) ? $this->claims[$claim] : null; 142 | } 143 | 144 | /** 145 | * Calculate client assertion using the key provided. 146 | * 147 | * @param string $privatekey 148 | * @return string 149 | */ 150 | public function assert_token($privatekey) { 151 | $assertion = \Firebase\JWT\JWT::encode($this->claims, $privatekey, 'RS256', null, $this->header); 152 | 153 | return $assertion; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /classes/loginflow/rocreds.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Resource Owner Password Credentials Grant login flow. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\loginflow; 27 | 28 | use auth_oidc\utils; 29 | 30 | defined('MOODLE_INTERNAL') || die(); 31 | 32 | require_once($CFG->dirroot . '/auth/oidc/lib.php'); 33 | 34 | /** 35 | * Login flow for the oauth2 resource owner credentials grant. 36 | */ 37 | class rocreds extends base { 38 | /** 39 | * Check for an existing user object. 40 | * 41 | * @param string $o356username 42 | * 43 | * @return string If there is an existing user object, return the username associated with it. 44 | * If there is no existing user object, return the original username. 45 | */ 46 | protected function check_objects($o356username) { 47 | global $DB; 48 | 49 | $user = null; 50 | if (auth_oidc_is_local_365_installed()) { 51 | $sql = 'SELECT u.username 52 | FROM {local_o365_objects} obj 53 | JOIN {user} u ON u.id = obj.moodleid 54 | WHERE obj.o365name = ? and obj.type = ?'; 55 | $params = [$o356username, 'user']; 56 | $user = $DB->get_record_sql($sql, $params); 57 | } 58 | 59 | return (!empty($user)) ? $user->username : $o356username; 60 | } 61 | 62 | /** 63 | * Provides a hook into the login page. 64 | * 65 | * @param stdClass $frm Form object. 66 | * @param stdClass $user User object. 67 | * @return bool 68 | */ 69 | public function loginpage_hook(&$frm, &$user) { 70 | global $DB; 71 | 72 | if (empty($frm)) { 73 | $frm = data_submitted(); 74 | } 75 | if (empty($frm)) { 76 | return true; 77 | } 78 | 79 | $username = $frm->username; 80 | $password = $frm->password; 81 | $auth = 'oidc'; 82 | 83 | $username = $this->check_objects($username); 84 | if ($username !== $frm->username) { 85 | $success = $this->user_login($username, $password); 86 | if ($success === true) { 87 | $existinguser = $DB->get_record('user', ['username' => $username]); 88 | if (!empty($existinguser)) { 89 | $user = $existinguser; 90 | return true; 91 | } 92 | } 93 | } 94 | 95 | $autoappend = get_config('auth_oidc', 'autoappend'); 96 | if (empty($autoappend)) { 97 | // If we're not doing autoappend, just let things flow naturally. 98 | return true; 99 | } 100 | 101 | $existinguser = $DB->get_record('user', ['username' => $username]); 102 | if (!empty($existinguser)) { 103 | // We don't want to prevent access to existing accounts. 104 | return true; 105 | } 106 | 107 | $username .= $autoappend; 108 | $success = $this->user_login($username, $password); 109 | if ($success !== true) { 110 | // No o365 user, continue normally. 111 | return false; 112 | } 113 | 114 | $existinguser = $DB->get_record('user', ['username' => $username]); 115 | if (!empty($existinguser)) { 116 | $user = $existinguser; 117 | return true; 118 | } 119 | 120 | // The user is authenticated but user creation may be disabled. 121 | if (!empty($CFG->authpreventaccountcreation)) { 122 | $failurereason = AUTH_LOGIN_UNAUTHORISED; 123 | 124 | // Trigger login failed event. 125 | $event = \core\event\user_login_failed::create(['other' => ['username' => $username, 126 | 'reason' => $failurereason]]); 127 | $event->trigger(); 128 | 129 | debugging('[client '.getremoteaddr()."] $CFG->wwwroot Unknown user, can not create new accounts: $username ". 130 | $_SERVER['HTTP_USER_AGENT']); 131 | 132 | return false; 133 | } 134 | 135 | $user = create_user_record($username, $password, $auth); 136 | return true; 137 | } 138 | 139 | /** 140 | * This is the primary method that is used by the authenticate_user_login() function in moodlelib.php. 141 | * 142 | * @param string $username The username (with system magic quotes) 143 | * @param string $password The password (with system magic quotes) 144 | * @return bool Authentication success or failure. 145 | */ 146 | public function user_login($username, $password = null) { 147 | global $DB; 148 | 149 | $client = $this->get_oidcclient(); 150 | $authparams = ['code' => '']; 151 | 152 | $oidcusername = $username; 153 | $oidctoken = $DB->get_records('auth_oidc_token', ['username' => $username]); 154 | if (!empty($oidctoken)) { 155 | $oidctoken = array_shift($oidctoken); 156 | if (!empty($oidctoken) && !empty($oidctoken->oidcusername)) { 157 | $oidcusername = $oidctoken->oidcusername; 158 | } 159 | } 160 | 161 | // Make request. 162 | $tokenparams = $client->rocredsrequest($oidcusername, $password); 163 | if (!empty($tokenparams) && isset($tokenparams['token_type']) && $tokenparams['token_type'] === 'Bearer') { 164 | [$oidcuniqid, $idtoken] = $this->process_idtoken($tokenparams['id_token']); 165 | 166 | // Check restrictions. 167 | $passed = $this->checkrestrictions($idtoken); 168 | if ($passed !== true) { 169 | $errstr = 'User prevented from logging in due to restrictions.'; 170 | utils::debug($errstr, __METHOD__, $idtoken); 171 | return false; 172 | } 173 | 174 | $tokenrec = $DB->get_record('auth_oidc_token', ['oidcuniqid' => $oidcuniqid]); 175 | if (!empty($tokenrec)) { 176 | $this->updatetoken($tokenrec->id, $authparams, $tokenparams); 177 | } else { 178 | $originalupn = null; 179 | if (auth_oidc_is_local_365_installed()) { 180 | $apiclient = \local_o365\utils::get_api(); 181 | $userdetails = $apiclient->get_user($oidcuniqid); 182 | if (!is_null($userdetails) && isset($userdetails['userPrincipalName']) && 183 | stripos($userdetails['userPrincipalName'], '#EXT#') !== false) { 184 | $originalupn = $userdetails['userPrincipalName']; 185 | } 186 | } 187 | $this->createtoken($oidcuniqid, $username, $authparams, $tokenparams, $idtoken, 0, $originalupn); 188 | } 189 | return true; 190 | } 191 | return false; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /classes/observers.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Event observer handlers for auth_oidc plugin. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc; 27 | 28 | use core\event\user_deleted; 29 | use core\event\user_loggedout; 30 | 31 | defined('MOODLE_INTERNAL') || die(); 32 | 33 | require_once($CFG->dirroot.'/lib/filelib.php'); 34 | 35 | /** 36 | * Handles events. 37 | */ 38 | class observers { 39 | /** 40 | * Handle user_deleted event - clean up calendar subscriptions. 41 | * 42 | * @param user_deleted $event The triggered event. 43 | * @return bool Success/Failure. 44 | */ 45 | public static function handle_user_deleted(user_deleted $event) { 46 | global $DB; 47 | $userid = $event->objectid; 48 | $DB->delete_records('auth_oidc_token', ['userid' => $userid]); 49 | return true; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /classes/preview.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Update username feature preview table. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2023 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc; 27 | 28 | use core_text; 29 | use core_user; 30 | use csv_import_reader; 31 | use html_table; 32 | 33 | defined('MOODLE_INTERNAL') || die(); 34 | 35 | require_once($CFG->libdir . '/csvlib.class.php'); 36 | 37 | /** 38 | * Class preview represents the preview table. 39 | */ 40 | class preview extends html_table { 41 | /** @var csv_import_reader */ 42 | protected $cir; 43 | /** @var array */ 44 | protected $filecolumns; 45 | /** @var int */ 46 | protected $previewrows; 47 | /** @var bool */ 48 | protected $noerror = true; 49 | 50 | /** 51 | * Preview constructor. 52 | * 53 | * @param csv_import_reader $cir 54 | * @param array $filecolumns 55 | * @param int $previewrows 56 | */ 57 | public function __construct(csv_import_reader $cir, array $filecolumns, int $previewrows) { 58 | parent::__construct(); 59 | 60 | $this->cir = $cir; 61 | $this->filecolumns = $filecolumns; 62 | $this->previewrows = $previewrows; 63 | 64 | $this->id = 'username_update_preview'; 65 | $this->attributes['class'] = 'generaltable'; 66 | $this->tablealign = 'center'; 67 | $this->header = []; 68 | $this->data = $this->read_data(); 69 | 70 | $this->head[] = get_string('csvline', 'auth_oidc'); 71 | foreach ($filecolumns as $column) { 72 | $this->head[] = $column; 73 | } 74 | $this->head[] = get_string('status'); 75 | } 76 | 77 | /** 78 | * Read data. 79 | * 80 | * @return array 81 | */ 82 | protected function read_data(): array { 83 | global $DB; 84 | 85 | $data = []; 86 | $this->cir->init(); 87 | $linenum = 1; 88 | 89 | while ($linenum <= $this->previewrows && $fields = $this->cir->next()) { 90 | $hasfatalerror = false; 91 | $linenum++; 92 | $rowcols = []; 93 | $rowcols['line'] = $linenum; 94 | foreach ($fields as $key => $value) { 95 | $rowcols[$this->filecolumns[$key]] = s(trim($value)); 96 | } 97 | $rowcols['status'] = []; 98 | 99 | if (!isset($rowcols['username']) || !isset($rowcols['new_username'])) { 100 | $rowcols['status'][] = get_string('update_error_incomplete_line', 'auth_oidc'); 101 | $hasfatalerror = true; 102 | } 103 | 104 | $user = $DB->get_record('user', ['username' => $rowcols['username']]); 105 | if (!$user) { 106 | $user = $DB->get_record('user', ['email' => $rowcols['username']]); 107 | if ($user) { 108 | $rowcols['status'][] = get_string('update_warning_email_match', 'auth_oidc'); 109 | } else { 110 | $rowcols['status'][] = get_string('update_error_user_not_found', 'auth_oidc'); 111 | } 112 | } else if ($user->auth != 'oidc') { 113 | $rowcols['status'][] = get_string('update_error_user_not_oidc', 'auth_oidc'); 114 | } 115 | 116 | $lcnewusername = core_text::strtolower($rowcols['new_username']); 117 | if ($lcnewusername != core_user::clean_field($lcnewusername, 'username')) { 118 | $rowcols['status'][] = get_string('update_error_invalid_new_username', 'auth_oidc'); 119 | $hasfatalerror = true; 120 | } 121 | 122 | $this->noerror = !$hasfatalerror && $this->noerror; 123 | $rowcols['status'] = join('
', $rowcols['status']); 124 | $data[] = $rowcols; 125 | } 126 | 127 | if ($fields = $this->cir->next()) { 128 | $data[] = array_fill(0, count($fields) + 2, '...'); 129 | } 130 | $this->cir->close(); 131 | 132 | return $data; 133 | } 134 | 135 | /** 136 | * Get no error. 137 | * 138 | * @return bool 139 | */ 140 | public function get_no_error(): bool { 141 | return $this->noerror; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /classes/privacy/provider.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Privacy subsystem implementation. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\privacy; 27 | 28 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | use core_privacy\local\metadata\collection; 31 | use core_privacy\local\request\contextlist; 32 | use core_privacy\local\request\approved_contextlist; 33 | use core_privacy\local\request\writer; 34 | 35 | /** 36 | * Interface for handling user lists in the OIDC authentication plugin. 37 | * 38 | * @package auth_oidc 39 | */ 40 | interface auth_oidc_userlist extends \core_privacy\local\request\core_userlist_provider { 41 | }; 42 | 43 | /** 44 | * Privacy provider for auth_oidc. 45 | */ 46 | class provider implements 47 | \core_privacy\local\request\plugin\provider, 48 | \core_privacy\local\metadata\provider, 49 | auth_oidc_userlist { 50 | 51 | /** 52 | * Returns meta data about this system. 53 | * 54 | * @param collection $collection The initialised collection to add items to. 55 | * @return collection A listing of user data stored through this system. 56 | */ 57 | public static function get_metadata(collection $collection): collection { 58 | 59 | $tables = [ 60 | 'auth_oidc_prevlogin' => [ 61 | 'userid', 62 | 'method', 63 | 'password', 64 | ], 65 | 'auth_oidc_token' => [ 66 | 'oidcuniqid', 67 | 'username', 68 | 'userid', 69 | 'oidcusername', 70 | 'useridentifier', 71 | 'scope', 72 | 'tokenresource', 73 | 'authcode', 74 | 'token', 75 | 'expiry', 76 | 'refreshtoken', 77 | 'idtoken', 78 | ], 79 | ]; 80 | 81 | foreach ($tables as $table => $fields) { 82 | $fielddata = []; 83 | foreach ($fields as $field) { 84 | $fielddata[$field] = 'privacy:metadata:'.$table.':'.$field; 85 | } 86 | $collection->add_database_table( 87 | $table, 88 | $fielddata, 89 | 'privacy:metadata:'.$table 90 | ); 91 | } 92 | 93 | return $collection; 94 | } 95 | 96 | /** 97 | * Get the list of contexts that contain user information for the specified user. 98 | * 99 | * @param int $userid The user to search. 100 | * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin. 101 | */ 102 | public static function get_contexts_for_userid(int $userid): contextlist { 103 | $contextlist = new \core_privacy\local\request\contextlist(); 104 | 105 | $sql = "SELECT ctx.id 106 | FROM {auth_oidc_token} tk 107 | JOIN {context} ctx ON ctx.instanceid = tk.userid AND ctx.contextlevel = :contextlevel 108 | WHERE tk.userid = :userid"; 109 | $params = ['userid' => $userid, 'contextlevel' => CONTEXT_USER]; 110 | $contextlist->add_from_sql($sql, $params); 111 | 112 | $sql = "SELECT ctx.id 113 | FROM {auth_oidc_prevlogin} pv 114 | JOIN {context} ctx ON ctx.instanceid = pv.userid AND ctx.contextlevel = :contextlevel 115 | WHERE pv.userid = :userid"; 116 | $params = ['userid' => $userid, 'contextlevel' => CONTEXT_USER]; 117 | $contextlist->add_from_sql($sql, $params); 118 | 119 | return $contextlist; 120 | } 121 | 122 | /** 123 | * Get the list of users who have data within a context. 124 | * 125 | * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination. 126 | */ 127 | public static function get_users_in_context(\core_privacy\local\request\userlist $userlist) { 128 | $context = $userlist->get_context(); 129 | 130 | if (!$context instanceof \context_user) { 131 | return; 132 | } 133 | 134 | $params = [ 135 | 'contextuser' => CONTEXT_USER, 136 | 'contextid' => $context->id, 137 | ]; 138 | 139 | $sql = "SELECT ctx.instanceid as userid 140 | FROM {auth_oidc_prevlogin} pl 141 | JOIN {context} ctx 142 | ON ctx.instanceid = pl.userid 143 | AND ctx.contextlevel = :contextuser 144 | WHERE ctx.id = :contextid"; 145 | $userlist->add_from_sql('userid', $sql, $params); 146 | 147 | $sql = "SELECT ctx.instanceid as userid 148 | FROM {auth_oidc_token} tk 149 | JOIN {context} ctx 150 | ON ctx.instanceid = tk.userid 151 | AND ctx.contextlevel = :contextuser 152 | WHERE ctx.id = :contextid"; 153 | $userlist->add_from_sql('userid', $sql, $params); 154 | } 155 | 156 | /** 157 | * Export all user data for the specified user, in the specified contexts. 158 | * 159 | * @param approved_contextlist $contextlist The approved contexts to export information for. 160 | */ 161 | public static function export_user_data(approved_contextlist $contextlist) { 162 | global $DB; 163 | $user = $contextlist->get_user(); 164 | $context = \context_user::instance($contextlist->get_user()->id); 165 | $tables = static::get_table_user_map($user); 166 | foreach ($tables as $table => $filterparams) { 167 | $records = $DB->get_recordset($table, $filterparams); 168 | foreach ($records as $record) { 169 | writer::with_context($context)->export_data([ 170 | get_string('privacy:metadata:auth_oidc', 'auth_oidc'), 171 | get_string('privacy:metadata:'.$table, 'auth_oidc'), 172 | ], $record); 173 | } 174 | } 175 | } 176 | 177 | /** 178 | * Get a map of database tables that contain user data, and the filters to get records for a user. 179 | * 180 | * @param \stdClass $user The user to get the map for. 181 | * @return array The table user map. 182 | */ 183 | protected static function get_table_user_map(\stdClass $user): array { 184 | $tables = [ 185 | 'auth_oidc_prevlogin' => ['userid' => $user->id], 186 | 'auth_oidc_token' => ['userid' => $user->id], 187 | ]; 188 | return $tables; 189 | } 190 | 191 | /** 192 | * Delete all data for all users in the specified context. 193 | * 194 | * @param context $context The specific context to delete data for. 195 | */ 196 | public static function delete_data_for_all_users_in_context(\context $context) { 197 | if ($context->contextlevel == CONTEXT_USER) { 198 | self::delete_user_data($context->instanceid); 199 | } 200 | } 201 | 202 | /** 203 | * Delete all user data for the specified user, in the specified contexts. 204 | * 205 | * @param approved_contextlist $contextlist The approved contexts and user information to delete information for. 206 | */ 207 | public static function delete_data_for_user(approved_contextlist $contextlist) { 208 | if (empty($contextlist->count())) { 209 | return; 210 | } 211 | foreach ($contextlist->get_contexts() as $context) { 212 | if ($context->contextlevel == CONTEXT_USER) { 213 | self::delete_user_data($context->instanceid); 214 | } 215 | } 216 | } 217 | 218 | /** 219 | * This does the deletion of user data given a userid. 220 | * 221 | * @param int $userid The user ID 222 | */ 223 | private static function delete_user_data(int $userid) { 224 | global $DB; 225 | $DB->delete_records('auth_oidc_prevlogin', ['userid' => $userid]); 226 | $DB->delete_records('auth_oidc_token', ['userid' => $userid]); 227 | } 228 | 229 | /** 230 | * Delete multiple users within a single context. 231 | * 232 | * @param \core_privacy\local\request\approved_userlist $userlist The approved context and user information to delete 233 | * information for. 234 | */ 235 | public static function delete_data_for_users(\core_privacy\local\request\approved_userlist $userlist) { 236 | $context = $userlist->get_context(); 237 | // Because we only use user contexts the instance ID is the user ID. 238 | if ($context instanceof \context_user) { 239 | self::delete_user_data($context->instanceid); 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /classes/process.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Process binding username claim tool. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2023 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc; 27 | 28 | use core_text; 29 | use core_user; 30 | use csv_import_reader; 31 | use moodle_exception; 32 | use stdClass; 33 | 34 | defined('MOODLE_INTERNAL') || die(); 35 | 36 | require_once($CFG->dirroot . '/auth/oidc/lib.php'); 37 | 38 | /** 39 | * Class process represents the process binding username claim tool. 40 | */ 41 | class process { 42 | /** 43 | * Route for renaming in auth_oidc. 44 | * 45 | * @var int 46 | */ 47 | const ROUTE_AUTH_OIDC_RENAME = 1; 48 | 49 | /** 50 | * Route for matching other authentication methods. 51 | * 52 | * @var int 53 | */ 54 | const ROUTE_AUTH_OTHER_MATCH = 2; 55 | 56 | /** @var csv_import_reader */ 57 | protected $cir; 58 | /** @var array */ 59 | protected $filecolumns = null; 60 | /** @var stdClass */ 61 | protected $formdata; 62 | /** @var update_progress_tracker */ 63 | protected $upt; 64 | /** @var int */ 65 | protected $userserrors = 0; 66 | /** @var int */ 67 | protected $usersupdated = 0; 68 | 69 | /** 70 | * Process constructor. 71 | * 72 | * @param csv_import_reader $cir 73 | */ 74 | public function __construct(csv_import_reader $cir) { 75 | $this->cir = $cir; 76 | } 77 | 78 | /** 79 | * Get the file columns. 80 | * 81 | * @return array 82 | * @throws moodle_exception 83 | */ 84 | public function get_file_columns(): array { 85 | if ($this->filecolumns === null) { 86 | $columns = $this->cir->get_columns(); 87 | if (count($columns) != 2) { 88 | $this->cir->close(); 89 | $this->cir->cleanup(); 90 | throw new moodle_exception('error_invalid_upload_file', 'auth_oidc'); 91 | } 92 | 93 | $stdfields = ['username', 'new_username']; 94 | $this->filecolumns = []; 95 | 96 | foreach ($columns as $key => $unused) { 97 | $field = $columns[$key]; 98 | $field = trim($field); 99 | $lcfield = core_text::strtolower($field); 100 | if (in_array($field, $stdfields) || in_array($lcfield, $stdfields)) { 101 | $newfield = $lcfield; 102 | } 103 | if (in_array($newfield, $this->filecolumns)) { 104 | $this->cir->close(); 105 | $this->cir->cleanup(); 106 | throw new moodle_exception('duplicate_upload_field', 'auth_oidc', '', $field); 107 | } 108 | $this->filecolumns[$key] = $newfield; 109 | } 110 | } 111 | 112 | return $this->filecolumns; 113 | } 114 | 115 | /** 116 | * Set the form data. 117 | * 118 | * @param stdClass $formdata 119 | */ 120 | public function set_form_data(stdClass $formdata) { 121 | $this->formdata = $formdata; 122 | } 123 | 124 | /** 125 | * Process the CSV file. 126 | */ 127 | public function process() { 128 | // Initialise the CSV import reader. 129 | $this->cir->init(); 130 | 131 | $this->upt = new upload_process_tracker(); 132 | $this->upt->start(); 133 | 134 | $linenum = 1; // Column header is first line. 135 | while ($line = $this->cir->next()) { 136 | $this->upt->flush(); 137 | $linenum++; 138 | 139 | $this->upt->track('line', $linenum); 140 | $this->process_line($line); 141 | } 142 | 143 | $this->upt->close(); 144 | $this->cir->close(); 145 | $this->cir->cleanup(true); 146 | } 147 | 148 | /** 149 | * Process a line from the CSV file. 150 | * 151 | * @param array $line 152 | */ 153 | protected function process_line(array $line) { 154 | global $DB; 155 | 156 | $username = ''; 157 | $lcusername = ''; 158 | $newusername = ''; 159 | $lcnewusername = ''; 160 | 161 | foreach ($line as $keynum => $value) { 162 | $key = $this->get_file_columns()[$keynum]; 163 | if ($key == 'username') { 164 | $username = $value; 165 | $lcusername = core_text::strtolower($username); 166 | $this->upt->track('username', $username); 167 | } else if ($key == 'new_username') { 168 | $newusername = $value; 169 | $lcnewusername = core_text::strtolower($newusername); 170 | } 171 | } 172 | 173 | if (!$username || !$lcusername || !$newusername || !$lcnewusername) { 174 | $this->upt->track('status', get_string('update_error_incomplete_line', 'auth_oidc')); 175 | $this->userserrors++; 176 | 177 | return; 178 | } 179 | 180 | $user = core_user::get_user_by_username($lcusername); 181 | if (!$user) { 182 | $user = core_user::get_user_by_email($lcusername); 183 | $this->upt->track('status', get_string('update_warning_email_match', 'auth_oidc')); 184 | } 185 | 186 | if ($user && $user->auth == 'oidc') { 187 | $route = self::ROUTE_AUTH_OIDC_RENAME; 188 | } else { 189 | $route = self::ROUTE_AUTH_OTHER_MATCH; 190 | } 191 | 192 | if ($newusername !== core_user::clean_field($newusername, 'username')) { 193 | $this->upt->track('status', get_string('update_error_invalid_new_username', 'auth_oidc')); 194 | $this->userserrors++; 195 | 196 | return; 197 | } 198 | 199 | $this->upt->track('new_username', $newusername); 200 | 201 | // All check passed, update the user record. 202 | $userupdated = false; 203 | $authoidctokenupdated = false; 204 | $localo365objectupdated = false; 205 | 206 | // Step 1: Update the user object, if route is auth_oidc rename. 207 | if ($route == self::ROUTE_AUTH_OIDC_RENAME) { 208 | $this->upt->track('id', $user->id); 209 | 210 | $user->username = $lcnewusername; 211 | try { 212 | user_update_user($user, false); 213 | $userupdated = true; 214 | } catch (moodle_exception $e) { 215 | $this->upt->track('status', get_string('update_error_user_update_failed', 'auth_oidc')); 216 | $this->userserrors++; 217 | 218 | return; 219 | } 220 | } 221 | 222 | // Step 2: Update the token record. 223 | if ($route == self::ROUTE_AUTH_OIDC_RENAME) { 224 | if ($tokenrecord = $DB->get_record('auth_oidc_token', ['userid' => $user->id])) { 225 | $tokenrecord->username = $lcnewusername; 226 | $tokenrecord->useridentifier = $newusername; 227 | $DB->update_record('auth_oidc_token', $tokenrecord); 228 | $authoidctokenupdated = true; 229 | } 230 | } else { 231 | $sql = "SELECT * 232 | FROM {auth_oidc_token} 233 | WHERE lower(useridentifier) = ?"; 234 | if ($tokenrecord = $DB->get_record_sql($sql, [$lcusername])) { 235 | $tokenrecord->useridentifier = $newusername; 236 | $DB->update_record('auth_oidc_token', $tokenrecord); 237 | $authoidctokenupdated = true; 238 | } 239 | } 240 | 241 | // Step 3: Update connection record in local_o365_object table. 242 | if (auth_oidc_is_local_365_installed()) { 243 | if ($route == static::ROUTE_AUTH_OIDC_RENAME) { 244 | if ($connectionrecord = $DB->get_record('local_o365_objects', ['type' => 'user', 'moodleid' => $user->id])) { 245 | $connectionrecord->o365name = $newusername; 246 | $DB->update_record('local_o365_objects', $connectionrecord); 247 | $localo365objectupdated = true; 248 | } 249 | } else { 250 | $sql = "SELECT * 251 | FROM {local_o365_objects} 252 | WHERE type = 'user' 253 | AND lower(o365name) = ?"; 254 | if ($connectionrecord = $DB->get_record_sql($sql, [$lcusername])) { 255 | $connectionrecord->o365name = $newusername; 256 | $DB->update_record('local_o365_objects', $connectionrecord); 257 | $localo365objectupdated = true; 258 | } 259 | } 260 | } 261 | 262 | if ($userupdated) { 263 | $this->upt->track('status', get_string('update_success_username', 'auth_oidc')); 264 | } 265 | 266 | if ($authoidctokenupdated) { 267 | $this->upt->track('status', get_string('update_success_token', 'auth_oidc')); 268 | } 269 | 270 | if ($localo365objectupdated) { 271 | $this->upt->track('status', get_string('update_success_o365', 'auth_oidc')); 272 | } 273 | 274 | if ($userupdated || $authoidctokenupdated || $localo365objectupdated) { 275 | // At least one of the records has been updated. 276 | $this->usersupdated++; 277 | } else { 278 | $this->upt->track('status', get_string('update_error_nothing_updated', 'auth_oidc')); 279 | $this->userserrors++; 280 | } 281 | } 282 | 283 | /** 284 | * Return stats about the process. 285 | * 286 | * @return array 287 | */ 288 | public function get_stats(): array { 289 | $lines = []; 290 | 291 | $lines[] = get_string('update_stats_users_updated', 'auth_oidc', $this->usersupdated); 292 | $lines[] = get_string('update_stats_users_errors', 'auth_oidc', $this->userserrors); 293 | 294 | return $lines; 295 | } 296 | } 297 | -------------------------------------------------------------------------------- /classes/task/cleanup_oidc_sid.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * A scheduled task to clean up oidc sid records. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2021 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\task; 27 | 28 | use core\task\scheduled_task; 29 | 30 | /** 31 | * A scheduled task that cleans up OIDC SID records. 32 | */ 33 | class cleanup_oidc_sid extends scheduled_task { 34 | /** 35 | * Get a descriptive name for the task. 36 | */ 37 | public function get_name() { 38 | return get_string('task_cleanup_oidc_sid', 'auth_oidc'); 39 | } 40 | 41 | /** 42 | * Clean up OIDC SID records. 43 | */ 44 | public function execute() { 45 | global $DB; 46 | 47 | $DB->delete_records_select('auth_oidc_sid', 'timecreated < ?', [strtotime('-1 day')]); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /classes/task/cleanup_oidc_state_and_token.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * A scheduled task to clean up oidc state and invalid token. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2021 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\task; 27 | 28 | use core\task\scheduled_task; 29 | 30 | /** 31 | * A scheduled task that cleans up oidc states and tokens. 32 | */ 33 | class cleanup_oidc_state_and_token extends scheduled_task { 34 | /** 35 | * Get a descriptive name for the task. 36 | */ 37 | public function get_name() { 38 | return get_string('task_cleanup_oidc_state_and_token', 'auth_oidc'); 39 | } 40 | 41 | /** 42 | * Clean up oidc state and invalid oidc token. 43 | */ 44 | public function execute() { 45 | global $DB; 46 | 47 | // Clean up oidc state. 48 | $DB->delete_records_select('auth_oidc_state', 'timecreated < ?', [strtotime('-5 min')]); 49 | 50 | // Clean up invalid oidc token. 51 | $DB->delete_records('auth_oidc_token', ['userid' => 0]); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /classes/tests/mockhttpclient.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Mock http client used in unit test. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\tests; 27 | 28 | use moodle_exception; 29 | 30 | /** 31 | * A mock HTTP client allowing set responses. 32 | */ 33 | class mockhttpclient extends \auth_oidc\httpclient { 34 | /** @var string The stored set response. */ 35 | protected $mockresponse = ''; 36 | 37 | /** @var int The index of the current response. */ 38 | protected $curresponse = 0; 39 | 40 | /** 41 | * Set a response to return. 42 | * 43 | * @param string $response The response to return. 44 | */ 45 | public function set_response($response) { 46 | $this->set_responses([$response]); 47 | } 48 | 49 | /** 50 | * Set multiple responses. 51 | * 52 | * Responses will be returned in sequence every time $this->request is called. I.e. The first 53 | * time request() is called, the first item in the response array will be returned, the second time it's 54 | * called the second item will be returned, etc. 55 | * 56 | * @param array $responses Array of responses. 57 | */ 58 | public function set_responses(array $responses) { 59 | $this->curresponse = 0; 60 | $this->mockresponse = $responses; 61 | } 62 | 63 | /** 64 | * Return the set response instead of making the actual HTTP request. 65 | * 66 | * @param string $url The request URL 67 | * @param array $options Additional curl options. 68 | * @return string The set response. 69 | */ 70 | protected function request($url, $options = []) { 71 | if (isset($this->mockresponse[$this->curresponse])) { 72 | $response = $this->mockresponse[$this->curresponse]; 73 | $this->curresponse++; 74 | return $response; 75 | } else { 76 | $this->curresponse = 0; 77 | if (!isset($this->mockresponse[$this->curresponse])) { 78 | throw new moodle_exception('error_no_response_available', 'auth_oidc'); 79 | } 80 | return $this->mockresponse[$this->curresponse]; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /classes/tests/mockoidcclient.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Mock OIDC client used in unit test. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc\tests; 27 | 28 | /** 29 | * A mock oidcclient class providing access to all inaccessible properties/methods. 30 | */ 31 | class mockoidcclient extends \auth_oidc\oidcclient { 32 | /** @var \auth_oidc\httpclientinterface An HTTP client to use. */ 33 | public $httpclient; 34 | 35 | /** @var array Array of endpoints. */ 36 | public $endpoints = []; 37 | 38 | /** 39 | * Stub method to access protected parent method. 40 | * 41 | * @param bool $promptlogin Whether to prompt for login or use existing session. 42 | * @param array $stateparams Parameters to store as state. 43 | * @param array $extraparams Additional parameters to send with the OIDC request. 44 | * @param bool $selectaccount Whether to prompt the user to select an account. 45 | * @return array Array of request parameters. 46 | */ 47 | public function getauthrequestparams( 48 | $promptlogin = false, 49 | array $stateparams = [], 50 | array $extraparams = [], 51 | bool $selectaccount = false 52 | ) { 53 | return parent::getauthrequestparams($promptlogin, $stateparams); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /classes/upload_process_tracker.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Process binding username claim tool upload process tracker. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2023 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc; 27 | 28 | use html_writer; 29 | 30 | /** 31 | * Class to track the progress of processing username claims uploads. 32 | */ 33 | class upload_process_tracker { 34 | /** @var array */ 35 | protected $_row; 36 | /** @var array */ 37 | public $columns = []; 38 | /** @var array */ 39 | protected $headers = []; 40 | 41 | /** 42 | * upload_process_tracker constructor. 43 | */ 44 | public function __construct() { 45 | $this->headers = [ 46 | 'status' => get_string('status'), 47 | 'line' => get_string('csvline', 'auth_oidc'), 48 | 'id' => 'ID', 49 | 'username' => get_string('username'), 50 | 'new_username' => get_string('new_username', 'auth_oidc'), 51 | ]; 52 | $this->columns = array_keys($this->headers); 53 | } 54 | 55 | /** 56 | * Start the tracker. 57 | * 58 | * @return void 59 | */ 60 | public function start() { 61 | $ci = 0; 62 | echo html_writer::start_tag('table', ['class' => 'generaltable boxaligncenter flexible-wrap', 63 | 'summary' => get_string('update_username_results', 'auth_oidc')]); 64 | echo html_writer::start_tag('tr', ['class' => 'heading r0']); 65 | foreach ($this->headers as $header) { 66 | echo html_writer::tag('th', $header, ['class' => 'header c' . $ci++, 'scope' => 'col']); 67 | } 68 | echo html_writer::end_tag('tr'); 69 | $this->_row = null; 70 | } 71 | 72 | /** 73 | * Flush the tracker. 74 | * 75 | * @return void 76 | */ 77 | public function flush() { 78 | if (empty($this->_row) || empty($this->_row['line']['normal'])) { 79 | // Nothing to print - each line has to have at least number. 80 | $this->_row = []; 81 | foreach ($this->columns as $col) { 82 | $this->_row[$col] = ['normal' => '', 'info' => '', 'warning' => '', 'error' => '']; 83 | } 84 | 85 | return; 86 | } 87 | $ci = 0; 88 | $ri = 1; 89 | echo ''; 90 | foreach ($this->_row as $key => $field) { 91 | foreach ($field as $type => $content) { 92 | if ($field[$type] !== '') { 93 | $field[$type] = '' . $field[$type] . ''; 94 | } else { 95 | unset($field[$type]); 96 | } 97 | } 98 | echo ''; 99 | if (!empty($field)) { 100 | echo implode('
', $field); 101 | } else { 102 | echo ' '; 103 | } 104 | echo ''; 105 | } 106 | echo ''; 107 | foreach ($this->columns as $col) { 108 | $this->_row[$col] = ['normal' => '', 'info' => '', 'warning' => '', 'error' => '']; 109 | } 110 | } 111 | 112 | /** 113 | * Track a message. 114 | * 115 | * @param string $col 116 | * @param string $msg 117 | * @param string $level 118 | * @param bool $merge 119 | * @return void 120 | */ 121 | public function track($col, $msg, $level = 'normal', $merge = true) { 122 | if (empty($this->_row)) { 123 | $this->flush(); 124 | } 125 | if (!in_array($col, $this->columns)) { 126 | debugging('Incorrect column:' . $col); 127 | 128 | return; 129 | } 130 | if ($merge) { 131 | if ($this->_row[$col][$level] != '') { 132 | $this->_row[$col][$level] .= '
'; 133 | } 134 | $this->_row[$col][$level] .= $msg; 135 | } else { 136 | $this->_row[$col][$level] = $msg; 137 | } 138 | } 139 | 140 | /** 141 | * Close the tracker. 142 | * 143 | * @return void 144 | */ 145 | public function close() { 146 | $this->flush(); 147 | echo html_writer::end_tag('table'); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /classes/utils.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Utility functions. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc; 27 | 28 | use Exception; 29 | use moodle_exception; 30 | use auth_oidc\event\action_failed; 31 | use moodle_url; 32 | 33 | /** 34 | * General purpose utility class. 35 | */ 36 | class utils { 37 | /** 38 | * Process an OIDC JSON response. 39 | * 40 | * @param string $response The received JSON. 41 | * @param array $expectedstructure 42 | * @return array The parsed JSON. 43 | * @throws moodle_exception 44 | */ 45 | public static function process_json_response($response, array $expectedstructure = []) { 46 | $result = @json_decode($response, true); 47 | if (empty($result) || !is_array($result)) { 48 | self::debug('Bad response received', __METHOD__, $response); 49 | throw new moodle_exception('erroroidccall', 'auth_oidc'); 50 | } 51 | 52 | if (isset($result['error'])) { 53 | $errmsg = 'Error response received.'; 54 | self::debug($errmsg, __METHOD__, $result); 55 | if (isset($result['error_description'])) { 56 | $isadminconsent = optional_param('admin_consent', false, PARAM_BOOL); 57 | if ($isadminconsent) { 58 | if (get_config('auth_oidc', 'idptype') == AUTH_OIDC_IDP_TYPE_MICROSOFT_IDENTITY_PLATFORM && 59 | auth_oidc_is_local_365_installed() && 60 | $result['error'] === 'invalid_grant' && 61 | isset($result['error_codes']) && count($result['error_codes']) == 1 && 62 | $result['error_codes'][0] == 53003) { 63 | $localo365configurationpageurl = new moodle_url('/admin/settings.php', ['section' => 'local_o365']); 64 | throw new moodle_exception('settings_adminconsent_error_53003', 'local_o365', 65 | $localo365configurationpageurl, '', $result['error_description']); 66 | } 67 | } 68 | throw new moodle_exception('erroroidccall_message', 'auth_oidc', '', $result['error_description']); 69 | } else { 70 | throw new moodle_exception('erroroidccall', 'auth_oidc'); 71 | } 72 | } 73 | 74 | foreach ($expectedstructure as $key => $val) { 75 | if (!isset($result[$key])) { 76 | $errmsg = 'Invalid structure received. No "'.$key.'"'; 77 | self::debug($errmsg, __METHOD__, $result); 78 | throw new moodle_exception('erroroidccall', 'auth_oidc'); 79 | } 80 | 81 | if ($val !== null && $result[$key] !== $val) { 82 | $strreceivedval = self::tostring($result[$key]); 83 | $strval = self::tostring($val); 84 | $errmsg = 'Invalid structure received. Invalid "'.$key.'". Received "'.$strreceivedval.'", expected "'.$strval.'"'; 85 | self::debug($errmsg, __METHOD__, $result); 86 | throw new moodle_exception('erroroidccall', 'auth_oidc'); 87 | } 88 | } 89 | return $result; 90 | } 91 | 92 | /** 93 | * Convert any value into a debuggable string. 94 | * 95 | * @param mixed $val The variable to convert. 96 | * @return string A string representation. 97 | */ 98 | public static function tostring($val) { 99 | if (is_scalar($val)) { 100 | if (is_bool($val)) { 101 | return '(bool)'.(string)(int)$val; 102 | } else { 103 | return '('.gettype($val).')'.(string)$val; 104 | } 105 | } else if (is_null($val)) { 106 | return '(null)'; 107 | } else if ($val instanceof Exception) { 108 | $valinfo = [ 109 | 'file' => $val->getFile(), 110 | 'line' => $val->getLine(), 111 | 'message' => $val->getMessage(), 112 | ]; 113 | if ($val instanceof moodle_exception) { 114 | $valinfo['debuginfo'] = $val->debuginfo; 115 | $valinfo['errorcode'] = $val->errorcode; 116 | $valinfo['module'] = $val->module; 117 | } 118 | return json_encode($valinfo, JSON_PRETTY_PRINT); 119 | } else { 120 | return json_encode($val, JSON_PRETTY_PRINT); 121 | } 122 | } 123 | 124 | /** 125 | * Record a debug message. 126 | * 127 | * @param string $message The debug message to log. 128 | * @param string $where 129 | * @param null $debugdata 130 | */ 131 | public static function debug($message, $where = '', $debugdata = null) { 132 | $debugmode = (bool)get_config('auth_oidc', 'debugmode'); 133 | if ($debugmode === true) { 134 | $debugbacktrace = debug_backtrace(); 135 | $debugbacktracechecksum = md5(json_encode($debugbacktrace)); 136 | 137 | $otherdata = static::make_json_safe([ 138 | 'other' => [ 139 | 'message' => $message, 140 | 'where' => $where, 141 | 'debugdata' => $debugdata, 142 | 'backtrace_checksum' => $debugbacktracechecksum, 143 | ], 144 | ]); 145 | $event = action_failed::create($otherdata); 146 | $event->trigger(); 147 | 148 | $debugbacktracedata = [ 149 | 'checksum' => $debugbacktracechecksum, 150 | 'backtrace' => $debugbacktrace, 151 | ]; 152 | 153 | debugging(json_encode($debugbacktracedata), DEBUG_DEVELOPER); 154 | } 155 | } 156 | 157 | /** 158 | * Make a JSON structure safe for logging. 159 | * 160 | * @param mixed $data The data to make safe. 161 | * @return mixed The safe data. 162 | */ 163 | private static function make_json_safe($data) { 164 | if (is_array($data)) { 165 | foreach ($data as $key => $value) { 166 | $data[$key] = static::make_json_safe($value); 167 | } 168 | } else if (is_object($data)) { 169 | $data = (array)$data; 170 | foreach ($data as $key => $value) { 171 | $data[$key] = static::make_json_safe($value); 172 | } 173 | } else if (is_bool($data)) { 174 | $data = (int)$data; 175 | } else if (is_null($data)) { 176 | $data = null; 177 | } else if (!is_scalar($data)) { 178 | $data = (string)$data; 179 | } 180 | return $data; 181 | } 182 | 183 | /** 184 | * Get the redirect URL that should be set in the identity provider 185 | * 186 | * @return string The redirect URL. 187 | */ 188 | public static function get_redirecturl() { 189 | $redirecturl = new moodle_url('/auth/oidc/'); 190 | return $redirecturl->out(false); 191 | } 192 | 193 | /** 194 | * Get the front channel logout URL that should be set in the identity provider. 195 | * 196 | * @return string The redirect URL. 197 | */ 198 | public static function get_frontchannellogouturl() { 199 | $logouturl = new moodle_url('/auth/oidc/logout.php'); 200 | return $logouturl->out(false); 201 | } 202 | 203 | /** 204 | * Get and check existence of OIDC client certificate path. 205 | * 206 | * @return string|bool cert path if exists otherwise false 207 | */ 208 | public static function get_certpath() { 209 | $clientcertfile = get_config('auth_oidc', 'clientcertfile'); 210 | $certlocation = self::get_openssl_internal_path(); 211 | $certfile = "$certlocation/$clientcertfile"; 212 | 213 | if (is_file($certfile) && is_readable($certfile)) { 214 | return "file://$certfile"; 215 | } 216 | 217 | return false; 218 | } 219 | 220 | /** 221 | * Get and check existence of OIDC client key path. 222 | * 223 | * @return string|bool key path if exists otherwise false 224 | */ 225 | public static function get_keypath() { 226 | $clientprivatekeyfile = get_config('auth_oidc', 'clientprivatekeyfile'); 227 | $keylocation = self::get_openssl_internal_path(); 228 | $keyfile = "$keylocation/$clientprivatekeyfile"; 229 | 230 | if (is_file($keyfile) && is_readable($keyfile)) { 231 | return "file://$keyfile"; 232 | } 233 | 234 | return false; 235 | } 236 | 237 | /** 238 | * Get openssl cert base path, which is dataroot/microsoft_certs. 239 | * 240 | * @return string base path to put cert files 241 | */ 242 | public static function get_openssl_internal_path() { 243 | global $CFG; 244 | 245 | return $CFG->dataroot . '/microsoft_certs'; 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /cleanupoidctokens.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Admin page to cleanup oidc tokens. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | require_once(__DIR__ . '/../../config.php'); 27 | require_once($CFG->libdir . '/adminlib.php'); 28 | require_once($CFG->dirroot . '/auth/oidc/lib.php'); 29 | 30 | require_login(); 31 | 32 | $context = context_system::instance(); 33 | $pageurl = new moodle_url('/auth/oidc/cleanupoidctokens.php'); 34 | 35 | admin_externalpage_setup('auth_oidc_cleanup_oidc_tokens'); 36 | 37 | require_admin(); 38 | 39 | $PAGE->set_url($pageurl); 40 | $PAGE->set_context($context); 41 | $PAGE->set_pagelayout('admin'); 42 | $PAGE->set_heading(get_string('cleanup_oidc_tokens', 'auth_oidc')); 43 | $PAGE->set_title(get_string('cleanup_oidc_tokens', 'auth_oidc')); 44 | 45 | $emptyuseridtokens = auth_oidc_get_tokens_with_empty_ids(); 46 | $mismatchedtokens = auth_oidc_get_tokens_with_mismatched_usernames(); 47 | 48 | $tokenstoclean = $emptyuseridtokens + $mismatchedtokens; 49 | 50 | uasort($tokenstoclean, function($a, $b) { 51 | return strcmp($a->oidcusername, $b->oidcusername); 52 | }); 53 | 54 | $deletetokenid = optional_param('id', 0, PARAM_INT); 55 | if ($deletetokenid) { 56 | if (array_key_exists($deletetokenid, $tokenstoclean)) { 57 | auth_oidc_delete_token($deletetokenid); 58 | 59 | redirect($pageurl, get_string('token_deleted', 'auth_oidc')); 60 | } 61 | } 62 | 63 | if ($tokenstoclean) { 64 | $table = new html_table(); 65 | $table->head = [ 66 | get_string('table_token_id', 'auth_oidc'), 67 | get_string('table_oidc_username', 'auth_oidc'), 68 | get_string('table_oidc_unique_identifier', 'auth_oidc'), 69 | get_string('table_token_unique_id', 'auth_oidc'), 70 | get_string('table_matching_status', 'auth_oidc'), 71 | get_string('table_matching_details', 'auth_oidc'), 72 | get_string('table_action', 'auth_oidc'), 73 | ]; 74 | $table->colclasses = [ 75 | 'leftalign', 76 | 'leftalign', 77 | 'leftalign', 78 | 'leftalign', 79 | 'leftalign', 80 | 'leftalign', 81 | 'centeralign', 82 | ]; 83 | $table->attributes['class'] = 'admintable generaltable'; 84 | $table->id = 'cleanupoidctokens'; 85 | $table->data = []; 86 | foreach ($tokenstoclean as $item) { 87 | $table->data[] = [ 88 | $item->id, 89 | $item->oidcusername, 90 | $item->useridentifier, 91 | $item->oidcuniqueid, 92 | $item->matchingstatus, 93 | $item->details, 94 | $item->action, 95 | ]; 96 | } 97 | } 98 | 99 | echo $OUTPUT->header(); 100 | 101 | if ($tokenstoclean) { 102 | echo html_writer::table($table); 103 | } else { 104 | echo html_writer::span(get_string('no_token_to_cleanup', 'auth_oidc')); 105 | } 106 | 107 | echo $OUTPUT->footer(); 108 | -------------------------------------------------------------------------------- /db/access.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Plugin capabilities. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | global $CFG; 29 | 30 | $capabilities = [ 31 | 'auth/oidc:manageconnection' => [ 32 | 'riskbitmask' => RISK_CONFIG, 33 | 'captype' => 'write', 34 | 'contextlevel' => CONTEXT_USER, 35 | 'archetypes' => [], 36 | ], 37 | 'auth/oidc:manageconnectionconnect' => [ 38 | 'riskbitmask' => RISK_CONFIG, 39 | 'captype' => 'write', 40 | 'contextlevel' => CONTEXT_USER, 41 | 'archetypes' => [], 42 | ], 43 | 'auth/oidc:manageconnectiondisconnect' => [ 44 | 'riskbitmask' => RISK_CONFIG, 45 | 'captype' => 'write', 46 | 'contextlevel' => CONTEXT_USER, 47 | 'archetypes' => [], 48 | ], 49 | ]; 50 | -------------------------------------------------------------------------------- /db/events.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Event observers. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | $observers = [ 29 | [ 30 | 'eventname' => '\core\event\user_deleted', 31 | 'callback' => '\auth_oidc\observers::handle_user_deleted', 32 | 'priority' => 200, 33 | 'internal' => false, 34 | ], 35 | ]; 36 | -------------------------------------------------------------------------------- /db/install.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Plugin installation script. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | /** 27 | * Installation script. 28 | */ 29 | function xmldb_auth_oidc_install() { 30 | // Set the default value for the bindingusernameclaim setting. 31 | $bindingusernameclaimconfig = get_config('auth_oidc', 'bindingusernameclaim'); 32 | if (empty($bindingusernameclaimconfig)) { 33 | set_config('bindingusernameclaim', 'auto', 'auth_oidc'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /db/install.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
74 |
75 |
76 | -------------------------------------------------------------------------------- /db/tasks.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Plugin tasks. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2021 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | $tasks = [ 29 | [ 30 | 'classname' => 'auth_oidc\task\cleanup_oidc_state_and_token', 31 | 'blocking' => 0, 32 | 'minute' => '*', 33 | 'hour' => '*', 34 | 'day' => '*', 35 | 'dayofweek' => '*', 36 | 'month' => '*', 37 | ], 38 | [ 39 | 'classname' => 'auth_oidc\task\cleanup_oidc_sid', 40 | 'blocking' => 0, 41 | 'minute' => '51', 42 | 'hour' => '*', 43 | 'day' => '*', 44 | 'dayofweek' => '*', 45 | 'month' => '*', 46 | ], 47 | ]; 48 | -------------------------------------------------------------------------------- /example.csv: -------------------------------------------------------------------------------- 1 | username,new_username 2 | old_username@domain_A.com,725741c1-f2f2-4db4-9fcf-1a1363e58e4b -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Authentication landing page. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | // phpcs:ignore moodle.Files.RequireLogin.Missing 27 | require_once(__DIR__.'/../../config.php'); 28 | require_once(__DIR__.'/auth.php'); 29 | 30 | $auth = new \auth_plugin_oidc('authcode'); 31 | $auth->set_httpclient(new \auth_oidc\httpclient()); 32 | $auth->handleredirect(); 33 | -------------------------------------------------------------------------------- /js/module.js: -------------------------------------------------------------------------------- 1 | /*global $, M, sessionStorage*/ 2 | 3 | M.auth_oidc = {}; 4 | 5 | M.auth_oidc.init = function(Y, idptype_ms, authmethodsecret, authmethodcertificate, authmethodcertificatetext) { 6 | var $idptype = $("#id_idptype"); 7 | var $clientauthmethod = $("#id_clientauthmethod"); 8 | var $clientsecret = $("#id_clientsecret"); 9 | var $clientcert = $("#id_clientcert"); 10 | var $clientprivatekey = $("#id_clientprivatekey"); 11 | var $clientprivatekeyfile = $("#id_clientprivatekeyfile"); 12 | var $clientcertfile = $("#id_clientcertfile"); 13 | var $clientcertpassphrase = $("#id_clientcertpassphrase"); 14 | var $clientcertsource = $("#id_clientcertsource"); 15 | var $secretexpiryrecipients = $("#id_secretexpiryrecipients"); 16 | 17 | $idptype.change(function() { 18 | if ($(this).val() != idptype_ms) { 19 | $("#id_clientauthmethod option[value='" + authmethodcertificate + "']").each(function() { 20 | $(this).remove(); 21 | }); 22 | $clientauthmethod.val(authmethodsecret); 23 | $clientsecret.prop('disabled', false); 24 | $clientcertsource.prop('disabled', true); 25 | $clientcert.prop('disabled', true); 26 | $clientprivatekey.prop('disabled', true); 27 | $clientprivatekeyfile.prop('disabled', true); 28 | $clientcertfile.prop('disabled', true); 29 | $clientcertpassphrase.prop('disabled', true); 30 | $secretexpiryrecipients.prop('disabled', false); 31 | } else { 32 | $clientauthmethod.append(""); 33 | } 34 | }); 35 | 36 | $clientauthmethod.change(function() { 37 | if ($(this).val() == authmethodcertificate) { 38 | if ($clientcertsource.val() == 'file') { 39 | $clientcert.prop('disabled', true); 40 | $clientprivatekey.prop('disabled', true); 41 | $clientprivatekeyfile.prop('disabled', false); 42 | $clientcertfile.prop('disabled', false); 43 | } else { 44 | $clientcert.prop('disabled', false); 45 | $clientprivatekey.prop('disabled', false); 46 | $clientprivatekeyfile.prop('disabled', true); 47 | $clientcertfile.prop('disabled', true); 48 | } 49 | $clientcertpassphrase.prop('disabled', false); 50 | $clientcertsource.prop('disabled', false); 51 | } else { 52 | $secretexpiryrecipients.prop('disabled', false); 53 | } 54 | }); 55 | }; 56 | -------------------------------------------------------------------------------- /lang/cs/auth_oidc.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Czech language strings. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @author Lai Wei 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 25 | */ 26 | 27 | // phpcs:disable moodle.Files.LangFilesOrdering.IncorrectOrder 28 | // phpcs:disable moodle.Files.LangFilesOrdering.UnexpectedComment 29 | 30 | $string['pluginname'] = 'OpenID Connect'; 31 | $string['auth_oidcdescription'] = 'Plugin OpenID Connect poskytuje funkci jednotného přihlašování pomocí konfigurovatelných poskytovatelů identity.'; 32 | $string['cfg_authendpoint_key'] = 'Koncový bod autorizace'; 33 | $string['cfg_authendpoint_desc'] = 'Identifikátor URI koncového bodu autorizace od vašeho poskytovatele identity, který se má použít.'; 34 | $string['cfg_autoappend_key'] = 'Automaticky připojit'; 35 | $string['cfg_autoappend_desc'] = 'Automaticky připojit tento řetězec při přihlašování uživatelů pomocí postupu přihlášení uživatelské_jméno/heslo. To je užitečné, když váš poskytovatel identity požaduje společnou doménu, ale po uživatelích nechcete požadovat její psaní při přihlašování. Pokud například uživatel OpenID Connect má celé uživatelské jméno „jankovar@example.com“ a zde zadáte „@example.com“, bude uživatel jako své uživatelské jméno zadávat jen „jankovar“.
Poznámka: V případě, že existují konfliktní uživatelská jména – například že existuje uživatel v Moodlu se stejným uživatelským jménem, k určení „vítězného“ uživatele se použije priorita pluginu ověření.'; 36 | $string['cfg_clientid_key'] = 'ID klienta'; 37 | $string['cfg_clientid_desc'] = 'Vaše registrované ID klienta u poskytovatele identity.'; 38 | $string['cfg_clientsecret_key'] = 'Tajný klíč klienta'; 39 | $string['cfg_clientsecret_desc'] = 'Váš registrovaný tajný klíč klienta u poskytovatele identity. U některých poskytovatelů označovaný jen jako klíč.'; 40 | $string['cfg_err_invalidauthendpoint'] = 'Neplatný koncový bod autorizace'; 41 | $string['cfg_err_invalidtokenendpoint'] = 'Neplatný koncový bod tokenu'; 42 | $string['cfg_err_invalidclientid'] = 'Neplatné ID klienta'; 43 | $string['cfg_err_invalidclientsecret'] = 'Neplatný tajný klíč klienta'; 44 | $string['cfg_icon_key'] = 'Ikona'; 45 | $string['cfg_icon_desc'] = 'Ikona, která se bude zobrazovat na přihlašovací stránce vedle názvu poskytovatele.'; 46 | $string['cfg_iconalt_o365'] = 'Ikona Microsoft 365'; 47 | $string['cfg_iconalt_locked'] = 'Ikona uzamčení'; 48 | $string['cfg_iconalt_lock'] = 'Ikona zámku'; 49 | $string['cfg_iconalt_go'] = 'Zelené kolečko'; 50 | $string['cfg_iconalt_stop'] = 'Červené kolečko'; 51 | $string['cfg_iconalt_user'] = 'Ikona uživatele'; 52 | $string['cfg_iconalt_user2'] = 'Alternativa ikony uživatele'; 53 | $string['cfg_iconalt_key'] = 'Ikona klíče'; 54 | $string['cfg_iconalt_group'] = 'Ikona skupiny'; 55 | $string['cfg_iconalt_group2'] = 'Alternativa ikony skupiny'; 56 | $string['cfg_iconalt_mnet'] = 'Ikona MNET'; 57 | $string['cfg_iconalt_userlock'] = 'Ikona uživatele se zámkem'; 58 | $string['cfg_iconalt_plus'] = 'Ikona plus'; 59 | $string['cfg_iconalt_check'] = 'Ikona zaškrtnutí'; 60 | $string['cfg_iconalt_rightarrow'] = 'Ikona šipky doprava'; 61 | $string['cfg_customicon_key'] = 'Vlastní ikona'; 62 | $string['cfg_customicon_desc'] = 'Pokud chcete použít vlastní ikonu, nahrajte ji zde. To přepíše jakékoli ikony vybrané výše.

Poznámky k používání vlastních ikon:
  • Velikost tohoto obrázku se na přihlašovací stránce nepřizpůsobí, proto doporučujeme nenahrávat obrázky větší než 35x35 pixelů.
  • Pokud jste nahráli vlastní ikonu a chtěli byste se vrátit k některé ze základních dodaných ikon, klikněte nahoře na vlastní ikonu, pak klikněte na tlačítko Odstranit, potvrďte kliknutím na OK a potom klikněte dole ve formuláři na tlačítko Uložit změny. Na přihlašovací stránce Moodlu se objeví vybraná základní ikona.
'; 63 | $string['cfg_debugmode_key'] = 'Zaznamenávat zprávy ladění'; 64 | $string['cfg_debugmode_desc'] = 'Pokud je toto nastavení povoleno, do protokolu Moodlu jsou zaznamenávány informace, které vám mohou pomoci identifikovat problémy.'; 65 | $string['cfg_loginflow_key'] = 'Postup přihlášení'; 66 | $string['cfg_loginflow_authcode'] = 'Požadavek na autorizaci'; 67 | $string['cfg_loginflow_authcode_desc'] = 'Při použití tohoto postupu uživatel na přihlašovací stránce Moodlu klikne na ikonu poskytovatele identity (viz výše „Název poskytovatele“) a je následně přesměrován na poskytovatele, aby se přihlásil. Po úspěšném přihlášení je uživatel přesměrován zpět do Moodlu, kde proběhne transparentní přihlášení do Moodlu. Toto je nejstandardizovanější bezpečný způsob přihlašování uživatelů.'; 68 | $string['cfg_loginflow_rocreds'] = 'Ověřování uživatelské_jméno/heslo'; 69 | $string['cfg_loginflow_rocreds_desc'] = 'Při použití tohoto postupu uživatel zadá své uživatelské jméno a heslo do přihlašovacího formuláře Moodlu, obdobně jako při ručním přihlášení. Jeho přihlašovací údaje jsou pak na pozadí předány poskytovateli identity, aby bylo získáno ověření. Tento postup je pro uživatele nejtransparentnější, protože nemá žádný přímý kontakt s poskytovatelem identity. Ne všichni poskytovatelé identity ale tento postup podporují.'; 70 | $string['cfg_oidcresource_key'] = 'Zdroj'; 71 | $string['cfg_oidcresource_desc'] = 'Zdroj OpenID Connect, pro který se odesílá požadavek.'; 72 | $string['cfg_oidcscope_key'] = 'Scope'; 73 | $string['cfg_oidcscope_desc'] = 'Rozsah OIDC, který se má použít.'; 74 | $string['cfg_opname_key'] = 'Název poskytovatele'; 75 | $string['cfg_opname_desc'] = 'Toto je údaj zobrazovaný koncovému uživateli, který identifikuje, jaký typ přihlašovacích údajů potřebuje uživatel použít k přihlášení. Tento údaj se používá na více místech rozhraní pro koncového uživatele v tomto pluginu k identifikaci vašeho poskytovatele.'; 76 | $string['cfg_redirecturi_key'] = 'URI pro přesměrování'; 77 | $string['cfg_redirecturi_desc'] = 'Toto je identifikátor URI, který se registruje jako „URI pro přesměrování“. Váš poskytovatel identity OpenID Connect by vás měl o tento identifikátor požádat při registraci Moodlu jako klienta.
Poznámka: Tento identifikátor musíte ve svém poskytovateli identity OpenID Connect zadat *přesně* tak, jak je zde uveden. Jakákoli odchylka znemožní přihlášení s použitím OpenID Connect.'; 78 | $string['cfg_tokenendpoint_key'] = 'Koncový bod tokenu'; 79 | $string['cfg_tokenendpoint_desc'] = 'URI koncového bodu tokenu od vašeho poskytovatele identity, který se má použít.'; 80 | $string['event_debug'] = 'Zpráva ladění'; 81 | $string['errorauthdisconnectemptypassword'] = 'Heslo nemůže být prázdné.'; 82 | $string['errorauthdisconnectemptyusername'] = 'Uživatelské jméno nemůže být prázdné.'; 83 | $string['errorauthdisconnectusernameexists'] = 'Toto uživatelské jméno se již používá. Zvolte jiné.'; 84 | $string['errorauthdisconnectnewmethod'] = 'Použít metodu přihlášení'; 85 | $string['errorauthdisconnectinvalidmethod'] = 'Přijata neplatná metoda přihlášení.'; 86 | $string['errorauthdisconnectifmanual'] = 'Pokud používáte metodu ručního přihlášení, zadejte níže přihlašovací údaje.'; 87 | $string['errorauthinvalididtoken'] = 'Přijato neplatné id_token.'; 88 | $string['errorauthloginfailednouser'] = 'Neplatné přihlášení: Uživatel nebyl v Moodlu nalezen.'; 89 | $string['errorauthnoauthcode'] = 'Nebyl přijat kód ověření.'; 90 | $string['errorauthnocreds'] = 'Nakonfigurujte přihlašovací údaje klienta OpenID Connect.'; 91 | $string['errorauthnoendpoints'] = 'Nakonfigurujte koncové body serveru OpenID Connect.'; 92 | $string['errorauthnohttpclient'] = 'Nastavte klienta HTTP.'; 93 | $string['errorauthnoidtoken'] = 'Nebylo přijato id_token OpenID Connect.'; 94 | $string['errorauthunknownstate'] = 'Neznámý stav.'; 95 | $string['errorauthuseralreadyconnected'] = 'Jste již připojeni k jinému uživateli OpenID Connect.'; 96 | $string['errorauthuserconnectedtodifferent'] = 'Uživatel OpenID Connect, který byl ověřen, je již připojen k uživateli Moodle.'; 97 | $string['errorbadloginflow'] = 'Byl zadán neplatný postup přihlášení. Poznámka: Pokud se vám tato zpráva zobrazuje poté, co jste provedli instalaci nebo upgrade, vymažte mezipaměť Moodlu.'; 98 | $string['errorjwtbadpayload'] = 'Nejde přečíst datovou část JWT.'; 99 | $string['errorjwtcouldnotreadheader'] = 'Nelze číst hlavičku JWT.'; 100 | $string['errorjwtempty'] = 'Přijato prázdné nebo ne-řetězec JWT.'; 101 | $string['errorjwtinvalidheader'] = 'Neplatná hlavička JWT'; 102 | $string['errorjwtmalformed'] = 'Přijato poškozené JWT.'; 103 | $string['errorjwtunsupportedalg'] = 'JWS Alg nebo JWE není podporováno'; 104 | $string['erroroidcnotenabled'] = 'Plugin ověření OpenID Connect není povolen.'; 105 | $string['errornodisconnectionauthmethod'] = 'Nelze se odpojit, protože není povolen žádný plugin ověření, který by mohl převzít funkci. (buď uživatelova předchozí metoda přihlášení, nebo metoda ručního přihlášení).'; 106 | $string['erroroidcclientinvalidendpoint'] = 'Přijato neplatné URI koncového bodu.'; 107 | $string['erroroidcclientnocreds'] = 'Nastavte přihlašovací údaje klienta s tajnými klíči.'; 108 | $string['erroroidcclientnoauthendpoint'] = 'Není nastaven žádný koncový bod autorizace. Nastavte pomocí $this->setendpoints'; 109 | $string['erroroidcclientnotokenendpoint'] = 'Není nastaven žádný koncový bod tokenu. Nastavte pomocí $this->setendpoints'; 110 | $string['erroroidcclientinsecuretokenendpoint'] = 'Koncový bod tokenu musí pro toto používat SSL/TLS.'; 111 | $string['errorucpinvalidaction'] = 'Přijata neplatná akce.'; 112 | $string['erroroidccall'] = 'Chyba v OpenID Connect. Další informace naleznete v protokolech.'; 113 | $string['erroroidccall_message'] = 'Chyba v OpenID Connect: {$a}'; 114 | $string['eventuserauthed'] = 'Uživatel autorizován s OpenID Connect'; 115 | $string['eventusercreated'] = 'Uživatel vytvořen s OpenID Connect'; 116 | $string['eventuserconnected'] = 'Uživatel připojen k OpenID Connect'; 117 | $string['eventuserloggedin'] = 'Uživatel přihlášen s OpenID Connect'; 118 | $string['eventuserdisconnected'] = 'Uživatel odpojen od OpenID Connect'; 119 | $string['oidc:manageconnection'] = 'Spravovat připojení OpenID Connect'; 120 | $string['ucp_general_intro'] = 'Zde můžete spravovat své připojení k {$a}. Pokud je nastavení povoleno, budete moci použít svůj účet {$a} k přihlášení do Moodlu namísto používání samostatného uživatelského jména a hesla. Jakmile se připojíte, nebudete si muset nadále pamatovat svoje uživatelské jméno a heslo pro Moodle, veškerá přihlášení budou probíhat přes {$a}.'; 121 | $string['ucp_login_start'] = 'Začít používat {$a} k přihlašování do Moodlu'; 122 | $string['ucp_login_start_desc'] = 'Toto přepne váš účet, aby k přihlašování do Moodlu používal {$a}. Jakmile nastavení povolíte, budete se přihlašovat se svými přihlašovacími údaji {$a} – vaše aktuální uživatelské jméno a heslo pro Moodle nebudou fungovat. Kdykoli můžete svůj účet odpojit a vrátit se k normálnímu přihlašování.'; 123 | $string['ucp_login_stop'] = 'Přestat používat {$a} k přihlašování do Moodlu'; 124 | $string['ucp_login_stop_desc'] = 'Aktuálně k přihlašování do Moodlu používáte {$a}. Když kliknete na „Přestat používat {$a} k přihlašování do Moodlu“, váš účet Moodle se odpojí od {$a}. Nebudete se nadále moci přihlašovat do Moodlu pomocí účtu {$a}. Bude požádáni, abyste si vytvořili uživatelské jméno a heslo, a od té chvíle se pak budete moci do Moodlu přihlašovat přímo.'; 125 | $string['ucp_login_status'] = 'Přihlašování {$a} je:'; 126 | $string['ucp_status_enabled'] = 'Povoleno'; 127 | $string['ucp_status_disabled'] = 'Zakázáno'; 128 | $string['ucp_disconnect_title'] = 'Odpojení {$a}'; 129 | $string['ucp_disconnect_details'] = 'Váš účet Moodle bude odpojen od {$a}. Budete si muset vytvořit uživatelské jméno a heslo pro přihlašování do Moodlu.'; 130 | $string['ucp_title'] = 'Správa {$a}'; 131 | 132 | // phpcs:enable moodle.Files.LangFilesOrdering.IncorrectOrder 133 | // phpcs:enable moodle.Files.LangFilesOrdering.UnexpectedComment -------------------------------------------------------------------------------- /lang/fi/auth_oidc.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Finnish language strings. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @author Lai Wei 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 25 | */ 26 | 27 | // phpcs:disable moodle.Files.LangFilesOrdering.IncorrectOrder 28 | // phpcs:disable moodle.Files.LangFilesOrdering.UnexpectedComment 29 | 30 | $string['pluginname'] = 'OpenID Connect'; 31 | $string['auth_oidcdescription'] = 'OpenID Connect -lisäosa mahdollistaa kertakirjautumisen käyttämällä määritettävissä olevaa identiteetintarjoajaa.'; 32 | $string['cfg_authendpoint_key'] = 'Todennuksen päätepiste'; 33 | $string['cfg_authendpoint_desc'] = 'Käytettävän identiteetintarjoajan todennuksen päätepisteen URI.'; 34 | $string['cfg_autoappend_key'] = 'Lisää automaattisesti'; 35 | $string['cfg_autoappend_desc'] = 'Lisää tämän merkkijonon automaattisesti, kun käyttäjät käyttävät kirjautumiseen käyttäjänimi/salasana-kulkua. Tästä on hyötyä, kun identiteetintarjoaja edellyttää yhtenäistä toimialuetta, mutta et halua, että käyttäjien on kirjoitettava toimialue jokaisen kirjautumisen yhteydessä. Jos käyttäjän täydellinen OpenID Connect -käyttäjätunnus on esimerkiksi james@example.com ja kirjoitat tähän kenttään @example.com, käyttäjän tarvitsee antaa käyttäjänimeksi vain james.
Huomautus: Jos käyttäjänimissä on ristiriitoja, esimerkiksi järjestelmässä on samanniminen Moodle-käyttäjä, prioriteettijärjestys määräytyy todennuslisäosan mukaan.'; 36 | $string['cfg_clientid_key'] = 'Asiakastunnus'; 37 | $string['cfg_clientid_desc'] = 'Identiteetintarjoajan palveluun rekisteröity asiakastunnus.'; 38 | $string['cfg_clientsecret_key'] = 'Asiakassalaisuus'; 39 | $string['cfg_clientsecret_desc'] = 'Identiteetintarjoajan palveluun rekisteröity asiakassalaisuus. Joidenkin palveluntarjoajien palveluissa tätä kutsutaan avaimeksi.'; 40 | $string['cfg_err_invalidauthendpoint'] = 'Virheellinen todennuksen päätepiste'; 41 | $string['cfg_err_invalidtokenendpoint'] = 'Virheellinen avaimen päätepiste'; 42 | $string['cfg_err_invalidclientid'] = 'Virheellinen asiakastunnus'; 43 | $string['cfg_err_invalidclientsecret'] = 'Virheellinen asiakassalaisuus'; 44 | $string['cfg_icon_key'] = 'Kuvake'; 45 | $string['cfg_icon_desc'] = 'Kirjautumissivulla palveluntarjoajan nimen vieressä näkyvä kuvake.'; 46 | $string['cfg_iconalt_o365'] = 'Microsoft 365 -kuvake'; 47 | $string['cfg_iconalt_locked'] = 'Lukittu-kuvake'; 48 | $string['cfg_iconalt_lock'] = 'Lukkokuvake'; 49 | $string['cfg_iconalt_go'] = 'Vihreä ympyrä'; 50 | $string['cfg_iconalt_stop'] = 'Punainen ympyrä'; 51 | $string['cfg_iconalt_user'] = 'Käyttäjäkuvake'; 52 | $string['cfg_iconalt_user2'] = 'Vaihtoehtoinen käyttäjäkuvake'; 53 | $string['cfg_iconalt_key'] = 'Avainkuvake'; 54 | $string['cfg_iconalt_group'] = 'Ryhmäkuvake'; 55 | $string['cfg_iconalt_group2'] = 'Vaihtoehtoinen ryhmäkuvake'; 56 | $string['cfg_iconalt_mnet'] = 'MNET-kuvake'; 57 | $string['cfg_iconalt_userlock'] = 'Käyttäjä ja lukko -kuvake'; 58 | $string['cfg_iconalt_plus'] = 'Pluskuvake'; 59 | $string['cfg_iconalt_check'] = 'Valintamerkki-kuvake'; 60 | $string['cfg_iconalt_rightarrow'] = 'Oikealle osoittava nuolikuvake'; 61 | $string['cfg_customicon_key'] = 'Mukautettu kuvake'; 62 | $string['cfg_customicon_desc'] = 'Jos haluat käyttää mukautettua kuvaketta, lataa se tähän. Ladattu kuvake korvaa valittuna olevan kuvakkeen.

Mukautettujen kuvakkeiden käytössä huomioitavaa:
  • Kuvan kokoa ei muuteta kirjautumissivulla, joten suosittelemme lataamaan kuvan, jonka koko on enintään 35 x 35 pikseliä.
  • Jos olet ladannut mukautetun kuvan, mutta haluat palata käyttämään vakiokuvaketta, napsauta mukautetun kuvakkeen ruutua yllä ja valitse Poista ja sitten OK. Valitse lopuksi Tallenna muutokset tämän lomakkeen alaosassa. Valittu vakiokuvake näytetään tämän jälkeen Moodlen kirjautumissivulla.
'; 63 | $string['cfg_debugmode_key'] = 'Kirjaa virheenkorjausviestit'; 64 | $string['cfg_debugmode_desc'] = 'Jos asetus on käytössä, tiedot kirjataan Moodlen lokiin ongelmien tunnistamista varten.'; 65 | $string['cfg_loginflow_key'] = 'Kirjautumiskulku'; 66 | $string['cfg_loginflow_authcode'] = 'Valtuutuspyyntö'; 67 | $string['cfg_loginflow_authcode_desc'] = 'Jos tämä kirjautumiskulku on käytössä, käyttäjä napsauttaa identiteetintarjoajan nimeä (ks. Palveluntarjoajan nimi) Moodlen kirjautumissivulla, jonka jälkeen käyttäjä ohjataan palveluntarjoajan sivulle kirjautumista varten. Jos kirjautuminen onnistuu, käyttäjä ohjataan takaisin Moodleen, jossa Moodle-kirjautuminen tapahtuu läpinäkyvästi. Tämä on standardisoitu ja turvallisin käyttäjien kirjautumismenetelmä.'; 68 | $string['cfg_loginflow_rocreds'] = 'Käyttäjänimen/salasanan todennus'; 69 | $string['cfg_loginflow_rocreds_desc'] = 'Jos tämä kirjautumiskulku on käytössä, käyttäjä kirjautuu Moodleen antamalla käyttäjänimen ja salasanan Moodlen kirjautumislomakkeeseen. Tunnistetiedot välitetään taustalla identiteetintarjoajalle todennusta varten. Tämä kulku on läpinäkyvin käyttäjän kannalta, koska käyttäjä ei ole suoraan tekemisissä identiteetintarjoajan kanssa. Huomaa, että kaikki identiteetintarjoajat eivät tue tätä kulkua.'; 70 | $string['cfg_oidcresource_key'] = 'Resurssi'; 71 | $string['cfg_oidcresource_desc'] = 'OpenID Connect -resurssi, jota lähetettävä pyyntö koskee.'; 72 | $string['cfg_oidcscope_key'] = 'laajuus'; 73 | $string['cfg_oidcscope_desc'] = 'Käytettävä OIDC-soveltamisala.'; 74 | $string['cfg_opname_key'] = 'Palveluntarjoajan nimi'; 75 | $string['cfg_opname_desc'] = 'Tämä on loppukäyttäjälle näkyvä selite, joka ilmoittaa kirjautumiseen käytettävien tunnistetietojen tyypin. Tätä palveluntarjoajan selitettä käytetään tämän lisäosan kaikissa käyttäjälle näkyvissä osioissa.'; 76 | $string['cfg_redirecturi_key'] = 'Uudelleenohjauksen URI'; 77 | $string['cfg_redirecturi_desc'] = 'Tämä on rekisteröitävä uudelleenohjauksen URI. OpenID Connect -identiteetintarjoaja pyytää tätä tietoa, kun rekisteröit Moodlen asiakkaaksi.
HUOMAUTUS: Anna URI OpenID Connect -palveluntarjoajan palveluun *täsmälleen* tässä näkyvässä muodossa. Muussa tapauksessa kirjautuminen OpenID Connect -palvelun avulla ei onnistu.'; 78 | $string['cfg_tokenendpoint_key'] = 'Avaimen päätepiste'; 79 | $string['cfg_tokenendpoint_desc'] = 'Käytettävän identiteetintarjoajan avaimen päätepiste.'; 80 | $string['event_debug'] = 'Virheenkorjausviesti'; 81 | $string['errorauthdisconnectemptypassword'] = 'Salasana ei voi olla tyhjä'; 82 | $string['errorauthdisconnectemptyusername'] = 'Käyttäjänimi ei voi olla tyhjä'; 83 | $string['errorauthdisconnectusernameexists'] = 'Annettu käyttäjänimi on jo käytössä. Valitse toinen nimi.'; 84 | $string['errorauthdisconnectnewmethod'] = 'Käyttäjän kirjautumismenetelmä'; 85 | $string['errorauthdisconnectinvalidmethod'] = 'Virheellinen kirjautumismenetelmä vastaanotettiin.'; 86 | $string['errorauthdisconnectifmanual'] = 'Jos käytät manuaalista kirjautumismenetelmää, anna tunnistetiedot alla.'; 87 | $string['errorauthinvalididtoken'] = 'Virheellinen id_token vastaanotettiin.'; 88 | $string['errorauthloginfailednouser'] = 'Kirjautumisvirhe: käyttäjää ei löydy Moodlesta.'; 89 | $string['errorauthnoauthcode'] = 'Todennuskoodia ei vastaanotettu.'; 90 | $string['errorauthnocreds'] = 'Määritä OpenID Connect -asiakkaan tunnistetiedot.'; 91 | $string['errorauthnoendpoints'] = 'Määritä OpenID Connect -palvelimen päätepisteet.'; 92 | $string['errorauthnohttpclient'] = 'Määritä HTTP-asiakas.'; 93 | $string['errorauthnoidtoken'] = 'OpenID Connectin id_token-avainta ei vastaanotettu.'; 94 | $string['errorauthunknownstate'] = 'Tuntematon tila.'; 95 | $string['errorauthuseralreadyconnected'] = 'Yhteys on jo muodostettu toiseen OpenID Connect -käyttäjään.'; 96 | $string['errorauthuserconnectedtodifferent'] = 'Todennettu OpenID Connect -käyttäjä on jo yhdistetty Moodle-käyttäjään.'; 97 | $string['errorbadloginflow'] = 'Määritetty kirjautumiskulku on virheellinen. Huomautus: Jos saat tämän viestin asennuksen tai päivityksen jälkeen, tyhjennä Moodlen välimuisti.'; 98 | $string['errorjwtbadpayload'] = 'JWT-tietoja ei voitu lukea.'; 99 | $string['errorjwtcouldnotreadheader'] = 'JWT-otsikkoa ei voitu lukea'; 100 | $string['errorjwtempty'] = 'Vastaanotettu JWT on tyhjä, tai se ei ole kelvollinen merkkijono.'; 101 | $string['errorjwtinvalidheader'] = 'Virheellinen JWT-otsikko'; 102 | $string['errorjwtmalformed'] = 'Vastaanotettu JWT on virheellinen.'; 103 | $string['errorjwtunsupportedalg'] = 'JWS Alg tai JWE ei ole tuettu'; 104 | $string['erroroidcnotenabled'] = 'OpenID Connect -todennuslisäosa ei ole käytössä.'; 105 | $string['errornodisconnectionauthmethod'] = 'Yhteyttä ei voi katkaista, koska vaihtoehtoista todennuslisäosaa ei ole määritetty (se voi olla käyttäjän edellinen kirjautumismenetelmä tai manuaalinen kirjautumismenetelmä).'; 106 | $string['erroroidcclientinvalidendpoint'] = 'Virheellinen pääpisteen URI vastaanotettiin.'; 107 | $string['erroroidcclientnocreds'] = 'Määritä asiakkaan tunnistetiedot setcreds-komennolla'; 108 | $string['erroroidcclientnoauthendpoint'] = 'Todennuksen päätepistettä ei ole määritetty. Määritä komennolla $this->setendpoints'; 109 | $string['erroroidcclientnotokenendpoint'] = 'Avaimen päätepistettä ei ole määritetty. Määritä komennolla $this->setendpoints'; 110 | $string['erroroidcclientinsecuretokenendpoint'] = 'Avaimen päätepisteen on käytettävä tähän SSL/TLS-yhteyttä.'; 111 | $string['errorucpinvalidaction'] = 'Virheellinen toiminto vastaanotettiin.'; 112 | $string['erroroidccall'] = 'OpenID Connect -palvelussa tapahtui virhe. Lisätietoja on lokeissa.'; 113 | $string['erroroidccall_message'] = 'Virhe OpenID Connect -palvelussa: {$a}'; 114 | $string['eventuserauthed'] = 'Käyttäjä valtuutettiin OpenID Connectin avulla'; 115 | $string['eventusercreated'] = 'Käyttäjä luotiin OpenID Connectin avulla'; 116 | $string['eventuserconnected'] = 'Käyttäjä yhdistettiin OpenID Connectin avulla'; 117 | $string['eventuserloggedin'] = 'Käyttäjä kirjautui OpenID Connectin avulla'; 118 | $string['eventuserdisconnected'] = 'Käyttäjän OpenID Connect -yhteys katkaistiin'; 119 | $string['oidc:manageconnection'] = 'OpenID Connect -yhteyden hallinta'; 120 | $string['ucp_general_intro'] = 'Tässä kohdassa voit hallita {$a} -yhteyttä. Jos asetus on käytössä, voit kirjautua Moodleen käyttämällä {$a} -tiliäsi erillisen käyttäjänimen ja salasanan sijaan. Kun yhteys on luotu, sinun ei tarvitse muistaa Moodle-käyttäjänimeä ja -salasanaa, koska {$a} huolehtii kirjautumisesta.'; 121 | $string['ucp_login_start'] = 'Aloita palvelun {$a} käyttö Moodle-kirjautumiseen'; 122 | $string['ucp_login_start_desc'] = 'Voit käyttää {$a} -tiliäsi Moodle-kirjautumiseen. Kun asetus on käytössä, kirjaudut Moodleen käyttämällä {$a} -tunnistetietojasi. Nykyinen Moodle-käyttäjänimi ja -salasana eivät enää toimi. Voit katkaista tilisi yhteyden milloin tahansa ja palata käyttämään normaalia kirjautumista.'; 123 | $string['ucp_login_stop'] = 'Lopeta palvelun {$a} käyttö Moodle-kirjautumiseen'; 124 | $string['ucp_login_stop_desc'] = '{$a} on tällä hetkellä käytössä Moodle-kirjautumiseen. Jos valitset Lopeta palvelun {$a} käyttö -asetuksen, Moodle-tilin yhteys palveluun {$a} katkaistaan. Tämän jälkeen et voi kirjautua Moodleen käyttämällä {$a} -tiliäsi. Sinua pyydetään luomaan käyttäjänimi ja salasana, joiden avulla voit kirjautua suoraan Moodleen.'; 125 | $string['ucp_login_status'] = '{$a} -kirjautuminen:'; 126 | $string['ucp_status_enabled'] = 'Käytössä'; 127 | $string['ucp_status_disabled'] = 'Ei käytössä'; 128 | $string['ucp_disconnect_title'] = '{$a} -yhteyden katkaisu'; 129 | $string['ucp_disconnect_details'] = 'Tämä katkaisee Moodle-tilin yhteyden kohteesta {$a}. Tarvitset käyttäjänimen ja salasanan, jotta voit kirjautua Moodleen.'; 130 | $string['ucp_title'] = '{$a} -hallinta'; 131 | 132 | // phpcs:enable moodle.Files.LangFilesOrdering.IncorrectOrder 133 | // phpcs:enable moodle.Files.LangFilesOrdering.UnexpectedComment -------------------------------------------------------------------------------- /lang/it/auth_oidc.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Italian language strings. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @author Lai Wei 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 25 | */ 26 | 27 | // phpcs:disable moodle.Files.LangFilesOrdering.IncorrectOrder 28 | // phpcs:disable moodle.Files.LangFilesOrdering.UnexpectedComment 29 | 30 | $string['pluginname'] = 'OpenID Connect'; 31 | $string['auth_oidcdescription'] = 'Il plugin OpenID Connect fornisce funzionalità single-sign-on utilizzando Identity Provider configurabili.'; 32 | $string['cfg_authendpoint_key'] = 'Endpoint di autorizzazione'; 33 | $string['cfg_authendpoint_desc'] = 'L\'URI dell\'endpoint di autorizzazione dall\'Identity Provider da utilizzare.'; 34 | $string['cfg_autoappend_key'] = 'Aggiungi automaticamente'; 35 | $string['cfg_autoappend_desc'] = 'Aggiunge automaticamente questa stringa durante il login di utenti utilizzando il flusso di login Nome utente/Password. È utile quando l\'Identity Provider richiede un dominio comune senza però richiederne l\'inserimento durante il login. Ad esempio, se l\'utente OpenID Connect completo è "james@example.com" e si inserisce "@example.com", l\'utente deve inserire solo "james" come nome utente.
Nota: in caso di conflitto tra nomi utente, ovvero quando esiste un utente Moodle con lo stesso nome, la priorità del plugin di autenticazione è utilizzata per determinare quale utente ha la meglio.'; 36 | $string['cfg_clientid_key'] = 'ID cliente'; 37 | $string['cfg_clientid_desc'] = 'Il tuo ID cliente registrato sull\'Identity Provider.'; 38 | $string['cfg_clientsecret_key'] = 'Segreto cliente'; 39 | $string['cfg_clientsecret_desc'] = 'Il tuo segreto cliente registrato sull\'Identity Provider. Su alcuni provider, viene anche indicato come chiave.'; 40 | $string['cfg_err_invalidauthendpoint'] = 'Endpoint di autorizzazione non valido'; 41 | $string['cfg_err_invalidtokenendpoint'] = 'Endpoint token non valido'; 42 | $string['cfg_err_invalidclientid'] = 'ID cliente non valido'; 43 | $string['cfg_err_invalidclientsecret'] = 'Segreto cliente non valido'; 44 | $string['cfg_icon_key'] = 'Icona'; 45 | $string['cfg_icon_desc'] = 'Un\'icona visualizzata accanto al nome del provider sulla pagina di login.'; 46 | $string['cfg_iconalt_o365'] = 'Icona Microsoft 365'; 47 | $string['cfg_iconalt_locked'] = 'Icona Bloccato'; 48 | $string['cfg_iconalt_lock'] = 'Icona blocca'; 49 | $string['cfg_iconalt_go'] = 'Cerchio verde'; 50 | $string['cfg_iconalt_stop'] = 'Cerchio rosso'; 51 | $string['cfg_iconalt_user'] = 'Icona utente'; 52 | $string['cfg_iconalt_user2'] = 'Icona utente alternativa'; 53 | $string['cfg_iconalt_key'] = 'Icona chiave'; 54 | $string['cfg_iconalt_group'] = 'Icona gruppo'; 55 | $string['cfg_iconalt_group2'] = 'Icona gruppo alternativa'; 56 | $string['cfg_iconalt_mnet'] = 'Icona MNET'; 57 | $string['cfg_iconalt_userlock'] = 'Utente con icona blocco'; 58 | $string['cfg_iconalt_plus'] = 'Icona più'; 59 | $string['cfg_iconalt_check'] = 'Icona segno di spunta'; 60 | $string['cfg_iconalt_rightarrow'] = 'Icona freccia verso destra'; 61 | $string['cfg_customicon_key'] = 'Icona personalizzato'; 62 | $string['cfg_customicon_desc'] = 'Se desideri utilizzare la tua icona, caricala qui. Questa ha la precedenza su qualsiasi icona scelta in precedenza.

Note sull\'utilizzo di icone personalizzate:
  • Questa immagine non verrà ridimensionata sulla pagina di login, pertanto si consiglia di caricare un\'immagine di dimensioni inferiori a 35x35 pixel.
  • Se hai caricato un\'icona personalizzata e desideri tornare a una delle icone di origine, fai clic sull\'icona personalizzata nella casella precedente, scegli "Elimina", fai clic su "OK", quindi su "Salva modifiche" nella parte inferiore di questo modulo. L\'icona di origine selezionata verrà visualizzata nella pagina di login di Moodle.
'; 63 | $string['cfg_debugmode_key'] = 'Registra messaggi di debug'; 64 | $string['cfg_debugmode_desc'] = 'Abilitando questa opzione, le informazioni verranno registrate nel log di Moodle per risolvere problemi di identificazione.'; 65 | $string['cfg_loginflow_key'] = 'Flusso di login'; 66 | $string['cfg_loginflow_authcode'] = 'Richiesta di autorizzazione'; 67 | $string['cfg_loginflow_authcode_desc'] = 'Utilizzando questo flusso, l\'utente fa clic sul nome dell\'Identity Provider (vedere "Nome provider" in precedenza) nella pagina login di Moodle e viene reindirizzato al provider per il login. Dopo il login, l\'utente viene nuovamente reindirizzato in Moodle dove il login a Moodle viene eseguito in maniera trasparente. Questo è il metodo di login più standardizzato e sicuro.'; 68 | $string['cfg_loginflow_rocreds'] = 'Autenticazione nome utente/password'; 69 | $string['cfg_loginflow_rocreds_desc'] = 'Utilizzando questo flusso, l\'utente inserisce il nome utente e la password nel modulo di login di Moodle seguendo la stessa procedura del login manuale. Le credenziali vengono quindi passate all\'Identity Provider in background per ottenere l\'autenticazione. Questo flusso è quello più trasparente per l\'utente in quanto non esiste interazione diretta con l\'Identity Provider. Osservare che non tutti gli Identity Provider supportano questo flusso.'; 70 | $string['cfg_oidcresource_key'] = 'Risorsa'; 71 | $string['cfg_oidcresource_desc'] = 'La risorsa OpenID Connect per la quale inviare la richiesta.'; 72 | $string['cfg_oidcscope_key'] = 'Scopo'; 73 | $string['cfg_oidcscope_desc'] = 'L\'ambito OIDC da utilizzare.'; 74 | $string['cfg_opname_key'] = 'Nome del provider'; 75 | $string['cfg_opname_desc'] = 'Si tratta di un\'etichetta presentata all\'utente finale che identifica il tipo di credenziali che l\'utente deve utilizzare per eseguire il login. Questa etichetta viene utilizzata in tutta la parte rivolta all\'utente del plugin per identificare il provider.'; 76 | $string['cfg_redirecturi_key'] = 'URI di reindirizzamento'; 77 | $string['cfg_redirecturi_desc'] = 'Si tratta dell\'URI da registrare come "URI di reindirizzamento". L\'Identity Provider di OpenID Connect deve richiedere questa informazione durante la registrazione come client.
NOTA: devi immettere questa informazione nell\'apposito campo *esattamente* come appare qui. Qualsiasi differenza non consentirà di accedere con OpenID Connect.'; 78 | $string['cfg_tokenendpoint_key'] = 'Endpoint token'; 79 | $string['cfg_tokenendpoint_desc'] = 'L\'URI dell\'endpoint token dall\'Identity Provider.'; 80 | $string['event_debug'] = 'Messaggio di debug'; 81 | $string['errorauthdisconnectemptypassword'] = 'La password non può essere vuota'; 82 | $string['errorauthdisconnectemptyusername'] = 'Il nome utente non può essere vuoto'; 83 | $string['errorauthdisconnectusernameexists'] = 'Questo nome utente è già impegnato. Sceglierne uno diverso.'; 84 | $string['errorauthdisconnectnewmethod'] = 'Utilizza metodo di login'; 85 | $string['errorauthdisconnectinvalidmethod'] = 'Ricevuto metodo di login non valido.'; 86 | $string['errorauthdisconnectifmanual'] = 'Se si utilizza il metodo di login manuale, immettere le credenziali sottostanti.'; 87 | $string['errorauthinvalididtoken'] = 'id_token non valido ricevuto.'; 88 | $string['errorauthloginfailednouser'] = 'Login non valido: utente non trovato in Moodle.'; 89 | $string['errorauthnoauthcode'] = 'Codice di autenticazione non ricevuto.'; 90 | $string['errorauthnocreds'] = 'Configurare le credenziali cliente OpenID Connect.'; 91 | $string['errorauthnoendpoints'] = 'Configurare gli endpoint server OpenID Connect.'; 92 | $string['errorauthnohttpclient'] = 'Impostare un client HTTP.'; 93 | $string['errorauthnoidtoken'] = 'OpenID Connect id_token non ricevuto.'; 94 | $string['errorauthunknownstate'] = 'Stato sconosciuto.'; 95 | $string['errorauthuseralreadyconnected'] = 'Sei già connesso a un utente OpenID Connect diverso.'; 96 | $string['errorauthuserconnectedtodifferent'] = 'L\'utente OpenID Connect autenticato è già connesso a un utente Moodle.'; 97 | $string['errorbadloginflow'] = 'Specificato flusso di login non valido. Nota: se stai ricevendo questo messaggio dopo un\'installazione o aggiornamento recente, cancella la cache Moodle.'; 98 | $string['errorjwtbadpayload'] = 'Impossibile leggere payload JWT.'; 99 | $string['errorjwtcouldnotreadheader'] = 'Impossibile leggere intestazione JWT'; 100 | $string['errorjwtempty'] = 'Ricevuto JWT vuoto o di tipo non stringa.'; 101 | $string['errorjwtinvalidheader'] = 'Intestazione JWT non valida'; 102 | $string['errorjwtmalformed'] = 'Ricevuto JWT danneggiato.'; 103 | $string['errorjwtunsupportedalg'] = 'JWS Alg o JWE non supportato'; 104 | $string['erroroidcnotenabled'] = 'Il plugin di autenticazione OpenID Connect non è abilitato.'; 105 | $string['errornodisconnectionauthmethod'] = 'Impossibile disconnettersi perché non esiste un plugin di autenticazione abilitato verso cui eseguire il fallback (metodo di accesso precedente dell\'utente o metodo di accesso manuale).'; 106 | $string['erroroidcclientinvalidendpoint'] = 'Ricevuto URI endpoint non valido.'; 107 | $string['erroroidcclientnocreds'] = 'Impostare credenziali cliente con segreti'; 108 | $string['erroroidcclientnoauthendpoint'] = 'Nessun endpoint di autorizzazione impostato. Impostarlo con $this->setendpoints'; 109 | $string['erroroidcclientnotokenendpoint'] = 'Nessun endpoint token impostato. Impostare con $this->setendpoints'; 110 | $string['erroroidcclientinsecuretokenendpoint'] = 'L\'endpoint token deve utilizzare SSL/TLS.'; 111 | $string['errorucpinvalidaction'] = 'Ricevuta azione non valida.'; 112 | $string['erroroidccall'] = 'Si è verificato un errore in OpenID Connect. Consultare i log per ulteriori informazioni.'; 113 | $string['erroroidccall_message'] = 'Si è verificato un errore in OpenID Connect: {$a}'; 114 | $string['eventuserauthed'] = 'Utente autorizzato con OpenID Connect'; 115 | $string['eventusercreated'] = 'Utente creato con OpenID Connect'; 116 | $string['eventuserconnected'] = 'Utente connesso a OpenID Connect'; 117 | $string['eventuserloggedin'] = 'Utente autenticato con OpenID Connect'; 118 | $string['eventuserdisconnected'] = 'Utente disconnesso da OpenID Connect'; 119 | $string['oidc:manageconnection'] = 'Gestisci connessione OpenID Connect'; 120 | $string['ucp_general_intro'] = 'Qui puoi gestire la connessione a {$a}. Abilitando questa opzione, sarai in grado di utilizzare il tuo account {$a} per accedere a Moodle anziché un nome utente e una password separati. Dopo la connessione, non dovrai più ricordare il nome utente e la password per Moodle, tutti i login verranno gestiti da {$a}.'; 121 | $string['ucp_login_start'] = 'Inizia a utilizzare {$a} per accedere a Moodle'; 122 | $string['ucp_login_start_desc'] = 'Il tuo account verrà cambiato per utilizzare {$a} per accedere a Moodle. Dopo che è stato abilitato, l\'accesso verrà eseguito utilizzando le tue credenziali {$a} - il nome utente e la password Moodle correnti non funzioneranno. In qualsiasi momento puoi disconnetterti dal tuo account e tornare a eseguire il login normalmente.'; 123 | $string['ucp_login_stop'] = 'Non utilizzare più {$a} per accedere a Moodle'; 124 | $string['ucp_login_stop_desc'] = 'Stai attualmente utilizzando {$a} per accedere a Moodle. Facendo clic su "Non utilizzare più il login {$a}", l\'account Moodle verrà disconnesso da {$a}. Non potrai più accedere a Moodle con il tuo account {$a}. Ti verrà chiesto di creare un nome utente e una password con cui potrai accedere a Moodle direttamente.'; 125 | $string['ucp_login_status'] = 'Login {$a} è:'; 126 | $string['ucp_status_enabled'] = 'Abilitato'; 127 | $string['ucp_status_disabled'] = 'Disabilitato'; 128 | $string['ucp_disconnect_title'] = 'Disconnessione {$a}'; 129 | $string['ucp_disconnect_details'] = 'Il tuo account Moodle verrà disconnesso da {$a}. Per accedere a Moodle dovrai creare un nome utente e una password.'; 130 | $string['ucp_title'] = 'Gestione {$a}'; 131 | 132 | // phpcs:enable moodle.Files.LangFilesOrdering.IncorrectOrder 133 | // phpcs:enable moodle.Files.LangFilesOrdering.UnexpectedComment -------------------------------------------------------------------------------- /lang/ja/auth_oidc.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Japanese language strings. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @author Lai Wei 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 25 | */ 26 | 27 | // phpcs:disable moodle.Files.LangFilesOrdering.IncorrectOrder 28 | // phpcs:disable moodle.Files.LangFilesOrdering.UnexpectedComment 29 | 30 | $string['pluginname'] = 'OpenID Connect'; 31 | $string['auth_oidcdescription'] = 'OpenID Connectプラグインは、設定可能なアイデンティティプロバイダを使用してシングルサインオン機能を提供します。'; 32 | $string['cfg_authendpoint_key'] = '認証エンドポイント'; 33 | $string['cfg_authendpoint_desc'] = 'アイデンティティプロバイダが使用する認証エンドポイントのURIです。'; 34 | $string['cfg_autoappend_key'] = '自動付加'; 35 | $string['cfg_autoappend_desc'] = 'ユーザがユーザ名/パスワードのログインフローを使用してログインした場合、自動的にこの文字列を付加します。これは、アイデンティティプロバイダが共通のドメインを求めているのものの、ユーザにログイン時に入力してほしくない場合に便利です。たとえば、完全なOpenID Connectユーザが"james@example.com"である場合、ここに"@example.com"と入力しておくと、ユーザはユーザ名として"james"を入力するだけで済みます。
注 : ユーザ名が競合する場合、つまり同じ名前のMoodleユーザが存在する場合、認証プラグインの優先順位を使用してユーザが決定されます。'; 36 | $string['cfg_clientid_key'] = 'クライアントID'; 37 | $string['cfg_clientid_desc'] = 'アイデンティティプロバイダに登録したクライアントID。'; 38 | $string['cfg_clientsecret_key'] = 'クライアント秘密鍵'; 39 | $string['cfg_clientsecret_desc'] = 'アイデンティティプロバイダに登録したクライアント秘密鍵です。プロバイダによっては、キーと呼ばれることもあります。'; 40 | $string['cfg_err_invalidauthendpoint'] = '無効な認証エンドポイント'; 41 | $string['cfg_err_invalidtokenendpoint'] = '無効なトークンエンドポイント'; 42 | $string['cfg_err_invalidclientid'] = '無効なクライアントID'; 43 | $string['cfg_err_invalidclientsecret'] = '無効なクライアント秘密鍵'; 44 | $string['cfg_icon_key'] = 'アイコン'; 45 | $string['cfg_icon_desc'] = 'ログインページでプロバイダ名の横に表示されるアイコンです。'; 46 | $string['cfg_iconalt_o365'] = 'Microsoft 365アイコン'; 47 | $string['cfg_iconalt_locked'] = 'ロック済みアイコン'; 48 | $string['cfg_iconalt_lock'] = 'ロックアイコン'; 49 | $string['cfg_iconalt_go'] = '緑の丸'; 50 | $string['cfg_iconalt_stop'] = '赤の丸'; 51 | $string['cfg_iconalt_user'] = 'ユーザアイコン'; 52 | $string['cfg_iconalt_user2'] = '別のユーザアイコン'; 53 | $string['cfg_iconalt_key'] = 'キーアイコン'; 54 | $string['cfg_iconalt_group'] = 'グループアイコン'; 55 | $string['cfg_iconalt_group2'] = '別のグループアイコン'; 56 | $string['cfg_iconalt_mnet'] = 'MNETアイコン'; 57 | $string['cfg_iconalt_userlock'] = 'ロック付きユーザアイコン'; 58 | $string['cfg_iconalt_plus'] = 'プラスアイコン'; 59 | $string['cfg_iconalt_check'] = 'チェックマークアイコン'; 60 | $string['cfg_iconalt_rightarrow'] = '右向き矢印アイコン'; 61 | $string['cfg_customicon_key'] = 'カスタムアイコン'; 62 | $string['cfg_customicon_desc'] = '独自のアイコンを使用する場合は、ここにアップロードします。これにより、上記で選択していたアイコンは上書きされます。

カスタムアイコンを使用する際の注意 :
  • この画像はログインページではサイズ変更されません。このため、35x35ピクセル以下の画像をアップロードすることをお勧めします。
  • カスタムアイコンをアップロードした後で標準のアイコンに戻す場合は、上のボックスのカスタムアイコンをクリックします。次に[削除]、[OK]をクリックし、最後にフォームの下部にある[変更の保存]をクリックします。これにより、選択された標準アイコンがMoodleログインページに表示されます。
'; 63 | $string['cfg_debugmode_key'] = 'デバッグメッセージを記録する'; 64 | $string['cfg_debugmode_desc'] = '有効にすると、Moodleログに情報が記録されます。これは問題を特定するのに役立つことがあります。'; 65 | $string['cfg_loginflow_key'] = 'ログインフロー'; 66 | $string['cfg_loginflow_authcode'] = '認証リクエスト'; 67 | $string['cfg_loginflow_authcode_desc'] = 'このフローでは、ユーザはMoodleログインページでアイデンティティプロバイダの名前 (上記の「プロバイダ名」を参照) をクリックします。ユーザはプロバイダにリダイレクトされ、そこでログインします。ログインが成功したら、ユーザはMoodleにリダイレクトされ、透過的にMoodleログインが行われます。これは最も標準化され、最もセキュアなユーザのログイン方法です。'; 68 | $string['cfg_loginflow_rocreds'] = 'ユーザ名/パスワード認証'; 69 | $string['cfg_loginflow_rocreds_desc'] = 'このフローでは、手動によるログインと同様、ユーザはMoodleのログインフォームにユーザ名とパスワードを入力します。これらの認証情報はバックグラウンドでアイデンティティプロバイダに渡され、認証を取得します。ユーザはアイデンティティプロバイダと直接やり取りしないので、このフローはユーザに最も透過的です。すべてのアイデンティティプロバイダがこのフローをサポートしているわけではない点にご注意ください。'; 70 | $string['cfg_oidcresource_key'] = 'リソース'; 71 | $string['cfg_oidcresource_desc'] = 'リクエストを送る、OpenID Connectのリソース。'; 72 | $string['cfg_oidcscope_key'] = '範囲'; 73 | $string['cfg_oidcscope_desc'] = '使用するOIDCスコープ。'; 74 | $string['cfg_opname_key'] = 'プロバイダ名'; 75 | $string['cfg_opname_desc'] = 'これはユーザがログインするために使用する必要がある認証情報の種類を識別するラベルで、エンドユーザに表示されます。このラベルはプロバイダを識別するために、このプラグインのユーザに表示されるすべての部分で使用されます。'; 76 | $string['cfg_redirecturi_key'] = 'リダイレクトURI'; 77 | $string['cfg_redirecturi_desc'] = 'これは"リダイレクトURI"として登録するURIです。OpenID Connectアイデンティティプロバイダは、クライアントとしてMoodleを登録するときにこれを要求します。
注意: これは、ここに表示されているとおり「正確」にOpenID Connectプロバイダに入力する必要があります。違いがあると、OpenID Connectを使用してログインできません。'; 78 | $string['cfg_tokenendpoint_key'] = 'トークエンドポイント'; 79 | $string['cfg_tokenendpoint_desc'] = 'アイデンティティプロバイダが使用する、トークンエンドポイントのURIです。'; 80 | $string['event_debug'] = 'デバッグメッセージ'; 81 | $string['errorauthdisconnectemptypassword'] = 'パスワードは空白にできません。'; 82 | $string['errorauthdisconnectemptyusername'] = 'ユーザ名は空白にできません。'; 83 | $string['errorauthdisconnectusernameexists'] = 'このユーザ名は既に使用されています。別のユーザ名を選択してください。'; 84 | $string['errorauthdisconnectnewmethod'] = 'ログイン方法を使用する'; 85 | $string['errorauthdisconnectinvalidmethod'] = '無効なログイン方法を受信しました。'; 86 | $string['errorauthdisconnectifmanual'] = '手動によるログインを利用する場合は、以下に認証情報を入力します。'; 87 | $string['errorauthinvalididtoken'] = 'Invalid id_tokenを受信しました。'; 88 | $string['errorauthloginfailednouser'] = '無効なログイン : Moodleでユーザが見つかりませんでした'; 89 | $string['errorauthnoauthcode'] = '認証コードを受信していません。'; 90 | $string['errorauthnocreds'] = 'OpenID Connectクライアント認証情報を設定してください。'; 91 | $string['errorauthnoendpoints'] = 'OpenID Connectサーバエンドポイントを設定してください。'; 92 | $string['errorauthnohttpclient'] = 'HTTPクライアントを設定してください。'; 93 | $string['errorauthnoidtoken'] = 'OpenID接続のid_tokenを受信していません。'; 94 | $string['errorauthunknownstate'] = '不明な状態です。'; 95 | $string['errorauthuseralreadyconnected'] = '既に別のOpenID Connectユーザに接続しています。'; 96 | $string['errorauthuserconnectedtodifferent'] = '認証したOpenID Connectユーザは既にMoodleユーザに接続されています。'; 97 | $string['errorbadloginflow'] = '無効なログインフローが指定されました。注 : インストールまたはアップグレードを最近行った場合は、Moodleキャッシュをクリアしてください。'; 98 | $string['errorjwtbadpayload'] = 'JWTペイロードを読み取れませんでした。'; 99 | $string['errorjwtcouldnotreadheader'] = 'JWTヘッダーを読み取れませんでした'; 100 | $string['errorjwtempty'] = '空のJWT、または文字列以外のJWTを受信しました。'; 101 | $string['errorjwtinvalidheader'] = '無効なJWTヘッダー'; 102 | $string['errorjwtmalformed'] = '無効な形式のJWTを受信しました。'; 103 | $string['errorjwtunsupportedalg'] = 'JWS AlgまたはJWEがサポートされていません'; 104 | $string['erroroidcnotenabled'] = 'OpenID Connect認証プラグインが有効になっていません。'; 105 | $string['errornodisconnectionauthmethod'] = 'フォールバックする有効な認証プラグインがないため、接続解除できません (ユーザの以前のログイン方法または手動ログイン方法)。'; 106 | $string['erroroidcclientinvalidendpoint'] = '無効なエンドポイントURIを受信しました。'; 107 | $string['erroroidcclientnocreds'] = 'クライアントの認証情報と秘密鍵を設定してください'; 108 | $string['erroroidcclientnoauthendpoint'] = '認証エンドポイントが設定されていません。$this->setendpointsを使用して設定してください。'; 109 | $string['erroroidcclientnotokenendpoint'] = 'トークンエンドポイントが設定されていません。$this->setendpointsを使用して設定してください。'; 110 | $string['erroroidcclientinsecuretokenendpoint'] = 'トークンエンドポイントはこのためにSSL/TLSを使用している必要があります。'; 111 | $string['errorucpinvalidaction'] = '無効なアクションを受信しました。'; 112 | $string['erroroidccall'] = 'OpenID接続のエラーが発生しました。詳細については、ログを確認してください。'; 113 | $string['erroroidccall_message'] = 'OpenID接続のエラー : {$a}'; 114 | $string['eventuserauthed'] = 'ユーザをOpenID Coonectで認証しました'; 115 | $string['eventusercreated'] = 'ユーザをOpenID Connectで作成しました'; 116 | $string['eventuserconnected'] = 'ユーザをOpenID Connectに接続しました'; 117 | $string['eventuserloggedin'] = 'ユーザはOpenID Connectにログインしました'; 118 | $string['eventuserdisconnected'] = 'ユーザはOpenID Connectから接続解除されました'; 119 | $string['oidc:manageconnection'] = 'OpenID Connect接続を管理する'; 120 | $string['ucp_general_intro'] = 'ここでは、{$a} への接続を管理できます。有効にした場合、個別のユーザ名とパスワードを使用する代わりに、{$a} アカウントを使用してMoodleにログインできます。接続後は、Moodleのユーザ名とパスワードを覚えておく必要がなくなります。すべてのログインは {$a} が処理します。'; 121 | $string['ucp_login_start'] = '{$a} を使用してMoodleへのログインを開始する'; 122 | $string['ucp_login_start_desc'] = 'アカウントが {$a} を使用してMoodleにログインするよう切り替わります。有効にした場合、{$a} の認証情報を使用してログインするようになります。現在のMoodleユーザ名とパスワードは機能しなくなります。いつでもアカウントの接続を解除し、通常のログイン方法に戻ることができます。'; 123 | $string['ucp_login_stop'] = '{$a} を使用したMoodleへのログインを停止する'; 124 | $string['ucp_login_stop_desc'] = '現在 {$a} を使用してMoodleにログインしています。[{$a} ログインの停止]をクリックすると、 Moodleアカウントが {$a} から接続解除されます。{$a} アカウントを使用してMoodleにログインできなくなります。 ユーザ名とパスワードを作成するように求められます。その後は、Moodleに直接ログインできるようになります。'; 125 | $string['ucp_login_status'] = '{$a} ログインは :'; 126 | $string['ucp_status_enabled'] = '有効'; 127 | $string['ucp_status_disabled'] = '無効'; 128 | $string['ucp_disconnect_title'] = '{$a} 接続解除'; 129 | $string['ucp_disconnect_details'] = 'Moodleアカウントを {$a} から接続解除します。Moodleにログインするには、ユーザ名とパスワードを作成する必要があります。'; 130 | $string['ucp_title'] = '{$a} 管理'; 131 | 132 | // phpcs:enable moodle.Files.LangFilesOrdering.IncorrectOrder 133 | // phpcs:enable moodle.Files.LangFilesOrdering.UnexpectedComment -------------------------------------------------------------------------------- /logout.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Single Sign Out end point. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | // phpcs:ignore moodle.Files.RequireLogin.Missing 27 | require_once(__DIR__ . '/../../config.php'); 28 | 29 | $PAGE->set_url('/auth/oidc/logout.php'); 30 | $PAGE->set_context(context_system::instance()); 31 | 32 | $sid = optional_param('sid', '', PARAM_TEXT); 33 | 34 | if ($sid) { 35 | if ($authoidcsidrecord = $DB->get_record('auth_oidc_sid', ['sid' => $sid])) { 36 | if ($authoidcsidrecord->userid == $USER->id) { 37 | $authsequence = get_enabled_auth_plugins(); // Auths, in sequence. 38 | foreach ($authsequence as $authname) { 39 | $authplugin = get_auth_plugin($authname); 40 | $authplugin->logoutpage_hook(); 41 | } 42 | 43 | $DB->delete_records('auth_oidc_sid', ['sid' => $sid]); 44 | require_logout(); 45 | } 46 | } 47 | } 48 | 49 | die(); 50 | -------------------------------------------------------------------------------- /manageapplication.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * OIDC application configuration page. 19 | * 20 | * @package auth_oidc 21 | * @author Lai Wei 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2022 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | use auth_oidc\form\application; 27 | 28 | require_once(dirname(__FILE__) . '/../../config.php'); 29 | require_once($CFG->libdir . '/adminlib.php'); 30 | require_once($CFG->dirroot . '/auth/oidc/lib.php'); 31 | 32 | require_login(); 33 | 34 | $url = new moodle_url('/auth/oidc/manageapplication.php'); 35 | $PAGE->set_url($url); 36 | $PAGE->set_context(context_system::instance()); 37 | $PAGE->set_pagelayout('admin'); 38 | $PAGE->set_heading(get_string('settings_page_application', 'auth_oidc')); 39 | $PAGE->set_title(get_string('settings_page_application', 'auth_oidc')); 40 | 41 | $jsparams = [AUTH_OIDC_IDP_TYPE_MICROSOFT_IDENTITY_PLATFORM, AUTH_OIDC_AUTH_METHOD_SECRET, AUTH_OIDC_AUTH_METHOD_CERTIFICATE, 42 | get_string('auth_method_certificate', 'auth_oidc')]; 43 | $jsmodule = [ 44 | 'name' => 'auth_oidc', 45 | 'fullpath' => '/auth/oidc/js/module.js', 46 | ]; 47 | $PAGE->requires->js_init_call('M.auth_oidc.init', $jsparams, true, $jsmodule); 48 | 49 | admin_externalpage_setup('auth_oidc_application'); 50 | 51 | require_admin(); 52 | 53 | $oidcconfig = get_config('auth_oidc'); 54 | 55 | $form = new application(null, ['oidcconfig' => $oidcconfig]); 56 | 57 | $formdata = []; 58 | foreach (['idptype', 'clientid', 'clientauthmethod', 'clientsecret', 'clientprivatekey', 'clientcert', 59 | 'clientcertsource', 'clientprivatekeyfile', 'clientcertfile', 'clientcertpassphrase', 60 | 'authendpoint', 'tokenendpoint', 'oidcresource', 'oidcscope', 'secretexpiryrecipients', 61 | 'bindingusernameclaim', 'customclaimname'] as $field) { 62 | if (isset($oidcconfig->$field)) { 63 | $formdata[$field] = $oidcconfig->$field; 64 | } 65 | } 66 | 67 | $form->set_data($formdata); 68 | 69 | if ($form->is_cancelled()) { 70 | redirect($url); 71 | } else if ($fromform = $form->get_data()) { 72 | // Handle odd cases where clientauthmethod is not received. 73 | if (!isset($fromform->clientauthmethod)) { 74 | $fromform->clientauthmethod = optional_param('clientauthmethod', AUTH_OIDC_AUTH_METHOD_SECRET, PARAM_INT); 75 | } 76 | 77 | // Prepare config settings to save. 78 | $configstosave = ['idptype', 'clientid', 'clientauthmethod', 'authendpoint', 'tokenendpoint', 79 | 'oidcresource', 'oidcscope']; 80 | 81 | // Depending on the value of clientauthmethod, save clientsecret or (clientprivatekey and clientcert). 82 | switch ($fromform->clientauthmethod) { 83 | case AUTH_OIDC_AUTH_METHOD_SECRET: 84 | $configstosave[] = 'clientsecret'; 85 | $configstosave[] = 'secretexpiryrecipients'; 86 | break; 87 | case AUTH_OIDC_AUTH_METHOD_CERTIFICATE: 88 | $configstosave[] = 'clientcertsource'; 89 | $configstosave[] = 'clientcertpassphrase'; 90 | switch ($fromform->clientcertsource) { 91 | case AUTH_OIDC_AUTH_CERT_SOURCE_TEXT: 92 | $configstosave[] = 'clientprivatekey'; 93 | $configstosave[] = 'clientcert'; 94 | break; 95 | case AUTH_OIDC_AUTH_CERT_SOURCE_FILE: 96 | $configstosave[] = 'clientprivatekeyfile'; 97 | $configstosave[] = 'clientcertfile'; 98 | break; 99 | } 100 | break; 101 | } 102 | 103 | // Save config settings. 104 | $updateapplicationtokenrequired = false; 105 | $settingschanged = false; 106 | foreach ($configstosave as $config) { 107 | $existingsetting = get_config('auth_oidc', $config); 108 | if ($fromform->$config != $existingsetting) { 109 | add_to_config_log($config, $existingsetting, $fromform->$config, 'auth_oidc'); 110 | set_config($config, $fromform->$config, 'auth_oidc'); 111 | $settingschanged = true; 112 | if ($config != 'secretexpiryrecipients') { 113 | $updateapplicationtokenrequired = true; 114 | } 115 | } 116 | } 117 | 118 | // Redirect destination and message depend on IdP type. 119 | $isgraphapiconnected = false; 120 | if ($fromform->idptype != AUTH_OIDC_IDP_TYPE_OTHER) { 121 | if (auth_oidc_is_local_365_installed()) { 122 | $isgraphapiconnected = true; 123 | } 124 | } 125 | 126 | if ($updateapplicationtokenrequired) { 127 | if ($isgraphapiconnected) { 128 | // First, delete the existing application token and purge cache. 129 | unset_config('apptokens', 'local_o365'); 130 | unset_config('azuresetupresult', 'local_o365'); 131 | purge_all_caches(); 132 | 133 | // Then show the message to the user with instructions to update the application token. 134 | $localo365configurl = new moodle_url('/admin/settings.php', ['section' => 'local_o365']); 135 | redirect($localo365configurl, get_string('application_updated_microsoft', 'auth_oidc')); 136 | } else { 137 | redirect($url, get_string('application_updated', 'auth_oidc')); 138 | } 139 | } else if ($settingschanged) { 140 | redirect($url, get_string('application_updated', 'auth_oidc')); 141 | } else { 142 | redirect($url, get_string('application_not_changed', 'auth_oidc')); 143 | } 144 | } 145 | 146 | echo $OUTPUT->header(); 147 | 148 | $form->display(); 149 | 150 | echo $OUTPUT->footer(); 151 | -------------------------------------------------------------------------------- /pix/o365.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/moodle-auth_oidc/a3487f8cd62f00757133e13be0266c43c4caa7ad/pix/o365.png -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | .auth_oidc_ucp_indicator h4 { 2 | display: inline-block; 3 | margin-right: 0.5rem; 4 | } 5 | 6 | .auth_oidc_ucp_indicator h5 { 7 | display: inline-block; 8 | margin-left: 0.5rem; 9 | } 10 | 11 | .auth_oidc_ucp_indicator h5 + span { 12 | display: block; 13 | } 14 | 15 | .cert_textarea textarea { 16 | font-family: 'Courier New', Courier, monospace; 17 | } 18 | 19 | .path-admin-auth-oidc .warning_header { 20 | border: 1px solid #f00; 21 | background-color: #ffe5e5; 22 | padding: 10px; 23 | margin: 10px 0; 24 | color: #f00; 25 | font-weight: bold; 26 | } 27 | 28 | .path-admin-auth-oidc .warning { 29 | color: #f00; 30 | font-weight: bold; 31 | } 32 | 33 | .path-admin-auth-oidc .existing_claims { 34 | display: inline-block; 35 | background-color: #f0f0f0; 36 | border: 1px solid #ccc; 37 | padding: 10px; 38 | font-family: 'Courier New', Courier, monospace; 39 | white-space: pre; 40 | } 41 | 42 | .path-admin-auth-oidc .not_support_user_sync { 43 | color: #f00; 44 | } 45 | 46 | .path-admin-auth-oidc .code { 47 | font-family: 'Courier New', Courier, monospace; 48 | white-space: pre; 49 | } 50 | -------------------------------------------------------------------------------- /tests/jwt_test.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * JWT test cases. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | namespace auth_oidc; 27 | 28 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | global $CFG; 31 | 32 | /** 33 | * Tests jwt. 34 | * 35 | * @group auth_oidc 36 | * @group office365 37 | */ 38 | final class jwt_test extends \advanced_testcase { 39 | /** 40 | * Perform setup before every test. This tells Moodle's phpunit to reset the database after every test. 41 | */ 42 | protected function setUp(): void { 43 | parent::setUp(); 44 | $this->resetAfterTest(true); 45 | } 46 | 47 | /** 48 | * Dataprovider for test_decode. 49 | * 50 | * @return array Array of arrays of test parameters. 51 | */ 52 | public static function dataprovider_decode(): array { 53 | $tests = []; 54 | 55 | $tests['emptytest'] = [ 56 | '', '', ['Exception', 'Empty or non-string JWT received.'], 57 | ]; 58 | 59 | $tests['nonstringtest'] = [ 60 | 100, '', ['Exception', 'Empty or non-string JWT received.'], 61 | ]; 62 | 63 | $tests['malformed1'] = [ 64 | 'a', '', ['Exception', 'Malformed JWT received.'], 65 | ]; 66 | 67 | $tests['malformed2'] = [ 68 | 'a.b', '', ['Exception', 'Malformed JWT received.'], 69 | ]; 70 | 71 | $tests['malformed3'] = [ 72 | 'a.b.c.d', '', ['Exception', 'Malformed JWT received.'], 73 | ]; 74 | 75 | $tests['badheader1'] = [ 76 | 'h.p.s', '', ['Exception', 'Could not read JWT header'], 77 | ]; 78 | 79 | $header = base64_encode(json_encode(['key' => 'val'])); 80 | $tests['invalidheader1'] = [ 81 | $header . '.p.s', '', ['Exception', 'Invalid JWT header'], 82 | ]; 83 | 84 | $header = base64_encode(json_encode(['alg' => 'ROT13'])); 85 | $tests['badalg1'] = [ 86 | $header . '.p.s', '', ['Exception', 'JWS Alg or JWE not supported'], 87 | ]; 88 | 89 | $header = base64_encode(json_encode(['alg' => 'RS256'])); 90 | $payload = 'p'; 91 | $tests['badpayload1'] = [ 92 | $header . '.' . $payload . '.s', '', ['Exception', 'Could not read JWT payload.'], 93 | ]; 94 | 95 | $header = base64_encode(json_encode(['alg' => 'RS256'])); 96 | $payload = base64_encode('nothing'); 97 | $tests['badpayload2'] = [ 98 | $header . '.' . $payload . '.s', '', ['Exception', 'Could not read JWT payload.'], 99 | ]; 100 | 101 | $header = ['alg' => 'RS256']; 102 | $payload = ['payload' => 'found']; 103 | $headerenc = base64_encode(json_encode($header)); 104 | $payloadenc = base64_encode(json_encode($payload)); 105 | $expected = [$header, $payload]; 106 | $tests['goodpayload1'] = [ 107 | $headerenc . '.' . $payloadenc . '.s', $expected, [], 108 | ]; 109 | 110 | return $tests; 111 | } 112 | 113 | /** 114 | * Test decode. 115 | * 116 | * @dataProvider dataprovider_decode 117 | * @covers \auth_oidc\jwt::decode 118 | * 119 | * @param string $encodedjwt The JWT token to be decoded. 120 | * @param mixed $expectedresult The expected result after decoding. 121 | * @param array $expectedexception The expected exception class and message if an error occurs. 122 | * @return void 123 | */ 124 | public function test_decode($encodedjwt, $expectedresult, $expectedexception): void { 125 | if (!empty($expectedexception)) { 126 | $this->expectException($expectedexception[0]); 127 | $this->expectExceptionMessage($expectedexception[1]); 128 | } 129 | $actualresult = \auth_oidc\jwt::decode($encodedjwt); 130 | $this->assertEquals($expectedresult, $actualresult); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /tests/oidcclient_test.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * OIDC client test cases. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | 27 | 28 | namespace auth_oidc; 29 | 30 | defined('MOODLE_INTERNAL') || die(); 31 | 32 | global $CFG; 33 | 34 | /** 35 | * Tests oidcclient. 36 | * 37 | * @group auth_oidc 38 | * @group office365 39 | */ 40 | final class oidcclient_test extends \advanced_testcase { 41 | /** 42 | * Perform setup before every test. This tells Moodle's phpunit to reset the database after every test. 43 | */ 44 | protected function setUp(): void { 45 | parent::setUp(); 46 | $this->resetAfterTest(true); 47 | } 48 | 49 | /** 50 | * Test getting and setting credentials. 51 | * 52 | * @covers \auth_oidc\tests\mockoidcclient::setcreds 53 | */ 54 | public function test_creds_getters_and_setters(): void { 55 | $httpclient = new \auth_oidc\tests\mockhttpclient(); 56 | $client = new \auth_oidc\tests\mockoidcclient($httpclient); 57 | 58 | $this->assertNull($client->get_clientid()); 59 | $this->assertNull($client->get_clientsecret()); 60 | $this->assertNull($client->get_redirecturi()); 61 | 62 | $id = 'id'; 63 | $secret = 'secret'; 64 | $redirecturi = 'redirecturi'; 65 | $tokenresource = 'resource'; 66 | $scope = (isset($this->config->oidcscope)) ? $this->config->oidcscope : null; 67 | $client->setcreds($id, $secret, $redirecturi, $tokenresource, $scope); 68 | 69 | $this->assertEquals($id, $client->get_clientid()); 70 | $this->assertEquals($secret, $client->get_clientsecret()); 71 | $this->assertEquals($redirecturi, $client->get_redirecturi()); 72 | $this->assertEquals($tokenresource, $client->get_tokenresource()); 73 | } 74 | 75 | /** 76 | * Dataprovider returning endpoints. 77 | * 78 | * @return array Array of arrays of test parameters. 79 | */ 80 | public static function dataprovider_endpoints(): array { 81 | $tests = []; 82 | 83 | $tests['oneinvalid'] = [ 84 | ['auth' => 100], 85 | ['Exception', 'Invalid Endpoint URI received.'], 86 | ]; 87 | 88 | $tests['oneinvalidonevalid1'] = [ 89 | ['auth' => 100, 'token' => 'http://example.com/token'], 90 | ['Exception', 'Invalid Endpoint URI received.'], 91 | ]; 92 | 93 | $tests['oneinvalidonevalid2'] = [ 94 | ['token' => 'http://example.com/token', 'auth' => 100], 95 | ['Exception', 'Invalid Endpoint URI received.'], 96 | ]; 97 | 98 | $tests['onevalid'] = [ 99 | ['token' => 'http://example.com/token'], 100 | [], 101 | ]; 102 | 103 | $tests['twovalid'] = [ 104 | ['auth' => 'http://example.com/auth', 'token' => 'http://example.com/token'], 105 | [], 106 | ]; 107 | 108 | return $tests; 109 | } 110 | 111 | /** 112 | * Test setting and getting endpoints. 113 | * 114 | * @dataProvider dataprovider_endpoints 115 | * @covers \auth_oidc\tests\mockoidcclient::setendpoints 116 | * @param array $endpoints 117 | * @param array $expectedexception 118 | */ 119 | public function test_endpoints_getters_and_setters(array $endpoints, array $expectedexception): void { 120 | if (!empty($expectedexception)) { 121 | $this->expectException($expectedexception[0]); 122 | $this->expectExceptionMessage($expectedexception[1]); 123 | } 124 | $httpclient = new \auth_oidc\tests\mockhttpclient(); 125 | $client = new \auth_oidc\tests\mockoidcclient($httpclient); 126 | $client->setendpoints($endpoints); 127 | 128 | foreach ($endpoints as $type => $uri) { 129 | $this->assertEquals($uri, $client->get_endpoint($type)); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /ucp.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * User control panel page. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | require_once(__DIR__.'/../../config.php'); 27 | require_once(__DIR__.'/auth.php'); 28 | require_once(__DIR__.'/lib.php'); 29 | 30 | require_login(); 31 | 32 | $action = optional_param('action', null, PARAM_TEXT); 33 | 34 | $oidctoken = $DB->get_record('auth_oidc_token', ['userid' => $USER->id]); 35 | $oidcconnected = (!empty($oidctoken)) ? true : false; 36 | 37 | $oidcloginconnected = ($USER->auth === 'oidc') ? true : false; 38 | 39 | if (!is_enabled_auth('oidc')) { 40 | throw new moodle_exception('erroroidcnotenabled', 'auth_oidc'); 41 | } 42 | 43 | if (!empty($action)) { 44 | if ($action === 'connectlogin' && $oidcloginconnected === false) { 45 | // Use authorization request login flow to connect existing users. 46 | auth_oidc_connectioncapability($USER->id, 'connect', true); 47 | $auth = new \auth_oidc\loginflow\authcode; 48 | $auth->set_httpclient(new \auth_oidc\httpclient()); 49 | $auth->initiateauthrequest(); 50 | } else if ($action === 'disconnectlogin' && $oidcloginconnected === true) { 51 | if (is_enabled_auth('manual') === true) { 52 | auth_oidc_connectioncapability($USER->id, 'disconnect', true); 53 | $auth = new \auth_plugin_oidc; 54 | $auth->set_httpclient(new \auth_oidc\httpclient()); 55 | $auth->disconnect(); 56 | } 57 | } else { 58 | throw new moodle_exception('errorucpinvalidaction', 'auth_oidc'); 59 | } 60 | } else { 61 | $PAGE->set_url('/auth/oidc/ucp.php'); 62 | $usercontext = \context_user::instance($USER->id); 63 | $PAGE->set_context(\context_system::instance()); 64 | $PAGE->set_pagelayout('standard'); 65 | $USER->editing = false; 66 | $authconfig = get_config('auth_oidc'); 67 | $opname = (!empty($authconfig->opname)) ? $authconfig->opname : get_string('pluginname', 'auth_oidc'); 68 | 69 | $ucptitle = get_string('ucp_title', 'auth_oidc', $opname); 70 | $PAGE->navbar->add($ucptitle, $PAGE->url); 71 | $PAGE->set_title($ucptitle); 72 | 73 | echo $OUTPUT->header(); 74 | echo \html_writer::tag('h2', $ucptitle); 75 | echo get_string('ucp_general_intro', 'auth_oidc', $opname); 76 | echo '

'; 77 | 78 | if (optional_param('o365accountconnected', null, PARAM_TEXT) == 'true') { 79 | echo \html_writer::start_div('connectionstatus alert alert-error'); 80 | echo \html_writer::tag('h5', get_string('ucp_o365accountconnected', 'auth_oidc')); 81 | echo \html_writer::end_div(); 82 | } 83 | 84 | // Login status. 85 | echo \html_writer::start_div('auth_oidc_ucp_indicator'); 86 | echo \html_writer::tag('h4', get_string('ucp_login_status', 'auth_oidc', $opname)); 87 | if ($oidcloginconnected === true) { 88 | echo \html_writer::tag('h4', get_string('ucp_status_enabled', 'auth_oidc'), ['class' => 'notifysuccess']); 89 | if (is_enabled_auth('manual') === true) { 90 | if (auth_oidc_connectioncapability($USER->id, 'disconnect')) { 91 | $connectlinkuri = new \moodle_url('/auth/oidc/ucp.php', ['action' => 'disconnectlogin']); 92 | $strdisconnect = get_string('ucp_login_stop', 'auth_oidc', $opname); 93 | $linkhtml = \html_writer::link($connectlinkuri, $strdisconnect); 94 | echo \html_writer::tag('h5', $linkhtml); 95 | echo \html_writer::span(get_string('ucp_login_stop_desc', 'auth_oidc', $opname)); 96 | } 97 | } 98 | } else { 99 | echo \html_writer::tag('h4', get_string('ucp_status_disabled', 'auth_oidc'), ['class' => 'notifyproblem']); 100 | if (auth_oidc_connectioncapability($USER->id, 'connect')) { 101 | $connectlinkuri = new \moodle_url('/auth/oidc/ucp.php', ['action' => 'connectlogin']); 102 | $linkhtml = \html_writer::link($connectlinkuri, get_string('ucp_login_start', 'auth_oidc', $opname)); 103 | echo \html_writer::tag('h5', $linkhtml); 104 | echo \html_writer::span(get_string('ucp_login_start_desc', 'auth_oidc', $opname)); 105 | } 106 | } 107 | echo \html_writer::end_div(); 108 | 109 | echo $OUTPUT->footer(); 110 | } 111 | -------------------------------------------------------------------------------- /version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Plugin version information. 19 | * 20 | * @package auth_oidc 21 | * @author James McQuillan 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/) 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | $plugin->version = 2024100710; 29 | $plugin->requires = 2024100700; 30 | $plugin->release = '4.5.2'; 31 | $plugin->component = 'auth_oidc'; 32 | $plugin->maturity = MATURITY_STABLE; 33 | --------------------------------------------------------------------------------