Source for file VBulletin_ExternalAuthDriver.php
Documentation is available at VBulletin_ExternalAuthDriver.php
* VBulletin integration driver.
* @copyright Amiro.CMS. All rights reserved. The changes are undesirable and dangerous.
* VBulletin common auth driver class.
* An associative array with driver specific options
* - 'forum_url' - vBulletin URL;
* - 'db_host' - Database: host;
* - 'db_username' - Database: username;
* - 'db_password' - Database: password;
* - 'db_flags' - Database: client flags (since 6.0.6)
* - 'db_database' - Database: name;
* - 'db_prefix' - Database: tables prefix;
* - 'cookie_ttl' - Cookies: time to live (seconds);
* - 'cookie_path' - Cookies: path;
* - 'secret_key' - Secret hash used for vBulletin authorization through social networks.
'secret_key' => 'Default secret key',
* Link to an external database connection
* Temporary storage for a password
* Returns an instance of VBulletin_ExternalAuthDriver.
* @return VBulletin_ExternalAuthDriver
self::$oInstance = new VBulletin_ExternalAuthDriver();
* Initializes external auth driver.
* @param array $aSettings Settings array
public function init(array $aSettings= array()){
parent::init($aSettings);
// Sets a database connection
if(!$this->_connectToExternalDatabase()){
* Custom handler for on_after_user_create event.
* @param string $name Event name
* @param array $aEvent Event data
* @param string $handlerModId Handler module id
* @param string $srcModId Source module id
public function afterCreate($name, array $aEvent, $handlerModId, $srcModId){
$oUser = isset ($aEvent['oUser']) ? $aEvent['oUser'] : null;
if(is_null($oUser) || !($oUser instanceof Users_TableItem)){
$aEvent['error'] = array(
// Check if user do exist in vBulletin
"FROM `" . $this->aSettings['db_prefix'] . "user` " .
"WHERE `username` = '" . $oUser->login . "'";
if(0 === $userExists){ // If user do not exist in vBulletin, create
$this->_vbCreateUser($oUser->login, $oUser->password, $oUser->email);
}else{ // Else, update the password and email to correspond new ones
$this->_vbUpdateUser($oUser->login, $oUser->password, $oUser->email);
* Custom handler for on_after_user_update event.
* @param string $name Event name
* @param array $aEvent Event data
* @param string $handlerModId Handler module id
* @param string $srcModId Source module id
public function afterUpdate($name, array $aEvent, $handlerModId, $srcModId){
// Protect from the recursive actions
if(AMI_Registry::get('vb_acton', false)){
$oUser = isset ($aEvent['oUser']) ? $aEvent['oUser'] : null;
if(is_null($oUser) || !($oUser instanceof Users_TableItem)){
$aEvent['error'] = array(
// Password is not avaiable from the $oUser object, we'll take it from the Request
$aRequest = $oRequest->getScope();
$password = isset ($aRequest['password']) ? $aRequest['password'] : '';
$this->_vbUpdateUser($oUser->login, $password, $oUser->email);
* Custom handler for on_before_user_login event.
* @param string $name Event name
* @param array $aEvent Event data
* @param string $handlerModId Handler module id
* @param string $srcModId Source module id
public function beforeLogin($name, array $aEvent, $handlerModId, $srcModId){
// We need to save the password, it will be used in "afterLogin" event handler
$this->password = isset ($aEvent['password']) ? $aEvent['password'] : '';
* Custom handler for on_after_user_login event.
* @param string $name Event name
* @param array $aEvent Event data
* @param string $handlerModId Handler module id
* @param string $srcModId Source module id
public function afterLogin($name, array $aEvent, $handlerModId, $srcModId){
// Protect from the recursive actions
if(AMI_Registry::get('vb_acton', false)){
$oUser = isset ($aEvent['oUser']) ? $aEvent['oUser'] : null;
if(is_null($oUser) || !($oUser instanceof Users_TableItem)){
$aEvent['error'] = array(
// We do not have a password property in the $oUser object
// but we can get it from beforeLogin event handler
$password = $this->password;
// If no password, it must be social network login, we use secret hash for this case
if(!$password && $this->aSettings['secret_key']){
$secretKey = $this->_genSecretKey($oUser->login);
$passwordHash = md5($password);
"SELECT `userid`, `salt`, `password` " .
"FROM `" . $this->aSettings['db_prefix'] . "user` " .
"WHERE `username` = '" . $oUser->login . "'";
// If user do not exist in vBulletin, create one
$userID = $this->_vbCreateUser($oUser->login, $password, $oUser->email);
$aUserRow = array('userid' => $userID, 'salt' => '', 'password' => md5($passwordHash));
// Check if the password is correct, update if not
$vbPassword = md5($passwordHash . $aUserRow['salt']);
if($aUserRow['password'] != $vbPassword){
$this->_vbUpdateUser($oUser->login, $password);
'vb_login_username' => $oUser->login,
'vb_login_password' => '',
'vb_login_md5password' => $passwordHash,
'vb_login_md5password_utf' => $passwordHash
// Send secret key if it was set
$aPostFields['amiro_key'] = $secretKey;
'userAgent' => $_SERVER['HTTP_USER_AGENT']
// Execute a POST request
$headers = $oHTTPRequest->send($url, $aPostFields, AMI_HTTPRequest::METHOD_POST);
// Set cookies from headers
$this->_setCookies($headers);
// Update user session with real data
$ipAddress = $_SERVER['REMOTE_ADDR'];
$idHash = md5($_SERVER['HTTP_USER_AGENT'] . $ipAddress);
"UPDATE `" . $this->aSettings['db_prefix'] . "session` " .
"SET `host` = '" . $ipAddress . "', `idhash` = '" . $idHash . "' " .
"WHERE `userid` = '" . $aUserRow['userid'] . "'";
* Custom handler for on_before_user_logout event.
* @param string $name Event name
* @param array $aEvent Event data
* @param string $handlerModId Handler module id
* @param string $srcModId Source module id
public function beforeLogout($name, array $aEvent, $handlerModId, $srcModId){
// Clear vBulletin cookie "bbsessionhash"
AMI::getSingleton('response')->HTTP->setCookie('bbsessionhash', '', 1, $this->aSettings['cookie_path']);
* Checks if specified secret key is valid for current username.
* @param string $username User login
* @param string $remoteKey Secret key to check
return $this->_genSecretKey($username) == $remoteKey;
* Generates a secret key for specified username and current website.
* @param string $username User login
private function _genSecretKey($username){
* Establishes a connection with an external database.
private function _connectToExternalDatabase(){
* Creates a new user in the vBulletin database.
* @param string $username New username
* @param string $password Password
* @param string $email Email address
private function _vbCreateUser($username, $password, $email){
// Create a user with the same login and password in vBulletin DB
$query = "INSERT INTO `" . $this->aSettings['db_prefix'] . "user` SET
`username` = '" . $username . "',
`password` = '" . md5(md5($password)) . "',
`joindate` = '" . time() . "',
`email` = '" . $email . "',
`usertitle` = 'Junior Member',
// Neccessary to add empty records to these tables
$query = "INSERT INTO `" . $this->aSettings['db_prefix'] . "userfield` SET `userid` = '" . $userID . "'";
$query = "INSERT INTO `" . $this->aSettings['db_prefix'] . "usertextfield` SET `userid` = '" . $userID . "'";
* @param string $username New username
* @param string $password Password
* @param string $email Email address
private function _vbUpdateUser($username, $password = FALSE, $email = FALSE){
// Get userdata from vBulletin database
"SELECT `userid`, `salt` " .
"FROM `" . $this->aSettings['db_prefix'] . "user` " .
"WHERE `username` = '" . $username . "'";
$userID = $userRow['userid'];
$userSalt = $userRow['salt'];
"UPDATE `" . $this->aSettings['db_prefix'] . "user` " .
"SET `password` = '" . md5(md5($password) . $userSalt) . "' " .
"WHERE `userid` = '" . $userID . "'";
"UPDATE `" . $this->aSettings['db_prefix'] . "user` " .
"SET `email` = '" . $email . "' " .
"WHERE `userid` = '" . $userID . "'";
* Grab vBulletin cookies from raw headers and set them according to the setings.
* @param string $headers Returned headers
private function _setCookies($headers){
if(preg_match_all("/Set-Cookie: (bb[^=]+)=([^;]+)/s", $headers, $matches)){
foreach($matches[1] as $index => $cookieName){
$oHTTPResponse->setCookie(
|