Extension:Wget Authentication

From MediaWiki.org
Jump to: navigation, search
MediaWiki extensions manual - list
Crystal Clear action run.png

Release status: stable

Implementation User identity
Description Allows you to securely use wget to authenticate against a pre-existing HTTP authentication login system.
Last version 1.0
MediaWiki 1.13.1
License GPL
Download http://hinespot.net/content/WgetAuthentication.txt

Check usage (experimental)

Contents

[edit] What can this extension do?

This allows you to securely exec() a wget url within mediawiki to authenticate your users (by way of HTTP authentication, as you've probably guessed). Once the username and password are received, this extension creates a pipe between php and a fork'd wget and proceeds to retreive a URL to the effect of: https://username:password@yourwebserver.com. Once wget returns, the extension will check wget's exit code and return success only if the code is zero.



[edit] Installation

First edit the file extensions/WgetAuthentication.php and paste the code that you see below.

To install this extension, add the following to LocalSettings.php:

require_once("$IP/extensions/WgetAuthentication.php");
 
/* This line is critical. Make sure you include it */
$wgAuth = new WgetAuthentication();

[edit] Configuration parameters

Now, add the following configuration parameters to your LocalSettings.php file....

/* Provide a list of possible domains that you would like the plugin to allow
 * the user to select from. They're just chosen names to be displayed on the
 * login form and used to index into the next two arrays.
 */
$wgetDomains = array("Domain One", "Domain Two");
 
/* For each domain, provide the actual URL to which the user's username and
 * password should be sent. Note: this is not just a domain name, it's the full
 * URL of the HTTP-authenticated location in which you would normally get a
 * pop-up login box if you were using a web browser.
 */
 
$wgetDomainURLS = array(
                "Domain One" => "yourwebserverone.com/login/at/this/url",
                "Domain Two" => "yourwebservertwo.com/login/at/another/url"
                );
 
/* Indicate whether or not you want 'https' login or 'http' logins for each
 * domain 
 */
$wgetSecurity = array(
                "Domain One" => "https",
                "Domain Two" => "http"
                );
 
/* Optional: you may specify the domain names of the above URLS to use for
 * filling in the email address of each user if a user is logging in for the
 * very first time. The plugin will set their email address as already confirmed
 * automatically when the account is created.
 */
$wgetEmailDomains = array(
                "Domain One" => "yourwebdomainone.com",
                "Domain Two" => "yourwebdomaintwo.com"
                );
 
/* Optional: this plugin doesn't support local authentication right now, so
 * you might find the following configuration setting useful:
 */
 
$wgGroupPermissions['*'    ]['createaccount']    = false;

[edit] Code

<?php
# Copyright (C) 2009 Michael R. Hines
# <http://www.mediawiki.org/wiki/User:Darkbeethoven>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# http://www.gnu.org/copyleft/gpl.html

/**
 *  Wget Authentication plugin.
 *  Does not support local accounts right now. Does not support NEW usernames,
 *  BUT will auto-create an account if the user has been
 *  authenticated when logging in for the first time.
 */
 
$wgExtensionCredits['other'][] = array(
        'name' => 'Wget Authentication Plugin',
        'version' => '1.0',
        'author' => 'Michael R. Hines',
        'description' => 'Allows you to securely use wget to authenticate against a pre-existing HTTP authentication login system.',
        'url' => 'http://hinespot.net/content/WgetAuthenticationtxt',
        );
 
class WgetAuthentication extends AuthPlugin {
        function WgetAuthentication() {
        }
        /**
         * Check whether there exists a user account with the given name.
         *
         * @param $username String: username.
         * @return bool
         * @public
         */
        function userExists( $username ) {
                /* Just assume the user exists and try to authenticate.
                 * We have no way to test otherwise.
                 */
                return true;
        }
 
        /**
         * Check if a username+password pair is a valid login.
         *
         * @param $username String: username.
         * @param $password String: user password.
         * @return bool
         * @public
         */
        function authenticate( $username, $password ) {
            global $_SERVER, $wgOut;
            global $wgetDomains, $wgetDomainURLS, $wgetSecurity;
 
                /* Disallow empty passwords */
 
                if ( '' == $password ) {
                        $wgOut->addHTML("<h2>Empty passwords not allowed.</h2>");
                        return false;
                }
 
 
                /* convert all usernames to lowercase first */
                $username = strtolower( $username );
 
                $rc = "";
                $auth = "";
                $descriptorspec = array(
                        0 => array("pipe", "r"),  // stdin
                        1 => array("pipe", "w"));  // stdout
 
                /* 
                 * Setup a two-way pipe to talk between php and the fork/exec'd
                 * wget process later. Wget will take the authentication URL
                 * from standard input and the shell will spit out the exit code
                 * on standard output.
                 */
                $process = proc_open("wget -i - -o /dev/null -O /dev/null; echo $?", $descriptorspec, $pipes);
 
                /* Make sure the fork/exec succeeded and the pipes are setup */
                if (!is_resource($process)) {
                        $wgOut->addHTML("<h2>Failed to internally setup the authentication process please contact your system administrator.</h2>");
                        return false;
                }
 
                /* Grab the selected domain name */
                $dom = $_SESSION['wsDomain'];
 
                /* Make sure the domain is valid (could be 'invaliddomain' */
                if(!$this->validDomain($dom)) {
                        $wgOut->addHTML("<h2>Invalid Domain name: $dom");
                        return false;
                }
 
                /* Setup the authentication URL based on LocalSetting parameters
                 */
                $auth = "";
                $auth .= $wgetSecurity[$dom]."://";
                $auth .= urlencode($username).":".urlencode($password)."@";
                $auth .= $wgetDomainURLS[$dom];
 
                /* wget is blocking. feed the beast. */
                $err = fwrite($pipes[0], $auth);
 
                if(!err)
                        return false;
 
                fclose($pipes[0]);
 
                /* wget is still blocking with the exit code. he needs to use the bathroom. */
                while($s = fgets($pipes[1], 1024))
                        $rc .= $s;
 
                fclose($pipes[1]);
 
                /* Check exit code. Success if zero */
                if($rc != 0)
                        return false;
 
                return true;
        }
 
        /**
         * Modify options in the login template.
         *
         * @param $template UserLoginTemplate object.
         * @public
         */
        function modifyUITemplate( &$template ) {
                global $wgetDomainURLS, $wgetSecurity, $wgetDomains, $wgAuth, $wgOut;
 
                /* Did you setup LocalSettings.php properly?? */
 
                if(!isset($wgetDomainURLS) || !isset($wgetSecurity) || !isset($wgetDomains)) {
                        $wgAuth = new AuthPlugin();
                        $wgOut->addHTML("<h2>NOTE: WgetAuthentication is not enabled. You are missing configuration parameters in LocalSettings.php</h2>");
 
                        return;
                }
 
                /* Support for multiple domains */
                $template->set( 'usedomain', true );
                $template->set( 'domainnames', $wgetDomains );
 
                /* Disable new user account creation */
                $template->set( 'create', false );
 
                $template->set('useemail', false);
                $template->set('remember', false);
        }
 
        /**
         * Set the domain this plugin is supposed to use when authenticating.
         *
         * @param $domain String: authentication domain.
         * @public
         */
        function setDomain( $domain ) {
                $_SESSION['wsDomain'] = $domain;
        }
 
        /**
         * Check to see if the specific domain is a valid domain.
         *
         * @param $domain String: authentication domain.
         * @return bool
         * @public
         */
        function validDomain( $domain ) {
                global $wgetDomainURLS, $wgetSecurity, $wgetDomains, $wgAuth, $wgOut;
 
                /* Make sure the domain is valid */
                if(in_array($domain, $wgetDomains))
                        return true;
 
                return false;
        }
 
        /**
         * When a user logs in, optionally fill in preferences and such.
         * For instance, you might pull the email address or real name from the
         * external user database.
         *
         * The User object is passed by reference so it can be modified; don't
         * forget the & on your function declaration.
         *
         * @param User $user
         * @public
         */
        function updateUser( &$user ) {
                /* Nothing to do here, really. We've setup initUser, though
                 * later */
                return true;
        }
 
 
        /**
         * Return true if the wiki should create a new local account automatically
         * when asked to login a user who doesn't exist locally but does in the
         * external auth database.
         *
         * If you don't automatically create accounts, you must still create
         * accounts in some way. It's not possible to authenticate without
         * a local account.
         *
         * This is just a question, and shouldn't perform any actions.
         *
         * @return bool
         * @public
         */
        function autoCreate() {
                return true;
        }
 
        /**
         * Can users change their passwords?
         *
         * @return bool
         */
        function allowPasswordChange() {
                /* HTTP-authenticated users should change their passwords
                 * elsewhere.
                 */
                return false;
        }
 
        /**
         * Set the given password in the authentication database.
         * As a special case, the password may be set to null to request
         * locking the password to an unusable value, with the expectation
         * that it will be set later through a mail reset or other method.
         *
         * Return true if successful.
         *
         * @param $user User object.
         * @param $password String: password.
         * @return bool
         * @public
         */
        function setPassword( $user, $password ) {
                /* HTTP-authenticated users should change their passwords
                 * elsewhere.
                 */
                return false;
        }
 
        /**
         * Update user information in the external authentication database.
         * Return true if successful.
         *
         * @param $user User object.
         * @return bool
         * @public
         */
        function updateExternalDB( $user ) {
                /* Just assume it worked. */
                return true;
        }
 
        /**
         * Check to see if external accounts can be created.
         * Return true if external accounts can be created.
         * @return bool
         * @public
         */
        function canCreateAccounts() {
                return false;
        }
 
        /**
         * Add a user to the external authentication database.
         * Return true if successful.
         *
         * @param User $user - only the name should be assumed valid at this point
         * @param string $password
         * @param string $email
         * @param string $realname
         * @return bool
         * @public
         */
        function addUser( $user, $password, $email='', $realname='' ) {
                return false;
        }
 
 
        /**
         * Return true to prevent logins that don't authenticate here from being
         * checked against the local database's password fields.
         *
         * This is just a question, and shouldn't perform any actions.
         *
         * @return bool
         * @public
         */
        function strict() {
                /* local authentication not supported right now */
                return true;
        }
 
        /**
         * Check if a user should authenticate locally if the global authentication fails.
         * If either this or strict() returns true, local authentication is not used.
         *
         * @param $username String: username.
         * @return bool
         * @public
         */
        function strictUserAuth( $username ) {
                /* local authentication not supported right now */
                return true;
        }
 
        /**
         * When creating a user account, optionally fill in preferences and such.
         * For instance, you might pull the email address or real name from the
         * external user database.
         *
         * The User object is passed by reference so it can be modified; don't
         * forget the & on your function declaration.
         *
         * @param $user User object.
         * @param $autocreate bool True if user is being autocreated on login
         * @public
         */
        function initUser( &$user, $autocreate=false ) {
            global $_SESSION, $wgetDomainURLS, $wgetSecurity, $wgetDomains,
                   $wgAuth, $wgOut, $wgetEmailDomains;
 
            /* Fill in the email address on first login? */
            if(!isset($wgetEmailDomains)) {
                return;       
            }
 
 
            $dom = $_SESSION['wsDomain'];
 
            if(!$this->validDomain($dom)) {
                    return;
            }
 
            $user->setEmail(strtolower($user->getName()) 
                            . "@" .  $wgetEmailDomains[$dom]);
 
            $user->mEmailAuthenticated = wfTimestampNow();
            $user->setToken();
            $user->saveSettings();
        }
 
        /**
         * If you want to munge the case of an account name before the final
         * check, now is your chance.
         */
        function getCanonicalName( $username ) {
            /* prevent multiple account names */
            $username = strtolower( $username );
            // uppercase first letter to make MediaWiki happy
            $username = ucfirst($username);
                return $username;
        }
}

[edit] See also

Personal tools
Namespaces
Variants
Actions
Site
Support
Download
Development
Communication
Print/export
Toolbox