MODx and Vbulletin 3.8.x — peace, friendship, chewing gum

we build a house?


In our time of forum engine vbulletin is familiar to many. Someone uses it, someone quietly hates, and someone begging for his superiors finances to buy a license.
/ > And because of his fame support this engine has many CMS, but MODx I have no plugin/code snippet, and existing was enough cheese to use them.
Ladies and gentlemen, I beg to love and favor:
the Experiment was conducted at the MODx version 1.0.2 and vbulletin version 3.8.1

easy does it


First we need to prepare, and the first will be the file global.php forum.
I did this: copied it to global_modx.php (in.../forum/global_modx.php), opened for editing and deleted everything after 891 (remember, version 3.8.1) connection styles, etc., i.e. the last line in the file I have a function call verify_ip_ban();

Note: there were problems with the connection of global — he was logged out (die(); or exit();) in the middle of the script because some of their internal checks, so I advise you to do everything on a test version first.

Now, in the file index.php, the Holy of holies MODx'sa, insert this magic line of code:

$VBDIR = "../forum/"; //path to forum directory better full, not relative
$CURDIR = getcwd();
chdir($VBDIR);
require_once($VBDIR."global_modx.php");
chdir($CURDIR);

TA-da! Now MODx sees all the forum data! In any snippet, we can use (declaring it globally) standard object $vbulletin (with the command print_r($vbulletin); you can see all available fields, but there are VERY many, and most likely will only need print_r($vbulletin- > userinfo);).

Continue our research, Lord


Now we need to introduce the question of authorization on the website. Create the chunk forum_login_form, which will copy the standard login form with "rolls":

 
<!-- login form --> 
<form action="[+forumLink+]login.php?do=login" method="post" onsubmit="md5hash(vb_login_password, vb_login_md5password, vb_login_md5password_utf, 0)"> 
<script type="text/javascript" src="[+forumLink+]clientscript/vbulletin_md5.js?v=381"></script> 
<table cellpadding="0" cellspacing="3" border="0"> 
<tr> 
<td><input type="text" value="Login" name="vb_login_username" id="navbar_username" accesskey="u" tabindex="101" onfocus="javascript: if (this.defaultValue == this.value) this.value = "; else if (this.value == ") this.value = this.defaultValue;" onblur="javascript: if (this.defaultValue == this.value) this.value = "; else if (this.value == ") this.value = this.defaultValue;" class="input" /></td> 
<td><input type="checkbox" name="cookieuser" value="1" tabindex="103" id="cb_cookieuser_navbar" accesskey="c" /></td> 
<td><label for="cb_cookieuser_navbar" > Remember?</label></td> 
</tr> 
<tr> 
<td><input type="password" value="Password" name="vb_login_password" id="navbar_password" tabindex="102" onfocus="javascript: if (this.defaultValue == this.value) this.value = "; else if (this.value == ") this.value = this.defaultValue;" onblur="javascript: if (this.defaultValue == this.value) this.value = "; else if (this.value == ") this.value = this.defaultValue;" class="input"/></td> 
<td></td> 
<td><input type="submit" class="button" value="Login" tabindex="104" title="Enter your username and password to login or click 'Register' to register." accesskey="s" /></td> 
</tr> 
</table> 
<input type="hidden" name="s" value="" /> 
<input type="hidden" name="securitytoken" value="guest" /> 
<input type="hidden" name="do" value="login" /> 
<input type="hidden" name="vb_login_md5password" /> 
<input type="hidden" name="vb_login_md5password_utf" /> 
</form> 
<!-- / login form --> 

Note the [+forumLink+], the address will be inserted when the snippet call for easy control.
Note: in any case, this form is different for different styles, so cut it from your forum and paste this chunk.

Next, create the chunk forum_login_logged, displayed to logged-in users:
 
<strong>Hello <a href="[+profile+]" style="white-space:nowrap;">[+loginName+]</a>! </strong><br /> 
<a href="[+action+]" class="button">Out.</a> 

Yep, made a view, now let's make a controller and create a snippet login, which later will replace the standard medicalschool WebLogin:
 
<?php 
global $vbulletin, $modx; 

$forumlink = (isset($forumlink)) ? $forumlink : 'http://PATH_TO_YOU_FORUM/'; //if not specified in the call parameter to the snippet address of the forum, take a standard 

if ($vbulletin- > userinfo['userid']==0) { //check whether the user is authorized 
//no? display the login form 
echo $modx- > parseChunk('forum_login_form', array('forumLink'=>$forumlink), '[+', '+]'); 
// do a check that the user is logged in on the website, but the forum - no. and if so, delete the session 
// todo: remove the session from the WEB user, without touching MANAGEMENT session 
if (!empty($_SESSION['webInternalKey'])) { 
session_destroy(); 
no(); 
} 
} 
else { //if the user is logged in on the forum - give information Modica 

//check that the user account on the website? 
$sql = "SELECT id FROM ".$modx- > getFullTableName("web_users")." WHERE id='".$vbulletin- > userinfo['userid']."'"; 
$rs = $modx->db->query($sql); 
$limit = $modx->db->getRecordCount($rs); 

if($limit==0) { 
// does not know modix this user 
// create 
$sql = "INSERT INTO ".$modx- > getFullTableName("web_users")." (id, username, password) 
VALUES(".$vbulletin- > userinfo['userid'].", '".$vbulletin- > userinfo['username']."', md5('empty'));"; 
$rs = $modx->db->query($sql); 

// save user attributes 
$sql = "INSERT INTO ".$modx- > getFullTableName("web_user_attributes")." (internalKey, fullname, email, zip, state, country) 
VALUES(".$vbulletin- > userinfo['userid'].", '".$vbulletin- > userinfo['username']."', '".$vbulletin- > userinfo['email']."', ", ", ");"; 
$rs = $modx->db->query($sql); 
$sql = "INSERT INTO ".$modx- > getFullTableName("web_groups")." (webgroup, webuser) 
VALUES(2, ".$vbulletin- > userinfo['userid'].");"; 
$rs = $modx->db->query($sql); 

$modx- > logEvent(998, 1, 'Created an account on the site.', 'Created an account on the site.', 'login snippet'); 
} 

if (!$modx- > userLoggedIn()) { //Now check if the user is not authorized 
//make the data of the forum in session Modica 
$_SESSION['webShortname'] = $vbulletin- > userinfo['username']; 
$_SESSION['webFullname'] = $vbulletin- > userinfo['username']; 
$_SESSION['webEmail'] = $vbulletin- > userinfo['email']; 
$_SESSION['webValidated'] = 1; 
$_SESSION['webInternalKey'] = $vbulletin- > userinfo['userid']; 
$_SESSION['webValid'] = base64_encode($vbulletin- > userinfo['password']); 
$_SESSION['webUser'] = base64_encode($vbulletin- > userinfo['username']); 
$_SESSION['webFailedlogins'] = 0; 
$_SESSION['webLastlogin'] = $vbulletin- > userinfo['lastactivity']; 
$_SESSION['webnrlogins'] = 0; 
$_SESSION['usertype'] = 'web'; 
$_SESSION['webUserGroupNames'] = "; // reset user group names 

// roughly check which groups of documents the user has access, 
// if these are changed already authenticated user, the latter will have to "reconnect" 
$dg="; 
$i=0; 
$tblug = $modx- > getFullTableName("web_groups"); 
$tbluga = $modx- > getFullTableName("webgroup_access"); 
$sql = "SELECT uga.documentgroup 
FROM $tblug ug 
INNER JOIN $tbluga uga ON uga.webgroup=ug.webgroup 
WHERE ug.webuser =".$vbulletin- > userinfo['userid']; 
$ds = $modx->db->query($sql); 
while ($row = $modx->db->getRow($ds,'num')) $dg[$i++]=$row[0]; 
$_SESSION['webDocgroups'] = $dg; 
} 
//parsim the form of "exit" 
echo $modx- > parseChunk('forum_login_logged', 
array('action' => $forumlink.'login.php?do=logout&logouthash='.$vbulletin- > userinfo['securitytoken'], 
'profile' => $forumlink.'usercp.php', 
'loginName' = > $vbulletin- > userinfo['username']), 
'[+', 
'+]' 
); 

//part of the recording user activity 
if (getenv("HTTP_CLIENT_IP")) $ip = getenv("HTTP_CLIENT_IP"); 
else if(getenv("HTTP_X_FORWARDED_FOR")) $ip = getenv("HTTP_X_FORWARDED_FOR"); 
else if(getenv("REMOTE_ADDR")) $ip = getenv("REMOTE_ADDR"); 
else $ip = "UNKNOWN";$_SESSION['ip'] = $ip; 

$itemid = isset($_REQUEST['id']) ? $_REQUEST['id'] : 'NULL' ;$lasthittime = time();$a = 998; 

$sql = "REPLACE INTO ".$modx- > getFullTableName("active_users")." (internalKey, username, lasthit, action, id, ip) values(-".$_SESSION['webInternalKey'].", '".$_SESSION['webShortname']."', '".$lasthittime."', '".$a."', ".$itemid.", '$ip')"; 
$rs = $modx->db->query($sql); 
} 
?>

Code is fairly commented, should not be any issues; the queries were done separately (not via the db->select db->insert) out of habit and convenience for debugging.

further to complete euphoria


Having everything written above, we have:
the
    the
  • a Unified forum authorization — input and output
  • the
  • Access to the forum data on any page of the site
  • the
  • by logging on the website or on the forum authorization, would work everywhere (with a redirect to the page you're viewing back)
  • the
  • Creating users Ehpm, i.e., it also recognizes its users that allows you to restrict access to documents, etc.
  • the
  • Same user ID on the website/forum
  • Destroying session authorization if no auth on the forum



And to put the bun remained in the site's templates to prescribe the snippet call [[login]], and then will only enjoy the work done. One drawback of this approach is: while a user of the forum without going to the site to limit its access rights to the pages will be impossible, unless you create handles in the database of this user.
In contrast to the method of BanzaiTokyo on the basis of which began to develop and from which there is only the introduction index.php global file on the forum, you do not need to create a product and modules to it, to control the output from the forum and registration — everything happens automatically.

the July 28, 2010 UPD:
Programmers who used this solution on their websites! ATTENTION! Then allowed the vulnerability that allows you to perform blind-SQL:
$itemid = isset($_REQUEST['id'])? $_REQUEST['id']: 'NULL' ;$lasthittime = time();$a = 998;
$sql = "REPLACE INTO ".$modx- > getFullTableName("active_users")." (internalKey, username, lasthit, action, id, ip) values(-".$_SESSION['webInternalKey'].", '".$_SESSION['webShortname']."', '".$lasthittime."', '".$a."', ".$itemid.", '$ip')";
$rs = $modx->db->query($sql);

If you substitute a specific id in the subquery, you can perform the comparison operation and easy to brothersit any data. Unfortunately using this vulnerability and hacked me(( Decided to just:
$itemid = isset($_REQUEST['id'])? the (is_numeric($_REQUEST['id'])?$_REQUEST['id']:'NULL'): 'NULL' ;$lasthittime = time();$a = 998;
$sql = "REPLACE INTO ".$modx- > getFullTableName("active_users")." (internalKey, username, lasthit, action, id, ip) values(-".$_SESSION['webInternalKey'].", '".$_SESSION['webShortname']."', '".$lasthittime."', '".$a."', ".$itemid.", '$ip')";
$rs = $modx->db->query($sql);
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

Integration of PostgreSQL with MS SQL Server for those who want faster and deeper

Custom database queries in MODx Revolution

Parse URL in Zend Framework 2