jenkins-bot has submitted this change and it was merged. Change subject: Add feature to restrict E-Maildomains ......................................................................
Add feature to restrict E-Maildomains Enable the restriction of access via GoogleLogin to allowed E-Maildomains. Introducing $wgGLAllowedDomains as config array in LocalSettings.php to specify those allowed E-Maildomains. With $wgGLAllowedDomainsStrict in LocalSettings.php can configured, if the domain must exactly match (test.example.com don't macth example.com if activated). Added configuration variables into GoogleLogin.php with short explanation and a default value. Bug: 67220 Change-Id: I00b9cb9b844d5fbebe3bcb12f101d91ff609014c --- M .gitignore M GoogleLogin.php M SpecialGoogleLogin.php A cache/README M i18n/de.json M i18n/en.json M i18n/qqq.json 7 files changed, 211 insertions(+), 23 deletions(-) Approvals: Florianschmidtwelzow: Looks good to me, approved jenkins-bot: Verified diff --git a/.gitignore b/.gitignore index 5664cb5..09f6347 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ vendor/* composer.phar +cache/* \ No newline at end of file diff --git a/GoogleLogin.php b/GoogleLogin.php index 52a62dc..532a235 100644 --- a/GoogleLogin.php +++ b/GoogleLogin.php @@ -53,3 +53,35 @@ $wgHooks['UserLogoutComplete'][] = 'GoogleLoginHooks::onUserLogoutComplete'; $wgHooks['LoadExtensionSchemaUpdates'][] = 'GoogleLoginHooks::onLoadExtensionSchemaUpdates'; $wgHooks['UserLoginForm'][] = 'GoogleLoginHooks::onUserLoginForm'; + + // Configuration settings defaults + + /** + * The Secret key of Google developer console + */ + $wgGLSecret = ''; + + /** + * The App ID of the web application to use for GoogleLogin + */ + $wgGLAppId = ''; + + /** + * Which domains are allowed to login (or create/merge an account) with GoogleLogin + * default: empty string -> all domains allowed + * to allow special domains, create an array with all allowed domains, example: + * array( 'example.com' ); + */ + $wgGLAllowedDomains = ''; + + /** + * If $wgGoogleAllowedDomains restrict to specified domains, use strict mode? Means: + * Only the exact specified domains are allowed, e.g. if test.example.com is allowed and strict + * mode is enabled, example.com isn't allowed (if strict mode is of, it is allowed) + */ + $wgGLAllowedDomainsStrict = false; + + /** + * If the user creates an account via GoogleLogin, show this as a reason in log? + */ + $wgGLShowCreateReason = false; diff --git a/SpecialGoogleLogin.php b/SpecialGoogleLogin.php index 218da19..cdbefe4 100644 --- a/SpecialGoogleLogin.php +++ b/SpecialGoogleLogin.php @@ -124,29 +124,180 @@ $request = $this->getRequest(); $user = $this->getUser(); $googleIdExists = $db->GoogleIdExists( $userInfo['id'] ); - if ( !$googleIdExists ) { - if ( !$user->isLoggedIn() ) { - $this->createGoogleUserForm( $userInfo, $db ); - } else { - $this->GoogleUserForm( 'Merge' ); - } - } else { - if ( $user->isLoggedIn() ) { - if ( $user->getId() != $googleIdExists['id'] ) { - $out->addWikiMsg( 'googlelogin-link-other' ); + if ( + $this->isValidDomain( + $this->getHost( + $userInfo['emails'][0]['value'] + ) + ) + ) { + if ( !$googleIdExists ) { + if ( !$user->isLoggedIn() ) { + $this->createGoogleUserForm( $userInfo, $db ); } else { - if ( $request->getVal( 'code' ) !== null ) { - // if user logged into google account and is already logged in and linked, - // show the whole special page, not only a button - bug 67486 - $out->redirect( $this->getPageTitle()->getLocalUrl() ); - } else { - $this->GoogleUserForm( 'Unlink' ); - } + $this->GoogleUserForm( 'Merge' ); } } else { - $this->loginGoogleUser( $googleIdExists['id'] ); + if ( $user->isLoggedIn() ) { + if ( $user->getId() != $googleIdExists['id'] ) { + $out->addWikiMsg( 'googlelogin-link-other' ); + } else { + if ( $request->getVal( 'code' ) !== null ) { + // if user logged into google account and is already logged in and linked, + // show the whole special page, not only a button - bug 67486 + $out->redirect( $this->getPageTitle()->getLocalUrl() ); + } else { + $this->GoogleUserForm( 'Unlink' ); + } + } + } else { + $this->loginGoogleUser( $googleIdExists['id'] ); + } } + } else { + $out->addWikiMsg( + 'googlelogin-unallowed-domain', + $this->getHost( + $userInfo['emails'][0]['value'] + ) + ); } + } + + /** + * Creates the TLD cache from which the valid tld of mail domain comes from. + * @param string $cacheFile The file to create the cache too (must be writeable for the + * webserver!) + * @param int $max_tl How deep the domain list is (enclude example.co.uk (2) or + * example.lib.wy.us (3)?) + * @see http://www.programmierer-forum.de/domainnamen-ermitteln-t244185.htm + */ + function createTLDCache( $cacheFile, $max_tl = 2 ) { + $cacheFolder = str_replace( basename( $cacheFile ), '', $cacheFile ); + if ( !is_writable( $cacheFolder ) ) { + throw new MWException( $cacheFolder . ' is not writeable!' ); + } + $tlds = file( + 'http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1' + ); + if ( $tlds === false ) { + throw new MWException( 'Domainlist can not be downloaded!' ); + } + $i = 0; + // remove unnecessary lines + foreach ( $tlds as $tld ) { + $tlds[ $i ] = trim( $tld ); + /** + empty + comments + top level domains + is overboard + */ + if ( + !$tlds[ $i ] || + $tld[0] == '/' || + strpos( $tld, '.' ) === false || + substr_count( $tld, '.' ) >= $max_tl + ) { + unset( $tlds[ $i ] ); + } + $i++; + } + $tlds = array_values( $tlds ); + file_put_contents( + $cacheFile, + "<?php\n" . '$tlds = ' . str_replace( + array( ' ', "\n" ), + '', + var_export( $tlds, true ) + ) . ";\n?" . ">" + ); + } + + /** + * Returns the domain and tld (without subdomains) of the provided E-Mailadress + * @param string $domain The domain part of the email address to extract from. + * @return string The Tld and domain of $domain without subdomains + * @see http://www.programmierer-forum.de/domainnamen-ermitteln-t244185.htm + */ + function getHost( $domain = '' ) { + global $wgGLAllowedDomainsStrict; + if ( $wgGLAllowedDomainsStrict ) { + $domain = explode( '@', $domain ); + // we can trust google to give us only valid email address, so give the last element + return array_pop( $domain ); + } + // for parse_url() + $domain = + !isset($domain[5]) || + ( + $domain[3] != ':' && + $domain[4] != ':' && + $domain[5] != ':' + ) ? 'http://' . $domain : $domain; + // remove "/path/file.html", "/:80", etc. + $domain = parse_url( $domain, PHP_URL_HOST ); + // separate domain level + $lvl = explode('.', $domain); // 0 => www, 1 => example, 2 => co, 3 => uk + // set levels + krsort( $lvl ); // 3 => uk, 2 => co, 1 => example, 0 => www + $lvl = array_values( $lvl ); // 0 => uk, 1 => co, 2 => example, 3 => www + $_1st = $lvl[0]; + $_2nd = isset( $lvl[1] ) ? $lvl[1] . '.' . $_1st : false; + $_3rd = isset( $lvl[2] ) ? $lvl[2] . '.' . $_2nd : false; + $_4th = isset( $lvl[3] ) ? $lvl[3] . '.' . $_3rd : false; + + // tld extract + if ( !file_exists(__DIR__ . "/cache/tld.txt") ) { + $this->createTLDCache( __DIR__ . "/cache/tld.txt" ); + } + require ( __DIR__ . "/cache/tld.txt" ); + $tlds = array_flip( $tlds ); + if ( // fourth level is TLD + $_4th && + !isset( $tlds[ '!' . $_4th ] ) && + ( + isset( $tlds[ $_4th ] ) || + isset( $tlds[ '*.' . $_3rd ] ) + ) + ) { + $domain = isset( $lvl[4] ) ? $lvl[4] . '.' . $_4th : false; + } elseif ( // third level is TLD + $_3rd && + !isset( $tlds[ '!' . $_3rd ] ) && + ( + isset($tlds[ $_3rd ]) || + isset( $tlds[ '*.' . $_2nd ] ) + ) + ) { + $domain = $_4th; + } elseif ( // second level is TLD + !isset( $tlds[ '!' . $_2nd ] ) && + ( + isset( $tlds[ $_2nd ] ) || + isset( $tlds[ '*.' . $_1st ] ) + ) + ) { + $domain = $_3rd; + } else { // first level is TLD + $domain = $_2nd; + } + return $domain; + } + /** + * If restriction of domains is enabled, check if the user E-Mail is valid before do anything. + * @param string $mailDomain The domain of email address + * @return boolean + */ + private function isValidDomain( $mailDomain ) { + global $wgGLAllowedDomains; + if ( is_array( $wgGLAllowedDomains ) ) { + if ( in_array( $mailDomain, $wgGLAllowedDomains ) ) { + return true; + } + return false; + } + return true; } /** @@ -180,8 +331,8 @@ */ private function prepareClient( $client ) { global $wgGLSecret, $wgGLAppId, $wgGLAppName; - $client->setClientId( $wgGoogleAppId ); - $client->setClientSecret( $wgGoogleSecret ); + $client->setClientId( $wgGLAppId ); + $client->setClientSecret( $wgGLSecret ); $client->setRedirectUri( WebRequest::detectServer().$this->getPageTitle()->getLocalUrl() ); $client->addScope( "https://www.googleapis.com/auth/userinfo.profile" ); $client->addScope( "https://www.googleapis.com/auth/userinfo.email" ); @@ -414,7 +565,7 @@ $user->setCookies(); // create a log entry for the created user - bug 67245 $createReason = ''; - if ( $wgGoogleShowCreateReason ) { + if ( $wgGLShowCreateReason ) { $createReason = 'via [[' . $this->getPageTitle() . '|Google Login]]'; } diff --git a/cache/README b/cache/README new file mode 100644 index 0000000..a173c87 --- /dev/null +++ b/cache/README @@ -0,0 +1 @@ +This folder is for files the Script generates automatically. \ No newline at end of file diff --git a/i18n/de.json b/i18n/de.json index 4374f96..564bbe7 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -10,6 +10,7 @@ "googlelogin-desc": "Stellt eine [[Special:GoogleLogin|Spezialseite]] zur Verfügung, die es Nutzern erlaubt, sich mit Ihrem Google-Konto anzumelden.", "googlelogin-parerror": "Die aufgerufene Seite existiert nicht. Bitte gehen Sie zurück und versuchen die Aktion erneut.", "googlelogin-generic-error": "Oops, da war ein Problem. Bitte gehen Sie zurück und versuchen die Aktion erneut. Fehlernachricht: $1", + "googlelogin-unallowed-domain": "Die E-Mail-Domain, welche von deiner primären E-Mailadresse verwendet wird ($1), ist für die Anmeldung mit GoogleLogin in diesem Wiki nicht erlaubt.", "googlelogin-form-choosename-title": "Wähle Benutzername", "googlelogin-form-choosename": "Wähle einen Benutzernamen um ein Konto zu erstellen", "googlelogin-form-choosename-finish-title": "Benutzerkonto erstellen", diff --git a/i18n/en.json b/i18n/en.json index dc796cd..0816910 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -8,6 +8,7 @@ "googlelogin-desc": "Provides a [[Special:GoogleLogin|Special page]] to allow users to login with their Google accounts", "googlelogin-parerror": "The requested page doesn't exist. Please go back and try the action again.", "googlelogin-generic-error": "Oops, there was an error. Please go back and try again. Message: $1", + "googlelogin-unallowed-domain": "The email domain used for the primary email address of your Google account ($1) isn't allowed to login into this wiki.", "googlelogin-form-choosename-title": "Choose username", "googlelogin-form-choosename": "Please choose your username to create a wiki account", "googlelogin-form-choosename-finish-title": "Create wiki account", @@ -30,7 +31,7 @@ "googlelogin-linkstatus": "Link status", "googlelogin-linked": "linked", "googlelogin-unlinked": "not linked", - "googlelogin-link-other": "Your Google account is already linked to another user. Your Google account can linked only to one wiki account. Please unlink the connection to your other wiki account or contact an administrator, if you haven't another wiki account.", + "googlelogin-link-other": "Your Google account is already linked to another user. Please unlink the connection or contact an administrator, if you have no other wiki account.", "googlelogin-success-merge": "Congratulations! Your wiki account is now linked to your Google account.", "googlelogin-success-unlink": "Congratulations! Your wiki account isn't linked to your Google account anymore." -} \ No newline at end of file +} diff --git a/i18n/qqq.json b/i18n/qqq.json index 919401b..cfaff6d 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -9,6 +9,7 @@ "googlelogin-desc": "{{desc|name=Google Login|url=http://www.mediawiki.org/wiki/Extension:GoogleLogin}}", "googlelogin-parerror": "Error message when a Subpage of Special:GoogleLogin is requested, which does not exist.", "googlelogin-generic-error": "Generic error message for errors with no specific error message.\n\nParameters:\n* $1 - a short description of the error (e.g. Database error)", + "googlelogin-unallowed-domain": "The domain of the user isn't allowed to use with Google Login, show this as an error message. $1 is the E-Maildomain used.", "googlelogin-form-choosename-title": "Title of SpecialPage when the user can create a new user and has to choose an Username.", "googlelogin-form-choosename": "Title of fieldset to explain shortly, what the user has to do (choose username).", "googlelogin-form-choosename-finish-title": "Title of Subpage 'Finish' after the Useraccount is successful created.", -- To view, visit https://gerrit.wikimedia.org/r/142741 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I00b9cb9b844d5fbebe3bcb12f101d91ff609014c Gerrit-PatchSet: 12 Gerrit-Project: mediawiki/extensions/GoogleLogin Gerrit-Branch: master Gerrit-Owner: Florianschmidtwelzow <florian.schmidt.wel...@t-online.de> Gerrit-Reviewer: Florianschmidtwelzow <florian.schmidt.wel...@t-online.de> Gerrit-Reviewer: Siebrand <siebr...@kitano.nl> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits