Skip to content

Instantly share code, notes, and snippets.

@michaelp85
Created February 6, 2013 02:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save michaelp85/4719735 to your computer and use it in GitHub Desktop.
Save michaelp85/4719735 to your computer and use it in GitHub Desktop.
MediaWiki external authentication plugin interface to ExpressionEngine 2.2+
<?php
/**
* External authentication plugin interface to ExpressionEngine 2.2+
*
* Basic setup:
* - Save this file into extensions/ExtExpressionEngineAuthDB/ExtExpressionEngineAuthDB.php
* - Insert LocalSettings.php requirements, see below for what they are.
*
* This extension is a derivation of http://www.mediawiki.org/wiki/Extension:ExtAuthDB
*
* @author Michael Pasqualone (http://www.mpasqualone.com)
*/
$wgExtensionCredits['parserhook'][] = array (
'name' => 'ExtExpressionEngineAuthDB',
'author' => '[http://www.mpasqualone.com]',
'description' => 'Authenticate users against an external ExpressionEngine 2 install',
'url' => '',
'version' => '0.1',
);
require_once("$IP/includes/AuthPlugin.php");
class ExtExpressionEngineAuthDB extends AuthPlugin
{
// From ExpressionEngine Auth.php class
private $hash_algos = array(
128 => 'sha512',
64 => 'sha256',
40 => 'sha1',
32 => 'md5'
);
/**
* LocalSettings.php requirements:
*
* $wgExtExpressionEngineAuthDB_host = ''; // Database host
* $wgExtExpressionEngineAuthDB_user = ''; // Database username
* $wgExtExpressionEngineAuthDB_pass = ''; // Database password
* $wgExtExpressionEngineAuthDB_db = ''; // ExpressionEngine database name
* require_once( "$IP/extensions/ExtExpressionEngineAuthDB/ExtExpressionEngineAuthDB.php" );
* $wgAuth = new ExtExpressionEngineAuthDB();
*
* @return Object Database
*/
private function connectDb()
{
$host = $GLOBALS['wgExtExpressionEngineAuthDB_host'];
$user = $GLOBALS['wgExtExpressionEngineAuthDB_user'];
$pass = $GLOBALS['wgExtExpressionEngineAuthDB_pass'];
$db = $GLOBALS['wgExtExpressionEngineAuthDB_db'];
$dbh = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
//wfDebug("ExtExpressionEngineAuthDB::connectDb() : DB failed to open\n");
return $dbh;
}
/**
* Check whether there exists a user account with the given name.
* The name will be normalized to MediaWiki's requirements, so
* you might need to munge it (for instance, for lowercase initial
* letters).
*
* @param $username String: username.
* @return bool
* @public
*/
function userExists( $username ) {
# Override this!
return true;
}
/**
* Check if a username+password pair is a valid login.
* The name will be normalized to MediaWiki's requirements, so
* you might need to munge it (for instance, for lowercase initial
* letters).
*
* @param $username String: username.
* @param $password String: user password.
* @return bool
* @public
*/
function authenticate( $username, $password )
{
//$db = $this->connectToDB();
//$hash_password = $db->selectRow($this->userTable,array ($this->userPswrd), array ($this->userLogin => $username ), __METHOD__ );
//if ($password == $hash_password->{$this->userPswrd}) {
// return true;
//}
// Convert username to lowercase
$username = strtolower( $username );
// First, connect to ExpressionEngine and get member info
$dbh = $this->connectDb();
$stmt = $dbh->query("SELECT password, salt, unique_id, crypt_key FROM exp_members WHERE username = '$username'");
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$member = $stmt->fetch();
if($stmt->rowCount() !== 1)
{
return false;
}
$m_salt = $member['salt'];
$m_pass = $member['password'];
$h_byte_size = strlen($m_pass);
$hashed_pair = $this->hash_password($password, $m_salt, $h_byte_size);
if ($hashed_pair === FALSE OR $m_pass !== $hashed_pair['password'])
{
return FALSE;
}
// Officially a valid user, but are they as secure as possible?
// ----------------------------------------------------------------
return true;
}
/**
* Set the domain this plugin is supposed to use when authenticating.
*
* @param $domain String: authentication domain.
* @public
*/
function setDomain( $domain ) {
$this->domain = $domain;
}
/**
* Check to see if the specific domain is a valid domain.
*
* @param $domain String: authentication domain.
* @return bool
* @public
*/
function validDomain( $domain ) {
# Override this!
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() {
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 ) {
return true;
}
/**
* Update user information in the external authentication database.
* Return true if successful.
*
* @param $user User object.
* @return bool
* @public
*/
function updateExternalDB( $user ) {
// $db = $this->connectToDB();
// $euser = $db->selectRow($this->userTable,array ( '*' ), array ($this->userLogin => $user->mName ), __METHOD__ );
// $user->setRealName($euser->{$this->userRealN});
// $user->setEmail($euser->{$this->userEmail});
// $user->mEmailAuthenticated = wfTimestampNow();
//$user->saveSettings();
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() {
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 ) {
# Override this to do something.
}
/**
* If you want to munge the case of an account name before the final
* check, now is your chance.
*/
function getCanonicalName( $username ) {
return $username;
}
/**
* Hash Password function from ExpressionEngine Auth.php class
*/
private function hash_password($password, $salt = FALSE, $h_byte_size = FALSE)
{
// Even for md5, collisions usually happen above 1024 bits, so
// we artifically limit their password to reasonable size.
if ( ! $password OR strlen($password) > 250)
{
return FALSE;
}
// No hash function specified? Use the best one
// we have access to in this environment.
if ($h_byte_size === FALSE)
{
reset($this->hash_algos);
$h_byte_size = key($this->hash_algos);
}
elseif ( ! isset($this->hash_algos[$h_byte_size]))
{
// What are they feeding us? This can happen if
// they move servers and the new environment is
// less secure. Nothing we can do but fail. Hard.
die('Fatal Error: No matching hash algorithm.');
}
// No salt? (not even blank), we'll regenerate
if ($salt === FALSE)
{
$salt = '';
// The salt should never be displayed, so any
// visible ascii character is fair game.
for ($i = 0; $i < $h_byte_size; $i++)
{
$salt .= chr(mt_rand(33, 126));
}
}
elseif (strlen($salt) !== $h_byte_size)
{
// they passed us a salt that isn't the right length,
// this can happen if old code resets a new password
// ignore it
$salt = '';
}
return array(
'salt' => $salt,
'password' => hash($this->hash_algos[$h_byte_size], $salt.$password)
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment