Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions config/Farm/CentralAuthUserManagement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

namespace MediaWikiConfig\Farm;

use MediaWiki\Request\WebRequest;
use MediaWikiConfig\MediaWikiConfig;

/**
* Use CentralAuth to manage shared user accounts across wikis.
*
* ## Setup after enabling
*
* 1. `mwutil run CentralAuth:migratePass0.php`
* 2. `mwutil run CentralAuth:migratePass1.php`
* 3. `INSERT INTO global_group_permissions (ggp_group,ggp_permission) VALUES ('steward','globalgrouppermissions'),
* ('steward','globalgroupmembership');`
* 4. `INSERT IGNORE INTO global_user_groups (gug_user, gug_group) VALUES ((SELECT gu_id FROM globaluser WHERE
* gu_name='Admin'), 'steward');`
*/
class CentralAuthUserManagement implements IFarmUserManagement {

/** @inheritDoc */
public function setup( MWCFarm $farm, MediaWikiConfig $mwc ): void {
$mwc->CentralAuth(
$farm->getCentralWiki()
);
$mwc->conf( 'wgCentralAuthLoginWiki', $farm->getCentralWiki() );
$this->enableSUL3( $farm, $mwc );
}

private function enableSUL3( MWCFarm $farm, MediaWikiConfig $mwc ) {
$mwc
->conf( 'wgCentralAuthSharedDomainCallback', fn ( $dbname ) => $this->getAuthDomain( $mwc, $dbname ) )
->conf( 'wgCentralAuthEnableSul3', true )
->conf( 'wgServer', WebRequest::detectServer( true ) )
->cloneConf( 'wgCanonicalServer', 'wgServer' );

if ( $mwc->getConf( 'wgServer' ) === $this->getAuthDomain( $mwc, null ) ) {
$dbName = $mwc->getConf( 'wgDBname' );
$mwc
->conf( 'wgEnableSidebarCache', false )
->conf( 'wgCentralAuthCookieDomain', '' )
->conf( 'wgCookiePrefix', 'auth' )
->conf( 'wgSessionName', 'authSession' )
->conf( 'wgScriptPath', "/$dbName/w" )
->conf( 'wgLoadScript', $mwc->getConf( 'wgScriptPath' ) . '/load.php' )
->conf( 'wgCanonicalServer', $this->getAuthDomain( $mwc, null ) )
->conf( 'wgScript', $mwc->getConf( 'wgScriptPath' ) . '/index.php' )
->conf( 'wgResourceBasePath', "/$dbName/w" )
->conf( 'wgExtensionAssetsPath', $mwc->getConf( 'wgResourceBasePath' ) . '/extensions' )
->conf( 'wgStylePath', $mwc->getConf( 'wgResourceBasePath' ) . '/skins' )
->cloneConf( 'wgLocalStylePath', 'wgStylePath' )
->conf( 'wgArticlePath', "/$dbName/wiki/\$1" )
->conf( 'wgServer', $this->getAuthDomain( $mwc, null ) );
}
}

/** @inheritDoc */
public function overrideWikiExists( MWCFarm $farm, MediaWikiConfig $mwc, string $subdomain ): ?string {
if ( $subdomain !== 'auth' ) {
return null;
}
// Taken from https://github.com/miraheze/mw-config/blob/main/initialise/MirahezeFunctions.php#L287-L298
$requestUri = $_SERVER['REQUEST_URI'];
$pathBits = explode( '/', $requestUri, 3 );
if ( count( $pathBits ) < 3 ) {
trigger_error(
"Invalid request URI (requestUri=$requestUri), can't determine wiki.\n",
E_USER_ERROR
);
}
return $pathBits[1];
}

private function getAuthDomain( MediaWikiConfig $mwc, ?string $dbName ): string {
$port = $mwc->env( 'MW_DOCKER_PORT' );
return "http://auth.localhost:$port" . ( $dbName ? "/$dbName" : '' );
}

}
20 changes: 20 additions & 0 deletions config/Farm/IFarmUserManagement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace MediaWikiConfig\Farm;

use MediaWikiConfig\MediaWikiConfig;

interface IFarmUserManagement {

/**
* Initialize the user management and set all relevant config options.
*/
public function setup( MWCFarm $farm, MediaWikiConfig $mwc ): void;

/**
* Override the check for whether a wiki exists.
* Used for CentralAuth/SUL3.
*/
public function overrideWikiExists( MWCFarm $farm, MediaWikiConfig $mwc, string $subdomain ): ?string;

}
50 changes: 43 additions & 7 deletions config/Farm/MWCFarm.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,35 @@

class MWCFarm {

public const USER_MANAGEMENT_STANDALONE = 1;
public const USER_MANAGEMENT_CENTRAL_AUTH = 2;
// ToDo support wgSharedDB

private readonly IFarmUserManagement $userManagement;

/**
* @param array<string, string> $wikis
* @param array $settings
* @param string $defaultWiki The wiki that will be used for maintenance scripts by default
* @param string $centralWiki The central wiki (will be used for maintenance scripts by default)
* @param int $userManagementType One of the USER_MANAGEMENT_ constants
*/
public function __construct(
private readonly array $wikis,
private array $settings,
private readonly string $defaultWiki,
private readonly string $centralWiki,
private readonly int $userManagementType,
) {
require_once 'IFarmUserManagement.php';
switch ( $this->userManagementType ) {
case self::USER_MANAGEMENT_STANDALONE:
require_once 'StandaloneUserManagement.php';
$this->userManagement = new StandaloneUserManagement();
break;
case self::USER_MANAGEMENT_CENTRAL_AUTH:
require_once 'CentralAuthUserManagement.php';
$this->userManagement = new CentralAuthUserManagement();
break;
}
}

public function apply( MediaWikiConfig $mwc ): void {
Expand All @@ -26,17 +45,23 @@ public function apply( MediaWikiConfig $mwc ): void {
$serverVals[$dbname] = "http://$subdomain.localhost:$port";
}
$this->settings['wgServer'] = $serverVals;
$this->settings['wgArticlePath'] = [
'default' => $mwc->getConf( 'wgArticlePath' ),
];

if ( defined( 'MW_DB' ) ) {
$wikiId = MW_DB;
} elseif ( MW_ENTRY_POINT === 'cli' ) {
$wikiId = $this->defaultWiki;
$wikiId = $this->centralWiki;
} else {
$subdomain = explode( '.', $_SERVER['SERVER_NAME'] )[0];
if ( !array_key_exists( $subdomain, $this->wikis ) ) {
$this->showWikiMap();
} else {
$wikiId = $this->wikis[$subdomain];
$wikiId = $this->userManagement->overrideWikiExists( $this, $mwc, $subdomain );
if ( $wikiId === null ) {
if ( !array_key_exists( $subdomain, $this->wikis ) ) {
$this->showWikiMap();
} else {
$wikiId = $this->wikis[$subdomain];
}
}
}

Expand All @@ -53,6 +78,9 @@ public function apply( MediaWikiConfig $mwc ): void {
}

$mwc->conf( 'wgConf', $siteConfiguration );

// Setup user management after config
$this->userManagement->setup( $this, $mwc );
}

private function showWikiMap(): never {
Expand All @@ -67,4 +95,12 @@ public function getWikis(): array {
return $this->wikis;
}

public function getUserManagement(): IFarmUserManagement {
return $this->userManagement;
}

public function getCentralWiki(): string {
return $this->centralWiki;
}

}
22 changes: 22 additions & 0 deletions config/Farm/StandaloneUserManagement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace MediaWikiConfig\Farm;

use MediaWikiConfig\MediaWikiConfig;

/**
* Every wiki has its own standalone user management system.
*/
class StandaloneUserManagement implements IFarmUserManagement {

/** @inheritDoc */
public function setup( MWCFarm $farm, MediaWikiConfig $mwc ): void {
// Don't do anything, this is already the default behavior of MW
}

/** @inheritDoc */
public function overrideWikiExists( MWCFarm $farm, MediaWikiConfig $mwc, string $subdomain ): ?string {
return null;
}

}
5 changes: 5 additions & 0 deletions config/MWCConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,9 @@ public function setupFarm( MWCFarm $farm ): self {
return $this;
}

public function getFarm(): ?MWCFarm {
global $wgMwcFarm;
return $wgMwcFarm;
}

}
83 changes: 82 additions & 1 deletion config/MWCExtensions.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ public function Analytics(): self {
return $this->ext( 'Analytics' );
}

public function AntiSpoof(): self {
return $this->ext( 'AntiSpoof' );
}

public function ApprovedRevs(): self {
return $this->ext( 'ApprovedRevs' );
}
Expand All @@ -73,6 +77,10 @@ public function AutoCreatePage(): self {
return $this->ext( 'AutoCreatePage' );
}

public function BetaFeatures(): self {
return $this->ext( 'BetaFeatures' );
}

public function Bootstrap(): self {
return $this->ext( 'Bootstrap' );
}
Expand Down Expand Up @@ -100,6 +108,19 @@ public function Cargo(): self {
return $this->ext( 'Cargo' );
}

public function CentralAuth(
string $centralWiki,
): self {
global $wgMwcFarm;
if ( !$wgMwcFarm ) {
throw new Exception( 'Please call setupFarm() before using ' . __METHOD__ . '!' );
}
// Call wfLoadExtension *before* setting the virtual domain mapping and similar settings
$this->ext( 'CentralAuth' );
return $this
->virtualDomainMapping( 'virtual-centralauth', $centralWiki );
}

public function CentralNotice(): self {
return $this
->ext( 'CentralNotice' )
Expand Down Expand Up @@ -153,6 +174,10 @@ public function Cite(): self {
return $this->ext( 'Cite' );
}

public function CodeEditor(): self {
return $this->ext( 'CodeEditor' );
}

public function CodeMirror( CodeMirrorVersion $version = CodeMirrorVersion::V6 ): self {
if ( $version === CodeMirrorVersion::V6 ) {
$this->conf( 'wgCodeMirrorV6', true );
Expand Down Expand Up @@ -342,6 +367,10 @@ public function Gadgets(): self {
}

public function GlobalUserPage( string $apiUrl ): self {
$farm = $this->getFarm();
if ( $farm ) {
$this->conf( 'wgGlobalUserPageDBname', $farm->getCentralWiki() );
}
return $this
->ext( 'GlobalUserPage' )
->conf( 'wgGlobalUserPageAPIUrl', $apiUrl );
Expand All @@ -351,6 +380,10 @@ public function GlobalUserrights(): self {
return $this->ext( 'GlobalUserrights' );
}

public function GlobalWatchlist(): self {
return $this->ext( 'GlobalWatchlist' );
}

public function GrowthExperiments(): self {
// https://www.mediawiki.org/wiki/Extension:GrowthExperiments/developer_setup
return $this
Expand Down Expand Up @@ -443,6 +476,10 @@ public function Lockdown(): self {
return $this->ext( 'Lockdown' );
}

public function Loops(): self {
return $this->ext( 'Loops' );
}

public function Maps(): self {
return $this->ext( 'Maps' );
}
Expand All @@ -453,6 +490,11 @@ public function MassEditRegex(): self {
->grantPermission( 'sysop', 'masseditregex' );
}

public function MediaSearch(): self {
// TODO are there any dependencies or settings?
return $this->ext( 'MediaSearch' );
}

public function MediaUploader(): self {
return $this->ext( 'MediaUploader' );
}
Expand Down Expand Up @@ -611,6 +653,30 @@ public function ProtectSite(): self {
return $this->ext( 'ProtectSite' );
}

public function QuickInstantCommons( ?string $apiUrl = null, ?string $name = null ): self {
if ( $apiUrl !== null ) {
// See https://www.mediawiki.org/wiki/Extension:QuickInstantCommons#Advanced_Configuration
$this->appendToIndexedConfArray( 'wgForeignFileRepos', [
'class' => '\MediaWiki\Extension\QuickInstantCommons\Repo',
'name' => $name ?? 'externalrepowiki',
'directory' => $this->getConf( 'wgUploadDirectory' ),
'apibase' => $apiUrl,
'hashLevels' => 2,
'thumbUrl' => false,
'fetchDescription' => true,
'descriptionCacheExpiry' => 43200,
'transformVia404' => false,
'abbrvThreshold' => 160,
'apiMetadataExpiry' => 60 * 60 * 24,
'disabledMediaHandlers' => [],
] );
}
return $this
->ext( 'QuickInstantCommons' )
->conf( 'wgUseInstantCommons', false )
->conf( 'wgUseQuickInstantCommons', $apiUrl === null );
}

public function QuizGame(): self {
return $this
->SocialProfile()
Expand All @@ -621,6 +687,10 @@ public function RandomImageByCategory(): self {
return $this->ext( 'RandomImageByCategory' );
}

public function RandomSelection(): self {
return $this->ext( 'RandomSelection' );
}

public function RatePage(): self {
return $this->ext( 'RatePage' );
}
Expand Down Expand Up @@ -888,6 +958,17 @@ public function UserVerification(): self {
return $this->ext( 'UserVerification' );
}

public function Variables(): self {
return $this->ext( 'Variables' );
}

public function VariablesLua(): self {
return $this
->Scribunto()
->Variables()
->ext( 'VariablesLua' );
}

public function Video(): self {
return $this->ext( 'Video' );
}
Expand Down Expand Up @@ -953,7 +1034,7 @@ public function WikiCategoryTagCloud(): self {
public function WikiEditor(): self {
return $this
->ext( 'WikiEditor' )
->modConf( 'wgHiddenPrefs', static fn ( &$c ) => $c[] = 'usebetatoolbar' )
->appendToIndexedConfArray( 'wgHiddenPrefs', 'usebetatoolbar' )
->defaultUserOption( 'usebetatoolbar', 1 );
}

Expand Down
Loading