diff --git a/roles/mediawiki/files/OpenIDConnect.php b/roles/mediawiki/files/OpenIDConnect.php deleted file mode 100644 index 4798f23698..0000000000 --- a/roles/mediawiki/files/OpenIDConnect.php +++ /dev/null @@ -1,496 +0,0 @@ -get( 'iss' ); - - if ( $iss !== null ) { - - 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'] ) ) { - wfDebugLog( 'OpenID Connect', - 'OpenID Connect: clientID or clientsecret not set for ' . $iss . - '.' . PHP_EOL ); - $params = [ - 'uri' => urlencode( $_SERVER['REQUEST_URI'] ), - 'query' => urlencode( $_SERVER['QUERY_STRING'] ) - ]; - self::redirect( 'Special:SelectOpenIDConnectIssuer', - $params, true ); - return false; - } - - } else { - wfDebugLog( 'OpenID Connect', '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'] ) ) { - wfDebugLog( 'OpenID Connect', - 'OpenID Connect: clientID or clientsecret not set for ' . - $iss . '.' . PHP_EOL ); - 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 ( isset( $config['verifyHost'] ) ) { - $oidc->setVerifyHost( $config['verifyHost'] ); - } - if ( isset( $config['verifyPeer'] ) ) { - $oidc->setVerifyPeer( $config['verifyPeer'] ); - } - $redirectURL = - SpecialPage::getTitleFor( 'PluggableAuthLogin' )->getFullURL(); - $oidc->setRedirectURL( $redirectURL ); - wfDebugLog( 'OpenID Connect', 'Redirect URL: ' . $redirectURL ); - if ( $oidc->authenticate() ) { - - if(!in_array("signed_fpca", $oidc->requestUserInfo('groups'))) { - $errorMessage = 'You need to have signed the FPCA'; - return false; - } - /* - * Enable the following block to require the equivalent of CLA+1 - * - if(!in_array("fedora-contributor", $oidc->requestUserInfo('groups'))) { - $errorMessage = 'You need to be in at least one group'; - return false; - } - */ - - $realname = $oidc->requestUserInfo( 'name' ); - $email = $oidc->requestUserInfo( 'email' ); - $this->subject = $oidc->requestUserInfo( 'sub' ); - $this->issuer = $oidc->getProviderURL(); - wfDebugLog( 'OpenID Connect', 'Real name: ' . $realname . - ', Email: ' . $email . ', Subject: ' . $this->subject . - ', Issuer: ' . $this->issuer ); - - list( $id, $username ) = - $this->findUser( $this->subject, $this->issuer ); - if ( $id !== null ) { - wfDebugLog( 'OpenID Connect', - 'Found user with matching subject and issuer.' . PHP_EOL ); - return true; - } - - wfDebugLog( 'OpenID Connect', - 'No user found with matching subject and issuer.' . PHP_EOL ); - - if ( $GLOBALS['wgOpenIDConnect_MigrateUsersByEmail'] === true ) { - wfDebugLog( 'OpenID Connect', 'Checking for email migration.' . - PHP_EOL ); - list( $id, $username ) = $this->getMigratedIdByEmail( $email ); - if ( $id !== null ) { - $this->saveExtraAttributes( $id ); - wfDebugLog( 'OpenID Connect', 'Migrated user ' . $username . - ' by email: ' . $email . '.' . PHP_EOL ); - return true; - } - } - - $preferred_username = $this->getPreferredUsername( $config, $oidc, - $realname, $email ); - wfDebugLog( 'OpenID Connect', 'Preferred username: ' . - $preferred_username . PHP_EOL ); - - if ( $GLOBALS['wgOpenIDConnect_MigrateUsersByUserName'] === true ) { - wfDebugLog( 'OpenID Connect', 'Checking for username migration.' . - PHP_EOL ); - $id = $this->getMigratedIdByUserName( $preferred_username ); - if ( $id !== null ) { - $this->saveExtraAttributes( $id ); - wfDebugLog( 'OpenID Connect', 'Migrated user by username: ' . - $preferred_username . '.' . PHP_EOL ); - $username = $preferred_username; - return true; - } - } - - $username = self::getAvailableUsername( $preferred_username, - $realname, $email ); - - wfDebugLog( 'OpenID Connect', 'Available username: ' . - $username . PHP_EOL ); - - $authManager = Authmanager::singleton(); - $authManager->setAuthenticationSessionData( - self::OIDC_SUBJECT_SESSION_KEY, $this->subject ); - $authManager->setAuthenticationSessionData( - self::OIDC_ISSUER_SESSION_KEY, $this->issuer ); - return true; - } - - } catch ( Exception $e ) { - wfDebugLog( 'OpenID Connect', $e->__toString() . PHP_EOL ); - $errorMessage = $e->__toString(); - $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 ( $this->subject === null ) { - $this->subject = $authManager->getAuthenticationSessionData( - self::OIDC_SUBJECT_SESSION_KEY ); - $authManager->removeAuthenticationSessionData( - self::OIDC_SUBJECT_SESSION_KEY ); - } - if ( $this->issuer === null ) { - $this->issuer = $authManager->getAuthenticationSessionData( - self::OIDC_ISSUER_SESSION_KEY ); - $authManager->removeAuthenticationSessionData( - self::OIDC_ISSUER_SESSION_KEY ); - } - $dbw = wfGetDB( DB_MASTER ); - $dbw->upsert( - 'openid_connect', - [ - 'oidc_user' => $id, - 'oidc_subject' => $this->subject, - 'oidc_issuer' => $this->issuer - ], - [ - [ 'oidc_user' ] - ], - [ - 'oidc_subject' => $this->subject, - 'oidc_issuer' => $this->issuer - ], - __METHOD__ - ); - } - - private static function findUser( $subject, $issuer ) { - $dbr = wfGetDB( DB_REPLICA ); - $row = $dbr->selectRow( - [ - 'user', - 'openid_connect' - ], - [ - 'user_id', - 'user_name' - ], - [ - 'oidc_subject' => $subject, - 'oidc_issuer' => $issuer - ], - __METHOD__, - [], - [ - 'openid_connect' => [ 'JOIN', [ 'user_id=oidc_user' ] ] - ] - ); - if ( $row === false ) { - return [ null, null ]; - } else { - return [ $row->user_id, $row->user_name ]; - } - } - - private static function getPreferredUsername( $config, $oidc, $realname, - $email ) { - if ( isset( $config['preferred_username'] ) ) { - wfDebugLog( 'OpenID Connect', 'Using ' . $config['preferred_username'] . - ' attribute for preferred username.' . PHP_EOL ); - $preferred_username = - $oidc->requestUserInfo( $config['preferred_username'] ); - } else { - $preferred_username = $oidc->requestUserInfo( 'preferred_username' ); - } - if ( strlen( $preferred_username ) > 0 ) { - // do nothing - } elseif ( strlen( $realname ) > 0 && - $GLOBALS['wgOpenIDConnect_UseRealNameAsUserName'] === true ) { - $preferred_username = $realname; - } elseif ( strlen( $email ) > 0 && - $GLOBALS['wgOpenIDConnect_UseEmailNameAsUserName'] === true ) { - $pos = strpos( $email, '@' ); - if ( $pos !== false && $pos > 0 ) { - $preferred_username = substr( $email, 0, $pos ); - } else { - $preferred_username = $email; - } - } else { - return null; - } - $nt = Title::makeTitleSafe( NS_USER, $preferred_username ); - if ( $nt === null ) { - return null; - } - return $nt->getText(); - } - - private static function getMigratedIdByUserName( $username ) { - $nt = Title::makeTitleSafe( NS_USER, $username ); - if ( $nt === null ) { - wfDebugLog( 'OpenID Connect', - 'Invalid preferred username for migration: ' . $username . '.' . - PHP_EOL ); - return null; - } - $username = $nt->getText(); - $dbr = wfGetDB( DB_REPLICA ); - $row = $dbr->selectRow( - [ - 'user', - 'openid_connect' - ], - [ - 'user_id' - ], - [ - 'user_name' => $username, - 'oidc_user' => null - ], - __METHOD__, - [], - [ - 'openid_connect' => [ 'LEFT JOIN', [ 'user_id=oidc_user' ] ] - ] - ); - if ( $row !== false ) { - return $row->user_id; - } - return null; - } - - private static function getMigratedIdByEmail( $email ) { - wfDebugLog( 'OpenID Connect', 'Matching user to email ' . $email . '.' . - PHP_EOL ); - $dbr = wfGetDB( DB_REPLICA ); - $row = $dbr->selectRow( - [ - 'user', - 'openid_connect' - ], - [ - 'user_id', - 'user_name', - 'oidc_user' - ], - [ - 'user_email' => $email - ], - __METHOD__, - [ - // if multiple matching accounts, use the oldest one - 'ORDER BY' => 'user_registration' - ], - [ - 'openid_connect' => [ 'LEFT JOIN', [ 'user_id=oidc_user' ] ] - ] - ); - if ( $row !== false && $row->oidc_user === null ) { - return [ $row->user_id, $row->user_name ]; - } - return [ null, null ]; - } - - private static function getAvailableUsername( $preferred_username ) { - if ( $preferred_username === null ) { - $preferred_username = 'User'; - } - - if ( User::idFromName( $preferred_username ) === null ) { - return $preferred_username; - } - - $count = 1; - while ( User::idFromName( $preferred_username . $count ) !== null ) { - $count++; - } - return $preferred_username . $count; - } - - private static function redirect( $page, $params = [], $doExit = false ) { - $title = Title::newFromText( $page ); - if ( $title === null ) { - $title = Title::newMainPage(); - } - $url = $title->getFullURL( $params ); - header( 'Location: ' . $url ); - if ( $doExit ) { - exit; - } - } - - /** - * Implements LoadExtensionSchemaUpdates hook. - * - * @param DatabaseUpdater $updater - */ - public static function loadExtensionSchemaUpdates( $updater ) { - $dir = $GLOBALS['wgExtensionDirectory'] . '/OpenIDConnect/sql/'; - $type = $updater->getDB()->getType(); - $updater->addExtensionTable( 'openid_connect', - $dir . $type . '/AddTable.sql' ); - $updater->addExtensionUpdate( [ [ __CLASS__, 'migrateSubjectAndIssuer' ], - $updater ] ); - } - - /** - * Migrate subject and issuer columns from user table to openid_connect - * table. - * - * @param DatabaseUpdater $updater - */ - public static function migrateSubjectAndIssuer( $updater ) { - if ( $updater->getDB()->fieldExists( 'user', 'subject', __METHOD__ ) && - $updater->getDB()->fieldExists( 'user', 'issuer', __METHOD__ ) ) { - $maintenance = new FakeMaintenance(); - $task = $maintenance->runChild( - 'MigrateOIDCSubjectAndIssuerFromUserTable' ); - if ( $task->execute() ) { - $dir = $GLOBALS['wgExtensionDirectory'] . '/OpenIDConnect/sql/'; - $type = $updater->getDB()->getType(); - $patch = $dir . $type . '/DropColumnsFromUserTable.sql'; - $updater->modifyField( 'user', 'subject', $patch, true ); - } - } else { - $updater->output( - '...user table does not have subject and issuer columns.' . PHP_EOL ); - } - } -} diff --git a/roles/mediawiki/tasks/main.yml b/roles/mediawiki/tasks/main.yml index ac3e908888..0df1c4f40f 100644 --- a/roles/mediawiki/tasks/main.yml +++ b/roles/mediawiki/tasks/main.yml @@ -51,6 +51,9 @@ - packages - mediawiki +# mediawiki-OpenIDConnect here is pulled from the infra repo, which is also patched to add +# the FPCA check, and returns the message to the user: +# "You need to have signed the FPCA to log into the wiki" - name: install needed packages (fedora only) package: name={{ item }} state=present with_items: