Florianschmidtwelzow has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/358081 )
Change subject: Add backend services and functions for allowed domains in the database ...................................................................... Add backend services and functions for allowed domains in the database Instead of requiring the users of this extension to manage the list of allowed domains, from which the users can login with Google, in an array in the Local- Settings.php file, this change implements to store this list in the database in a new database table. To allow different backends for the list of allowed domains, a new interface, AllowedDomainsStore, is created, which allows different implementations for the puprose of checking, if a specific domain is allowed or not (no matter where the list of allowed domains is stored or comes from). There're three implementations, which are inspired by the SiteStore implementations. One for the currently used global array, one for a list out of the database and one which uses a BagOStuff cache and another AllowedDomainsStore as a backend. There's currently no api or user interface to manage the list of allowed domains, therefore it has to be done in the database directly. There will be changes in the future to allow to manage the list through an api and/or through a user interface. The list, when the database is used, will be cached for up to 1 hour, so changes will not take effect immediately at the moment. Bug: T166423 Change-Id: I629534b97b0eddbc195c87b9a86d015c2e07a694 --- M extension.json A includes/Constants.php M includes/GoogleLogin.body.php M includes/GoogleLogin.hooks.php A includes/ServiceWiring.php A includes/alloweddomains/AllowedDomainsStore.php A includes/alloweddomains/ArrayAllowedDomainsStore.php A includes/alloweddomains/CachedAllowedDomainsStore.php A includes/alloweddomains/DBAllowedDomainsStore.php A includes/alloweddomains/MutableAllowedDomainsStore.php A includes/sql/googlelogin_allowed_domains.sql 11 files changed, 314 insertions(+), 5 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/GoogleLogin refs/changes/81/358081/1 diff --git a/extension.json b/extension.json index 5a0349e..2843a81 100644 --- a/extension.json +++ b/extension.json @@ -49,12 +49,17 @@ "GoogleLogin\\Specials\\SpecialManageGoogleLogin": "includes/specials/SpecialManageGoogleLogin.php", "GoogleLogin\\GoogleLoginHooks": "includes/GoogleLogin.hooks.php", "GoogleLogin\\GoogleUser": "includes/GoogleUser.php", + "GoogleLogin\\Constants": "includes/Constants.php", "GoogleLogin\\Auth\\GooglePrimaryAuthenticationProvider": "includes/auth/GooglePrimaryAuthenticationProvider.php", "GoogleLogin\\Auth\\GoogleServerAuthenticationRequest": "includes/auth/GoogleServerAuthenticationRequest.php", "GoogleLogin\\Auth\\GoogleAuthenticationRequest": "includes/auth/GoogleAuthenticationRequest.php", "GoogleLogin\\Auth\\GoogleRemoveAuthenticationRequest": "includes/auth/GoogleRemoveAuthenticationRequest.php", "GoogleLogin\\Auth\\GoogleUserInfoAuthenticationRequest": "includes/auth/GoogleUserInfoAuthenticationRequest.php", "GoogleLogin\\AllowedDomains\\AllowedDomainsStore": "includes/alloweddomains/AllowedDomainsStore.php", + "GoogleLogin\\AllowedDomains\\MutableAllowedDomainsStore": "includes/alloweddomains/MutableAllowedDomainsStore.php", + "GoogleLogin\\AllowedDomains\\ArrayAllowedDomainsStore": "includes/alloweddomains/ArrayAllowedDomainsStore.php", + "GoogleLogin\\AllowedDomains\\DBAllowedDomainsStore": "includes/alloweddomains/DBAllowedDomainsStore.php", + "GoogleLogin\\AllowedDomains\\CachedAllowedDomainsStore": "includes/alloweddomains/CachedAllowedDomainsStore.php", "GoogleLogin\\AllowedDomains\\EmailDomain": "includes/alloweddomains/EmailDomain.php", "ApiGoogleLoginInfo": "includes/api/ApiGoogleLoginInfo.php" }, @@ -150,9 +155,13 @@ "GLAppId": "", "GLAllowedDomains": "", "GLAllowedDomainsStrict": false, + "GLAllowedDomainsDB": false, "GLAPIKey": "", "GLEnableEchoEvents": true }, + "ServiceWiringFiles": [ + "includes/ServiceWiring.php" + ], "load_composer_autoloader": true, "manifest_version": 1 } diff --git a/includes/Constants.php b/includes/Constants.php new file mode 100644 index 0000000..e9e58d7 --- /dev/null +++ b/includes/Constants.php @@ -0,0 +1,14 @@ +<?php +/** + * Created by PhpStorm. + * User: florian + * Date: 09.06.17 + * Time: 19:40 + */ + +namespace GoogleLogin; + + +class Constants { + const SERVICE_ALLOWED_DOMAINS_STORE = 'GoogleLogin.AllowedDomainsStore'; +} \ No newline at end of file diff --git a/includes/GoogleLogin.body.php b/includes/GoogleLogin.body.php index 534e6f1..2e918cf 100755 --- a/includes/GoogleLogin.body.php +++ b/includes/GoogleLogin.body.php @@ -5,7 +5,11 @@ use ConfigFactory; use Google_Client; +use GoogleLogin\AllowedDomains\AllowedDomainsStore; +use GoogleLogin\AllowedDomains\CachedAllowedDomainsStore; use GoogleLogin\AllowedDomains\EmailDomain; +use GoogleLogin\AllowedDomains\MutableAllowedDomainsStore; +use MediaWiki\MediaWikiServices; class GoogleLogin { /** @var $mGoogleClient Stores an instance of GoogleClient */ @@ -51,13 +55,13 @@ */ public static function isValidDomain( $mailDomain ) { $glConfig = self::getGLConfig(); - if ( is_array( $glConfig->get( 'GLAllowedDomains' ) ) ) { + /** @var AllowedDomainsStore $allowedDomainsStore */ + $allowedDomainsStore = MediaWikiServices::getInstance() + ->getService( Constants::SERVICE_ALLOWED_DOMAINS_STORE ); + if ( $allowedDomainsStore !== null ) { $domain = new EmailDomain( $mailDomain, $glConfig->get( 'GLAllowedDomainsStrict' ) ); if ( - in_array( - $domain->getHost(), - $glConfig->get( 'GLAllowedDomains' ) - ) + $allowedDomainsStore->contains( $domain ) ) { return true; } diff --git a/includes/GoogleLogin.hooks.php b/includes/GoogleLogin.hooks.php index ba5d01e..267107b 100644 --- a/includes/GoogleLogin.hooks.php +++ b/includes/GoogleLogin.hooks.php @@ -20,6 +20,7 @@ public static function onLoadExtensionSchemaUpdates( \DatabaseUpdater $updater = null ) { $config = ConfigFactory::getDefaultInstance()->makeConfig( 'main' ); + $extConfig = GoogleLogin::getGLConfig(); // Don't create tables on a shared database $sharedDB = $config->get( 'SharedDB' ); if ( @@ -38,6 +39,11 @@ 'user_id', "$sql/user_google_user_user_id_index.sql" ); } + + if ( $extConfig->get( 'GLAllowedDomainsDB' ) ) { + $schema = "$sql/googlelogin_allowed_domains.sql"; + $updater->addExtensionUpdate( [ 'addTable', 'googlelogin_allowed_domains', $schema, true ] ); + } return true; } diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php new file mode 100644 index 0000000..073229b --- /dev/null +++ b/includes/ServiceWiring.php @@ -0,0 +1,26 @@ +<?php + +use MediaWiki\MediaWikiServices; +use GoogleLogin\GoogleLogin; +use GoogleLogin\AllowedDomains\CachedAllowedDomainsStore; +use GoogleLogin\AllowedDomains\DBAllowedDomainsStore; +use GoogleLogin\AllowedDomains\ArrayAllowedDomainsStore; +use GoogleLogin\Constants; + +return [ + Constants::SERVICE_ALLOWED_DOMAINS_STORE => function ( MediaWikiServices $services ) { + $glConfig = GoogleLogin::getGLConfig(); + if ( + is_array( $glConfig->get( 'GLAllowedDomains' ) ) && + !$glConfig->get( 'GLAllowedDomainsDB' ) + ) { + return new ArrayAllowedDomainsStore( $glConfig->get( 'GLAllowedDomains' ) ); + } elseif ( $glConfig->get( 'GLAllowedDomainsDB' ) ) { + $dbBackedStore = new DBAllowedDomainsStore( $services->getDBLoadBalancer() ); + $cache = wfGetCache( wfIsHHVM() ? CACHE_ACCEL : CACHE_ANYTHING ); + + return new CachedAllowedDomainsStore( $dbBackedStore, $cache ); + } + return null; + } +]; \ No newline at end of file diff --git a/includes/alloweddomains/AllowedDomainsStore.php b/includes/alloweddomains/AllowedDomainsStore.php new file mode 100644 index 0000000..5dc3a1c --- /dev/null +++ b/includes/alloweddomains/AllowedDomainsStore.php @@ -0,0 +1,29 @@ +<?php + +namespace GoogleLogin\AllowedDomains; + +/** + * Interface AllowedDomainsStore + * + * Defines, how a store should behave, which provides a list of allowed domains, which can be + * used to login with a Google account. + * + * @package GoogleLogin\AllowedDomains + */ +interface AllowedDomainsStore { + + /** + * Checks, if the given EmailDomain is allowed to be used for login or not. + * + * @param EmailDomain $domain + * @return boolean + */ + function contains( EmailDomain $domain ); + + /** + * Returns the complete list of allowed domains of this store as an array. + * + * @return array + */ + function getAllowedDomains(); +} \ No newline at end of file diff --git a/includes/alloweddomains/ArrayAllowedDomainsStore.php b/includes/alloweddomains/ArrayAllowedDomainsStore.php new file mode 100644 index 0000000..cf6f96c --- /dev/null +++ b/includes/alloweddomains/ArrayAllowedDomainsStore.php @@ -0,0 +1,32 @@ +<?php + +namespace GoogleLogin\AllowedDomains; + +use Config; + +/** + * Class GlobalAllowedDomainsStore + * + * An implementation of the AllowedDomainStore interface, which is backed by the an array passed + * to it, e.g. a configured array of allowed domains. + * + * @package GoogleLogin\AllowedDomains + */ +class ArrayAllowedDomainsStore implements AllowedDomainsStore { + private $allowedDomains; + + public function __construct( array $allowedDomains ) { + $this->allowedDomains = $allowedDomains; + } + + public function contains( EmailDomain $domain ) { + return in_array( + $domain->getHost(), + $this->allowedDomains + ); + } + + public function getAllowedDomains() { + return $this->allowedDomains; + } +} \ No newline at end of file diff --git a/includes/alloweddomains/CachedAllowedDomainsStore.php b/includes/alloweddomains/CachedAllowedDomainsStore.php new file mode 100644 index 0000000..60ac2ab --- /dev/null +++ b/includes/alloweddomains/CachedAllowedDomainsStore.php @@ -0,0 +1,72 @@ +<?php + +namespace GoogleLogin\AllowedDomains; + +use BagOStuff; + +class CachedAllowedDomainsStore implements AllowedDomainsStore, MutableAllowedDomainsStore { + /** + * @var AllowedDomainsStore + */ + private $rawStore; + /** + * @var BagOStuff + */ + private $cache; + /** + * @var string|null + */ + private $cacheKey; + private $allowedDomains; + + const CACHE_VERSION = '1'; + + public function __construct( AllowedDomainsStore $rawStore, BagOStuff $cache ) { + $this->cache = $cache; + $this->rawStore = $rawStore; + } + + /** + * Constructs a cache key to use for caching the list of allowed domains. + * + * @return string The cache key. + */ + private function getCacheKey() { + if ( $this->cacheKey === null ) { + $type = 'CachedAllowedDomainsStore#' . self::CACHE_VERSION; + $this->cacheKey = $this->cache->makeKey( "googlelogin/allowedDomains/$type" ); + } + return $this->cacheKey; + } + + /** + * @return array + */ + public function getAllowedDomains() { + if ( $this->allowedDomains === null ) { + $this->allowedDomains = $this->cache->get( $this->getCacheKey() ); + if ( !is_object( $this->allowedDomains ) ) { + $this->allowedDomains = $this->rawStore->getAllowedDomains(); + $this->cache->set( $this->getCacheKey(), $this->allowedDomains, 3600 ); + } + } + return $this->allowedDomains; + } + + public function contains( EmailDomain $domain ) { + return in_array( $domain->getHost(), $this->getAllowedDomains() ); + } + + public function add( EmailDomain $domain ) { + if ( !$this->rawStore instanceof MutableAllowedDomainsStore ) { + throw new \InvalidArgumentException( + 'The backend domain store does not support to change the store data.' ); + } + $this->rawStore->add( $domain ); + } + + public function clear() { + $this->cache->delete( $this->getCacheKey() ); + $this->allowedDomains = null; + } +} \ No newline at end of file diff --git a/includes/alloweddomains/DBAllowedDomainsStore.php b/includes/alloweddomains/DBAllowedDomainsStore.php new file mode 100644 index 0000000..521e208 --- /dev/null +++ b/includes/alloweddomains/DBAllowedDomainsStore.php @@ -0,0 +1,82 @@ +<?php + +namespace GoogleLogin\AllowedDomains; + +use Wikimedia\Rdbms\LoadBalancer; + +/** + * Class DBAllowedDomainsStore + * + * Implementation of the AllowedDomainsStore interface, which is backed by the database. The + * allowed domain list is stored and manageable in the database of MediaWiki. For performance + * reasons, you should use the CachedAllowedDomainsStore implementation and wrap an instance of + * this class into it. + * + * @package GoogleLogin\AllowedDomains + */ +class DBAllowedDomainsStore implements AllowedDomainsStore { + private $dbLoadBalancer; + private $allowedDomains; + + public function __construct( LoadBalancer $dbLoadBalancer ) { + $this->dbLoadBalancer = $dbLoadBalancer; + } + + private function loadDomains() { + if ( $this->allowedDomains !== null ) { + return; + } + $dbr = $this->dbLoadBalancer->getConnection( DB_REPLICA ); + + $res = $dbr->select( + 'googlelogin_allowed_domains', + [ + 'gl_allowed_domain_id', + 'gl_allowed_domain', + ], + '', + __METHOD__ + ); + + foreach ( $res as $row ) { + $this->allowedDomains[$row->gl_allowed_domain_id] = $row->gl_allowed_domain; + } + } + + public function getAllowedDomains() { + $this->loadDomains(); + + return $this->allowedDomains; + } + + public function contains( EmailDomain $domain ) { + $this->loadDomains(); + + return in_array( $domain->getHost(), $this->allowedDomains ); + } + + public function add( EmailDomain $domain ) { + if ( $this->contains( $domain ) ) { + return -1; + } + $dbw = $this->dbLoadBalancer->getConnection( DB_MASTER ); + $dbw->insert( + 'googlelogin_allowed_domains', + [ + 'gl_allowed_domain' => $domain->getHost() + ], + __METHOD__ + ); + + return $dbw->insertId(); + } + + public function clear() { + $dbw = $this->dbLoadBalancer->getConnection( DB_MASTER ); + + $ok = $dbw->delete( 'googlelogin_allowed_domains', '*', __METHOD__ ); + $this->allowedDomains = null; + + return $ok; + } +} \ No newline at end of file diff --git a/includes/alloweddomains/MutableAllowedDomainsStore.php b/includes/alloweddomains/MutableAllowedDomainsStore.php new file mode 100644 index 0000000..c40bc92 --- /dev/null +++ b/includes/alloweddomains/MutableAllowedDomainsStore.php @@ -0,0 +1,27 @@ +<?php + +namespace GoogleLogin\AllowedDomains; + +/** + * Interface MutableAllowedDomainsStore + * + * A domain store, which can be modified during runtime, where the changes persist between requests. + * + * @package GoogleLogin\AllowedDomains + */ +interface MutableAllowedDomainsStore { + /** + * Adds the host of the given EmailDomain to the store. + * + * @param EmailDomain $domain + * @return void + */ + function add( EmailDomain $domain ); + + /** + * Cleans the store and deletes all entries from it. + * + * @return void + */ + function clear(); +} \ No newline at end of file diff --git a/includes/sql/googlelogin_allowed_domains.sql b/includes/sql/googlelogin_allowed_domains.sql new file mode 100644 index 0000000..50af8b2 --- /dev/null +++ b/includes/sql/googlelogin_allowed_domains.sql @@ -0,0 +1,8 @@ +-- +-- extension Google Login SQL schema +-- +CREATE TABLE /*$wgDBprefix*/googlelogin_allowed_domains ( + gl_allowed_domain_id int unsigned AUTO_INCREMENT NOT NULL PRIMARY KEY, + gl_allowed_domain varchar(255) NOT NULL, + KEY(gl_allowed_domain) +) /*$wgDBTableOptions*/; -- To view, visit https://gerrit.wikimedia.org/r/358081 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I629534b97b0eddbc195c87b9a86d015c2e07a694 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/GoogleLogin Gerrit-Branch: master Gerrit-Owner: Florianschmidtwelzow <florian.schmidt.stargatewis...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits