diff options
author | Max Magorsch <arzano@gentoo.org> | 2020-05-27 01:53:07 +0200 |
---|---|---|
committer | Max Magorsch <arzano@gentoo.org> | 2020-05-27 01:53:07 +0200 |
commit | 6a4c71e39c017ee77b6177e0492c7035ba0f2057 (patch) | |
tree | d0cf1d5b927c1217f5c9d2700413f9a7206da99d | |
parent | Drop MatomoAnalytics (diff) | |
download | extensions-6a4c71e39c017ee77b6177e0492c7035ba0f2057.tar.gz extensions-6a4c71e39c017ee77b6177e0492c7035ba0f2057.tar.bz2 extensions-6a4c71e39c017ee77b6177e0492c7035ba0f2057.zip |
Add OpenIDConnect extension for Gentoo SSO
Signed-off-by: Max Magorsch <arzano@gentoo.org>
36 files changed, 855 insertions, 0 deletions
diff --git a/OpenIDConnect/.gitignore b/OpenIDConnect/.gitignore new file mode 100644 index 00000000..6574e829 --- /dev/null +++ b/OpenIDConnect/.gitignore @@ -0,0 +1,4 @@ +/node_modules/ +/vendor/ +/composer.lock +/package-lock.json diff --git a/OpenIDConnect/.gitreview b/OpenIDConnect/.gitreview new file mode 100644 index 00000000..27b98d1a --- /dev/null +++ b/OpenIDConnect/.gitreview @@ -0,0 +1,6 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/OpenIDConnect.git +track=1 +defaultrebase=0 diff --git a/OpenIDConnect/.phpcs.xml b/OpenIDConnect/.phpcs.xml new file mode 100644 index 00000000..95b1ff23 --- /dev/null +++ b/OpenIDConnect/.phpcs.xml @@ -0,0 +1,8 @@ +<?xml version="1.0"?> +<ruleset> + <rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki" /> + <file>.</file> + <arg name="extensions" value="php,php5,inc" /> + <arg name="encoding" value="utf8" /> + <exclude-pattern>vendor</exclude-pattern> +</ruleset> diff --git a/OpenIDConnect/CODE_OF_CONDUCT.md b/OpenIDConnect/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..d8e5d087 --- /dev/null +++ b/OpenIDConnect/CODE_OF_CONDUCT.md @@ -0,0 +1 @@ +The development of this software is covered by a [Code of Conduct](https://www.mediawiki.org/wiki/Code_of_Conduct). diff --git a/OpenIDConnect/Gruntfile.js b/OpenIDConnect/Gruntfile.js new file mode 100644 index 00000000..a45071e1 --- /dev/null +++ b/OpenIDConnect/Gruntfile.js @@ -0,0 +1,21 @@ +/*jshint node:true */ +module.exports = function ( grunt ) { + grunt.loadNpmTasks( 'grunt-jsonlint' ); + grunt.loadNpmTasks( 'grunt-banana-checker' ); + + grunt.initConfig( { + banana: { + all: 'i18n/' + }, + jsonlint: { + all: [ + '**/*.json', + '!node_modules/**', + '!vendor/**' + ] + } + } ); + + grunt.registerTask( 'test', [ 'jsonlint', 'banana' ] ); + grunt.registerTask( 'default', 'test' ); +}; diff --git a/OpenIDConnect/composer.json b/OpenIDConnect/composer.json new file mode 100644 index 00000000..692e24e4 --- /dev/null +++ b/OpenIDConnect/composer.json @@ -0,0 +1,37 @@ +{ + "name": "mediawiki/OpenIDConnect", + "description": "Provides authentication using OpenID Connect in conjunction with PluggableAuth", + "license": "MIT", + "authors": [ + { + "name": "Cindy Cicalese", + "email": "cicalese@mitre.org" + } + ], + "repositories": [ + { + "url": "https://github.com/jumbojett/OpenID-Connect-PHP.git", + "type": "git" + } + ], + "require": { + "jumbojett/openid-connect-php": "0.5.0" + }, + "require-dev": { + "jakub-onderka/php-parallel-lint": "1.0.0", + "mediawiki/mediawiki-codesniffer": "18.0.0", + "jakub-onderka/php-console-highlighter": "0.3.2", + "mediawiki/minus-x": "0.3.1" + }, + "scripts": { + "test": [ + "parallel-lint . --exclude vendor --exclude node_modules", + "phpcs -p -s", + "minus-x check ." + ], + "fix": [ + "phpcbf", + "minus-x fix ." + ] + } +} diff --git a/OpenIDConnect/extension.json b/OpenIDConnect/extension.json new file mode 100644 index 00000000..de2bac84 --- /dev/null +++ b/OpenIDConnect/extension.json @@ -0,0 +1,46 @@ +{ + "name": "OpenID Connect", + "version": "4.1", + "author": [ + "[https://www.mediawiki.org/wiki/User:Cindy.cicalese Cindy Cicalese]" + ], + "url": "https://www.mediawiki.org/wiki/Extension:OpenID_Connect", + "descriptionmsg": "openidconnect-desc", + "type": "other", + "requires": { + "extensions": { + "PluggableAuth": ">= 4.0" + } + }, + "SpecialPages": { + "SelectOpenIDConnectIssuer": "SelectOpenIDConnectIssuer" + }, + "MessagesDirs": { + "OpenIDConnect": [ + "i18n" + ] + }, + "ExtensionMessagesFiles": { + "SelectOpenIDConnectIssuerAlias": "i18n/SelectOpenIDConnectIssuer.alias.php" + }, + "AutoloadClasses": { + "OpenIDConnect": "src/OpenIDConnect.php", + "SelectOpenIDConnectIssuer": "src/SelectOpenIDConnectIssuer.php" + }, + "Hooks": { + "LoadExtensionSchemaUpdates": "OpenIDConnect::loadExtensionSchemaUpdates" + }, + "config": { + "OpenIDConnect_MigrateUsersByEmail": false, + "OpenIDConnect_MigrateUsersByUserName": false, + "OpenIDConnect_ForceLogout": false, + "OpenIDConnect_UseRealNameAsUserName": false, + "OpenIDConnect_UseEmailNameAsUserName": false, + "PluggableAuth_Class": "OpenIDConnect" + }, + "PluggableAuthLoginSpecialPages": [ + "SelectOpenIDConnectIssuer" + ], + "load_composer_autoloader": true, + "manifest_version": 1 +} diff --git a/OpenIDConnect/gitinfo.json b/OpenIDConnect/gitinfo.json new file mode 100644 index 00000000..ad2b408c --- /dev/null +++ b/OpenIDConnect/gitinfo.json @@ -0,0 +1 @@ +{"branch": "baea47f52e4b86ee09a01a6e26d1699bd31b6ea8\n", "headSHA1": "baea47f52e4b86ee09a01a6e26d1699bd31b6ea8\n", "remoteURL": "https://gerrit-replica.wikimedia.org/r/mediawiki/extensions/OpenIDConnect", "headCommitDate": "1523681260", "head": "baea47f52e4b86ee09a01a6e26d1699bd31b6ea8\n"}
\ No newline at end of file diff --git a/OpenIDConnect/i18n/SelectOpenIDConnectIssuer.alias.php b/OpenIDConnect/i18n/SelectOpenIDConnectIssuer.alias.php new file mode 100644 index 00000000..353ed4d5 --- /dev/null +++ b/OpenIDConnect/i18n/SelectOpenIDConnectIssuer.alias.php @@ -0,0 +1,46 @@ +<?php + +/* + * Copyright (c) 2015-2018 The MITRE Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +// @codingStandardsIgnoreFile + +$specialPageAliases = []; + +/** English (English) */ +$specialPageAliases['en'] = [ + 'SelectOpenIDConnectIssuer' => [ 'SelectOpenIDConnectIssuer', 'Select OpenID Connect Issuer' ], +]; + +/** Arabic (العربية) */ +$specialPageAliases['ar'] = [ + 'SelectOpenIDConnectIssuer' => [ 'اختيار_متحكم_الهوية_المفتوحة' ], +]; + +/** German (Deutsch) */ +$specialPageAliases['de'] = [ + 'SelectOpenIDConnectIssuer' => [ 'OpenID-Verbindungsherausgeber_auswählen' ], +]; + +/** Simplified Chinese (中文(简体)) */ +$specialPageAliases['zh-hans'] = [ + 'SelectOpenIDConnectIssuer' => [ '选择OpenID连接发行商' ], +]; diff --git a/OpenIDConnect/i18n/ast.json b/OpenIDConnect/i18n/ast.json new file mode 100644 index 00000000..8e6bd10b --- /dev/null +++ b/OpenIDConnect/i18n/ast.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Xuacu" + ] + }, + "openidconnect-desc": "Ufre autenticación usando OpenID Connect en conxunto con PluggableAuth", + "selectopenidconnectissuer": "Seleicionar el Fornidor d'Autenticación" +} diff --git a/OpenIDConnect/i18n/be-tarask.json b/OpenIDConnect/i18n/be-tarask.json new file mode 100644 index 00000000..e4a7ff8d --- /dev/null +++ b/OpenIDConnect/i18n/be-tarask.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Red Winged Duck" + ] + }, + "openidconnect-desc": "Забясьпечвае аўтэнтыфікацыю з дапамогай OpenID Connect у спалучэньні з PluggableAuth", + "selectopenidconnectissuer": "Абярыце крыніцу аўтэнтыфікацыі" +} diff --git a/OpenIDConnect/i18n/de.json b/OpenIDConnect/i18n/de.json new file mode 100644 index 00000000..111e405c --- /dev/null +++ b/OpenIDConnect/i18n/de.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Metalhead64" + ] + }, + "openidconnect-desc": "Ermöglicht eine Authentifizierung mithilfe OpenID Connect in Verbindung mit PluggableAuth", + "selectopenidconnectissuer": "Authentifizierungsgeber auswählen" +} diff --git a/OpenIDConnect/i18n/en.json b/OpenIDConnect/i18n/en.json new file mode 100644 index 00000000..52380151 --- /dev/null +++ b/OpenIDConnect/i18n/en.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Cicalese" + ] + }, + "openidconnect-desc": "Provides authentication using OpenID Connect in conjunction with PluggableAuth", + "selectopenidconnectissuer": "Select Authentication Issuer" +} diff --git a/OpenIDConnect/i18n/fr.json b/OpenIDConnect/i18n/fr.json new file mode 100644 index 00000000..4fcd46bb --- /dev/null +++ b/OpenIDConnect/i18n/fr.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Wladek92" + ] + }, + "openidconnect-desc": "Fournit une authentification en utilisant OpenID Connect en combinaison avec PluggableAuth", + "selectopenidconnectissuer": "Sélectionnez l'émetteur de l'authentification" +} diff --git a/OpenIDConnect/i18n/gl.json b/OpenIDConnect/i18n/gl.json new file mode 100644 index 00000000..c89fc552 --- /dev/null +++ b/OpenIDConnect/i18n/gl.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Elisardojm" + ] + }, + "openidconnect-desc": "Proporciona autentificación usando OpenID xunto con PluggableAuth", + "selectopenidconnectissuer": "Seleccionar distribuidor de autenticación" +} diff --git a/OpenIDConnect/i18n/ja.json b/OpenIDConnect/i18n/ja.json new file mode 100644 index 00000000..2324b127 --- /dev/null +++ b/OpenIDConnect/i18n/ja.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Otokoume" + ] + }, + "openidconnect-desc": "PluggableAuth と合わせて、OpenID の接続を使用して認証を提供します", + "selectopenidconnectissuer": "認証の発行者を選択" +} diff --git a/OpenIDConnect/i18n/ko.json b/OpenIDConnect/i18n/ko.json new file mode 100644 index 00000000..67cf6eb4 --- /dev/null +++ b/OpenIDConnect/i18n/ko.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Revi" + ] + }, + "openidconnect-desc": "PluggableAuth와 같이 사용하여 OpenID 연결 지원", + "selectopenidconnectissuer": "인증 제공자 선택" +} diff --git a/OpenIDConnect/i18n/ksh.json b/OpenIDConnect/i18n/ksh.json new file mode 100644 index 00000000..fee092c8 --- /dev/null +++ b/OpenIDConnect/i18n/ksh.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Purodha" + ] + }, + "openidconnect-desc": "Määd en Aanmäldong övver <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„offe Edäntefekazjuhn“ — en zäntrahle Manihr för ennzelogge\">OpenID</i> zersamme met <i lang=\"en\" xml:lang=\"en\">PluggableAuth</i> müjjelesch.", + "selectopenidconnectissuer": "Donn ußsöhke, wä di Aanmäldong aanbedt" +} diff --git a/OpenIDConnect/i18n/mk.json b/OpenIDConnect/i18n/mk.json new file mode 100644 index 00000000..15624d7c --- /dev/null +++ b/OpenIDConnect/i18n/mk.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Bjankuloski06" + ] + }, + "openidconnect-desc": "Овозможува заверка со OpenID Connect која работи заедно со PluggableAuth", + "selectopenidconnectissuer": "Изберете издавач на заверката" +} diff --git a/OpenIDConnect/i18n/nb.json b/OpenIDConnect/i18n/nb.json new file mode 100644 index 00000000..ff1b9a27 --- /dev/null +++ b/OpenIDConnect/i18n/nb.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Jon Harald Søby" + ] + }, + "openidconnect-desc": "Gir autentisering med OpenID Connect i forbindelse med PluggableAuth", + "selectopenidconnectissuer": "Velg autentiseringsutsteder" +} diff --git a/OpenIDConnect/i18n/nl.json b/OpenIDConnect/i18n/nl.json new file mode 100644 index 00000000..b250091c --- /dev/null +++ b/OpenIDConnect/i18n/nl.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Esketti" + ] + }, + "openidconnect-desc": "Zorgt voor verificatie met behulp van OpenID Connect in combinatie met PluggableAuth", + "selectopenidconnectissuer": "Selecteer Audenticatie Uitgevende Instelling" +} diff --git a/OpenIDConnect/i18n/pt-br.json b/OpenIDConnect/i18n/pt-br.json new file mode 100644 index 00000000..3e45d28d --- /dev/null +++ b/OpenIDConnect/i18n/pt-br.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "!Silent" + ] + }, + "openidconnect-desc": "Fornece autenticação usando o OpenID Connect em conjunto com o PluggableAuth", + "selectopenidconnectissuer": "Selecionar emissor de autenticação" +} diff --git a/OpenIDConnect/i18n/pt.json b/OpenIDConnect/i18n/pt.json new file mode 100644 index 00000000..5e61462b --- /dev/null +++ b/OpenIDConnect/i18n/pt.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Hamilton Abreu" + ] + }, + "openidconnect-desc": "Fornece capacidades de autenticação usando o OpenID Connect em conjunto com o PluggableAuth", + "selectopenidconnectissuer": "Selecionar emissor de autenticação" +} diff --git a/OpenIDConnect/i18n/qqq.json b/OpenIDConnect/i18n/qqq.json new file mode 100644 index 00000000..7911f3b2 --- /dev/null +++ b/OpenIDConnect/i18n/qqq.json @@ -0,0 +1,10 @@ +{ + "@metadata": { + "authors": [ + "Cicalese", + "Raymond" + ] + }, + "openidconnect-desc": "{{desc|name=OpenID Connect|url=https://www.mediawiki.org/wiki/Extension:OpenID_Connect}}", + "selectopenidconnectissuer": "Title of OpenID Connect issuer selection page" +} diff --git a/OpenIDConnect/i18n/roa-tara.json b/OpenIDConnect/i18n/roa-tara.json new file mode 100644 index 00000000..bd175952 --- /dev/null +++ b/OpenIDConnect/i18n/roa-tara.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Joetaras" + ] + }, + "openidconnect-desc": "Dèje l'autendicazione ausanne OpenID Connect cu PluggableAuth", + "selectopenidconnectissuer": "Scacchie 'nu probbleme de autendicazione" +} diff --git a/OpenIDConnect/i18n/ru.json b/OpenIDConnect/i18n/ru.json new file mode 100644 index 00000000..243302f7 --- /dev/null +++ b/OpenIDConnect/i18n/ru.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Okras" + ] + }, + "openidconnect-desc": "Обеспечивает проверку подлинности с помощью OpenID Connect в сочетании с PluggableAuth", + "selectopenidconnectissuer": "Выберите источник аутентификации" +} diff --git a/OpenIDConnect/i18n/sv.json b/OpenIDConnect/i18n/sv.json new file mode 100644 index 00000000..1c270d0c --- /dev/null +++ b/OpenIDConnect/i18n/sv.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Lokal Profil" + ] + }, + "openidconnect-desc": "Möjliggör autentisering med OpenID Connect i förbindelse med PluggableAuth", + "selectopenidconnectissuer": "Välj autentiseringsutfärdare" +} diff --git a/OpenIDConnect/i18n/uk.json b/OpenIDConnect/i18n/uk.json new file mode 100644 index 00000000..3ecf01cb --- /dev/null +++ b/OpenIDConnect/i18n/uk.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Ата" + ] + }, + "openidconnect-desc": "Забезпечує автентифікацію з допомогою OpenID Connect у поєднанні з PluggableAuth", + "selectopenidconnectissuer": "Виберіть джерело автентифікації" +} diff --git a/OpenIDConnect/i18n/zh-hans.json b/OpenIDConnect/i18n/zh-hans.json new file mode 100644 index 00000000..0af3a0d4 --- /dev/null +++ b/OpenIDConnect/i18n/zh-hans.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Liuxinyu970226" + ] + }, + "openidconnect-desc": "提供使用OpenID连接与PluggableAuth结合的认证", + "selectopenidconnectissuer": "选择认证提供商" +} diff --git a/OpenIDConnect/i18n/zh-hant.json b/OpenIDConnect/i18n/zh-hant.json new file mode 100644 index 00000000..fcdf30f7 --- /dev/null +++ b/OpenIDConnect/i18n/zh-hant.json @@ -0,0 +1,9 @@ +{ + "@metadata": { + "authors": [ + "Kly" + ] + }, + "openidconnect-desc": "提供使用 OpenID Connect 與 PluggableAuth 結合的認證", + "selectopenidconnectissuer": "選擇認證發行者" +} diff --git a/OpenIDConnect/package.json b/OpenIDConnect/package.json new file mode 100644 index 00000000..3b4b5f0c --- /dev/null +++ b/OpenIDConnect/package.json @@ -0,0 +1,11 @@ +{ + "private": true, + "scripts": { + "test": "grunt test" + }, + "devDependencies": { + "grunt": "1.0.1", + "grunt-banana-checker": "0.4.0", + "grunt-jsonlint": "1.0.7" + } +} diff --git a/OpenIDConnect/sql/AddIssuer.sql b/OpenIDConnect/sql/AddIssuer.sql new file mode 100644 index 00000000..4b18a376 --- /dev/null +++ b/OpenIDConnect/sql/AddIssuer.sql @@ -0,0 +1 @@ +ALTER TABLE /*_*/user ADD issuer TINYBLOB; diff --git a/OpenIDConnect/sql/AddSubject.sql b/OpenIDConnect/sql/AddSubject.sql new file mode 100644 index 00000000..76ff53d8 --- /dev/null +++ b/OpenIDConnect/sql/AddSubject.sql @@ -0,0 +1 @@ +ALTER TABLE /*_*/user ADD subject TINYBLOB; diff --git a/OpenIDConnect/src/OpenIDConnect.php b/OpenIDConnect/src/OpenIDConnect.php new file mode 100644 index 00000000..869c1555 --- /dev/null +++ b/OpenIDConnect/src/OpenIDConnect.php @@ -0,0 +1,375 @@ +<?php + +/* + * Copyright (c) 2015-2018 The MITRE Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +use \MediaWiki\Session\SessionManager; +use \MediaWiki\Auth\AuthManager; +use \Jumbojett\OpenIDConnectClient; + +class OpenIDConnect extends PluggableAuth { + + private $subject; + private $issuer; + + const OIDC_SUBJECT_SESSION_KEY = 'OpenIDConnectSubject'; + const OIDC_ISSUER_SESSION_KEY = 'OpenIDConnectIssuer'; + + /** + * @since 1.0 + * + * @param int &$id + * @param string &$username + * @param string &$realname + * @param string &$email + * @param string &$errorMessage + * @return bool true if user is authenticated, false otherwise + */ + public function authenticate( &$id, &$username, &$realname, &$email, + &$errorMessage ) { + if ( !array_key_exists( 'SERVER_PORT', $_SERVER ) ) { + wfDebug( "in authenticate, server port not set" . PHP_EOL ); + return false; + } + + if ( !isset( $GLOBALS['wgOpenIDConnect_Config'] ) ) { + wfDebug( "wgOpenIDConnect_Config not set" . PHP_EOL ); + return false; + } + + try { + + $session = SessionManager::getGlobalSession(); + + $iss = $session->get( 'iss' ); + + if ( !is_null( $iss ) ) { + + if ( isset( $_REQUEST['code'] ) && isset( $_REQUEST['status'] ) ) { + $session->remove( 'iss' ); + } + + if ( isset( $GLOBALS['wgOpenIDConnect_Config'][$iss] ) ) { + + $config = $GLOBALS['wgOpenIDConnect_Config'][$iss]; + + if ( !isset( $config['clientID'] ) || + !isset( $config['clientsecret'] ) ) { + wfDebug( "OpenID Connect: clientID or clientsecret not set for " . $iss ); + $params = [ + "uri" => urlencode( $_SERVER['REQUEST_URI'] ), + "query" => urlencode( $_SERVER['QUERY_STRING'] ) + ]; + self::redirect( "Special:SelectOpenIDConnectIssuer", + $params, true ); + return false; + } + + } else { + wfDebug( 'Issuer ' . $iss . + ' does not exist in wgOpeIDConnect_Config'. PHP_EOL ); + return false; + } + + } else { + + $iss_count = count( $GLOBALS['wgOpenIDConnect_Config'] ); + + if ( $iss_count < 1 ) { + return false; + } + + if ( $iss_count == 1 ) { + + $iss = array_keys( $GLOBALS['wgOpenIDConnect_Config'] ); + $iss = $iss[0]; + + $values = array_values( $GLOBALS['wgOpenIDConnect_Config'] ); + $config = $values[0]; + + if ( !isset( $config['clientID'] ) || + !isset( $config['clientsecret'] ) ) { + wfDebug( "OpenID Connect: clientID or clientsecret not set for " . + $iss ); + return false; + } + + } else { + + $params = [ + "uri" => urlencode( $_SERVER['REQUEST_URI'] ), + "query" => urlencode( $_SERVER['QUERY_STRING'] ) + ]; + self::redirect( "Special:SelectOpenIDConnectIssuer", + $params, true ); + return false; + } + } + + $clientID = $config['clientID']; + $clientsecret = $config['clientsecret']; + + $oidc = new OpenIDConnectClient( $iss, $clientID, $clientsecret ); + if ( isset( $_REQUEST['forcelogin'] ) ) { + $oidc->addAuthParam( [ 'prompt' => 'login' ] ); + } + if ( isset( $config['authparam'] ) && + is_array( $config['authparam'] ) ) { + $oidc->addAuthParam( $config['authparam'] ); + } + if ( isset( $config['scope'] ) ) { + $scope = $config['scope']; + if ( is_array( $scope ) ) { + foreach ( $scope as $s ) { + $oidc->addScope( $s ); + } + } else { + $oidc->addScope( $scope ); + } + } + if ( isset( $config['proxy'] ) ) { + $oidc->setHttpProxy( $config['proxy'] ); + } + if ( $oidc->authenticate() ) { + + $preferred_username = + $oidc->requestUserInfo( + isset( $config['preferred_username'] ) ? + $config['preferred_username'] : + "preferred_username" + ); + $realname = $oidc->requestUserInfo( "name" ); + $email = $oidc->requestUserInfo( "email" ); + $this->subject = $oidc->requestUserInfo( 'sub' ); + $this->issuer = $oidc->getProviderURL(); + + $username = $this->getName( $this->subject, $this->issuer ); + if ( !is_null( $username ) ) { + return true; + } + + if ( $GLOBALS['wgOpenIDConnect_MigrateUsersByEmail'] === true ) { + list( $id, $username ) = $this->getMigratedIdByEmail( $email ); + if ( !is_null( $id ) ) { + $this->saveExtraAttributes( $id ); + wfDebug( "Migrated user " . $username . " by email: " . $email ); + return true; + } + } elseif ( $GLOBALS['wgOpenIDConnect_MigrateUsersByUserName'] === true ) { + $id = $this->getMigratedIdByUserName( $preferred_username ); + if ( !is_null( $id ) ) { + $this->saveExtraAttributes( $id ); + wfDebug( "Migrated user by username: " . $preferred_username ); + $username = $preferred_username; + return true; + } + } + + $username = self::getAvailableUsername( $preferred_username, + $realname, $email, $this->subject ); + + $authManager = Authmanager::singleton(); + $authManager->setAuthenticationSessionData( + self::OIDC_SUBJECT_SESSION_KEY, $this->subject ); + $authManager->setAuthenticationSessionData( + self::OIDC_ISSUER_SESSION_KEY, $this->issuer ); + return true; + + } else { + $session->clear(); + return false; + } + } catch ( Exception $e ) { + wfDebug( $e->__toString() . PHP_EOL ); + $session->clear(); + return false; + } + } + + /** + * @since 1.0 + * + * @param User &$user + */ + public function deauthenticate( User &$user ) { + if ( $GLOBALS['wgOpenIDConnect_ForceLogout'] === true ) { + $returnto = 'Special:UserLogin'; + $params = [ 'forcelogin' => 'true' ]; + self::redirect( $returnto, $params ); + } + } + + /** + * @since 1.0 + * + * @param int $id user id + */ + public function saveExtraAttributes( $id ) { + $authManager = Authmanager::singleton(); + if ( is_null( $this->subject ) ) { + $this->subject = $authManager->getAuthenticationSessionData( + self::OIDC_SUBJECT_SESSION_KEY ); + $authManager->removeAuthenticationSessionData( + self::OIDC_SUBJECT_SESSION_KEY ); + } + if ( is_null( $this->issuer ) ) { + $this->issuer = $authManager->getAuthenticationSessionData( + self::OIDC_ISSUER_SESSION_KEY ); + $authManager->removeAuthenticationSessionData( + self::OIDC_ISSUER_SESSION_KEY ); + } + $dbw = wfGetDB( DB_MASTER ); + $dbw->update( 'user', + [ + 'subject' => $this->subject, + 'issuer' => $this->issuer + ], [ + 'user_id' => $id + ], __METHOD__ + ); + } + + private static function getName( $subject, $issuer ) { + $dbr = wfGetDB( DB_REPLICA ); + $row = $dbr->selectRow( 'user', + [ 'user_name' ], + [ + 'subject' => $subject, + 'issuer' => $issuer + ], __METHOD__ + ); + if ( $row === false ) { + return null; + } else { + return $row->user_name; + } + } + + private static function getMigratedIdByUserName( $username ) { + $nt = Title::makeTitleSafe( NS_USER, $username ); + if ( is_null( $nt ) ) { + return null; + } + $username = $nt->getText(); + $dbr = wfGetDB( DB_REPLICA ); + $row = $dbr->selectRow( 'user', + [ 'user_id' ], + [ + 'user_name' => $username, + 'subject' => null, + 'issuer' => null + ], + __METHOD__ + ); + if ( $row === false ) { + return null; + } else { + return $row->user_id; + } + } + + private static function getMigratedIdByEmail( $email ) { + wfDebug( "Matching user to email " . $email ); + $dbr = wfGetDB( DB_REPLICA ); + $row = $dbr->selectRow( 'user', + [ + 'user_id', + 'user_name' + ], + [ + 'user_email' => $email, + 'subject' => null, + 'issuer' => null + ], + __METHOD__, + [ + // if multiple matching accounts, use the oldest one + 'ORDER BY' => 'user_registration', + 'LIMIT' => 1 + ] + ); + if ( $row === false ) { + return [ null, null ]; + } else { + return [ $row->user_id, $row->user_name ]; + } + } + + private static function getAvailableUsername( $preferred_username, + $realname, $email, $subject ) { + if ( strlen( $preferred_username ) > 0 ) { + $name = $preferred_username; + } elseif ( strlen( $realname ) > 0 && + $GLOBALS['wgOpenIDConnect_UseRealNameAsUserName'] === true ) { + $name = $realname; + } elseif ( strlen( $email ) > 0 && + $GLOBALS['wgOpenIDConnect_UseEmailNameAsUserName'] === true ) { + $pos = strpos( $email, '@' ); + if ( $pos !== false && $pos > 0 ) { + $name = substr( $email, 0, $pos ); + } else { + $name = $email; + } + } + $nt = Title::makeTitleSafe( NS_USER, $name ); + if ( is_null( $nt ) ) { + $name = "User"; + } elseif ( is_null( User::idFromName( $name ) ) ) { + return $nt->getText(); + } else { + $name = $nt->getText(); + } + $count = 1; + while ( !is_null( User::idFromName( $name . $count ) ) ) { + $count++; + } + return $name . $count; + } + + private static function redirect( $page, $params = null, $doExit = false ) { + $title = Title::newFromText( $page ); + if ( is_null( $title ) ) { + $title = Title::newMainPage(); + } + $url = $title->getFullURL(); + if ( is_array( $params ) && count( $params ) > 0 ) { + foreach ( $params as $key => $value ) { + $url = wfAppendQuery( $url, $key . '=' . $value ); + } + } + header( 'Location: ' . $url ); + if ( $doExit ) { + exit; + } + } + + /** + * Implements LoadExtensionSchemaUpdates hook. + * + * @param DatabaseUpdater $updater + */ + public static function loadExtensionSchemaUpdates( $updater ) { + $dir = $GLOBALS['wgExtensionDirectory'] . '/OpenIDConnect/sql/'; + $updater->addExtensionField( 'user', 'subject', $dir . '/AddSubject.sql' ); + $updater->addExtensionField( 'user', 'issuer', $dir . '/AddIssuer.sql' ); + } +} diff --git a/OpenIDConnect/src/SelectOpenIDConnectIssuer.php b/OpenIDConnect/src/SelectOpenIDConnectIssuer.php new file mode 100644 index 00000000..62199215 --- /dev/null +++ b/OpenIDConnect/src/SelectOpenIDConnectIssuer.php @@ -0,0 +1,103 @@ +<?php + +/* + * Copyright (c) 2015-2018 The MITRE Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +class SelectOpenIDConnectIssuer extends UnlistedSpecialPage { + + public function __construct() { + parent::__construct( 'SelectOpenIDConnectIssuer' ); + } + + /** + * @inheritDoc + */ + public function execute( $param ) { + if ( isset( $GLOBALS['wgOpenIDConnect_Config'] ) && + isset( $_REQUEST['uri'] ) && isset( $_REQUEST['query'] ) ) { + + if ( isset( $_REQUEST['iss'] ) ) { + $url = urldecode( $_REQUEST['uri'] ); + if ( strlen( $_REQUEST['query'] ) > 0 ) { + $url .= "?" . urldecode( $_REQUEST['query'] ); + } + if ( session_id() == '' ) { + wfSetupSession(); + } + $_SESSION['iss'] = $_REQUEST['iss']; + $GLOBALS['wgOut']->redirect( $url ); + } else { + + $request = $this->getRequest(); + $this->setHeaders(); + + $title = + Title::newFromText( "Special:SelectOpenIDConnectIssuer" ); + $urlbase = $title->getFullURL(); + $urlbase .= "?uri=" . urlencode( $_REQUEST['uri'] ); + $urlbase .= "&query=" . urlencode( $_REQUEST['query'] ); + $urlbase .= "&iss="; + + $html = Html::openElement( 'div', [ 'style' => 'text-align:center' ] ); + $html .= Html::openElement( 'table' ); + $html .= Html::openElement( 'tr' ); + $GLOBALS['wgOut']->AddHtml( $html ); + + foreach ( $GLOBALS['wgOpenIDConnect_Config'] as $iss => $data ) { + $html = Html::openElement( 'td' ); + $html .= Html::openElement( 'table', [ 'style' => 'padding:20px;' ] ); + $html .= Html::openElement( 'tr' ); + if ( isset( $data['icon'] ) ) { + $html .= Html::openElement( 'td', + [ 'style' => 'text-align:center;' ] ); + $html .= Html::openElement( 'a', [ 'href' => $urlbase . $iss ] ); + $html .= Html::openElement( 'img', [ 'src' => $data['icon'] ] ); + $html .= Html::closeElement( 'img' ); + $html .= Html::closeElement( 'a' ); + $html .= Html::closeElement( 'td' ); + $html .= Html::closeElement( 'tr' ); + $html .= Html::openElement( 'tr' ); + } + $html .= Html::openElement( 'td', + [ 'style' => 'text-align:center;' ] ); + $html .= Html::openElement( 'a', [ 'href' => $urlbase . $iss ] ); + if ( isset( $data['name'] ) ) { + $html .= $data['name']; + } else { + $html .= $iss; + } + $html .= Html::closeElement( 'a' ); + $html .= Html::closeElement( 'td' ); + $html .= Html::closeElement( 'tr' ); + $html .= Html::closeElement( 'table' ); + $html .= Html::closeElement( 'td' ); + $GLOBALS['wgOut']->AddHtml( $html ); + } + + $html = Html::closeElement( 'tr' ); + $html .= Html::closeElement( 'table' ); + $html .= Html::closeElement( 'div' ); + $GLOBALS['wgOut']->AddHtml( $html ); + } + } + } +} diff --git a/OpenIDConnect/version b/OpenIDConnect/version new file mode 100644 index 00000000..a25699de --- /dev/null +++ b/OpenIDConnect/version @@ -0,0 +1,4 @@ +OpenIDConnect: REL1_31 +2020-05-25T18:25:51 + +baea47f |