Skip to content

CL Auth Integration with Vanilla Forum Engine

Derek Jones edited this page Jul 5, 2012 · 16 revisions

Category:Core | Category:Core::Integration | Category:Library::Authorization

After a week of picking through code upon code, and even more time wasted on debugging errors, I finally managed to come up with a viable solution for using CL Auth (A New Codeigniter authentication system) in conjunction with the Vanilla Forum Engine. This is huge for so many reasons but mainly, it gives CI users another authentication/open source forum solution.

Before I proceed I must give thanks to Grahack, one of the contributors to FreakAuth. I used his integration AND Dip method/Vanilla integration doc as a foundation for this write up and the eventual code that lead to it's completion.

Requirements

  1. Codeigniter - You will need the Codeigniter Framework of course. This has been confirmed to work with version 1.6.3.
  2. You will then need to dip into CI - You will need to make use of this technique that has been dubbed "dipping into CI". It will provide you with a means to make use of CI in external applications without too much fuss (Use at your own risk).
  3. CL Auth - You will need the latest copy of CL Auth.
  4. Vanilla - You will need the latest copy of Vanilla

Original Guides Used

Pligg Vanilla Integration Write Up <-- Originally made use of the Drupal Integration Doc over at Lussumo Dip into CI Vanilla Integration with Wordpress CL Auth Documentation

Vanilla Installation

This part threw me for a loop at first. I wasn't sure where to place the Vanilla directory in relation to my main Codeigniter application and system directory.

You have to install Vanilla in a subdirectory next to your System folder (In other words, it should live in your root folder). Run the installation and follow all of Vanilla's steps making sure to include Vanilla's database in the same table as your CI installation (Vanilla tables will be prefixed with "LUM_").

Note: If you are working on a test server and do not have a mysql password set for your mysql user, then you will want to add the following line to /conf/database.php

[CODE] $Configuration['DATABASE_PASSWORD'] = ''; [/CODE]

Once Vanilla has been installed properly, we get to the good stuff.

Database Mapping

in /conf/database.php, add the following lines before the closing php bracket (?>)

replace "YOUR USER TABLE NAME HERE" with the actual name of your User table. I used a prefix for my user table, but the default CL auth table is "users".

//Integrate with CI here
$DatabaseTables['User'] = 'YOUR USER TABLE NAME HERE';
include 'ci_integration_database.php';
// End CI integration

Now you must create the CI_integration_database.php. In this file you are going to map the appropriate columns of your user table to Vanilla's DB schema.

&lt;?php
// Vanilla-CI Authentication Integration

// Map existing and matching CI User columns
$DatabaseColumns['User']['UserID'] = 'id';
$DatabaseColumns['User']['Name'] = 'username';
$DatabaseColumns['User']['Password'] = 'password';
$DatabaseColumns['User']['Email'] = 'email';
$DatabaseColumns['User']['DateLastActive'] = 'last_visit';
$DatabaseColumns['User']['DateFirstVisit'] = 'created';

// Also map the other CI User columns
$DatabaseColumns['User']['group_id'] = 'group_id';
$DatabaseColumns['User']['user_ip'] = 'user_ip';
$DatabaseColumns['User']['username_clean'] = 'username_clean';
$DatabaseColumns['User']['banned'] = 'banned';
$DatabaseColumns['User']['ban_reason'] = 'ban_reason';
$DatabaseColumns['User']['login_attempts'] = 'login_attempts';
$DatabaseColumns['User']['newpass'] = 'newpass';
$DatabaseColumns['User']['newpass_key'] = 'newpass_key';
$DatabaseColumns['User']['newpass_time'] = 'newpass_time';
$DatabaseColumns['User']['active_time'] = 'active_time';
$DatabaseColumns['User']['modified'] = 'modified';

?&gt;

Now you have to add the extra columns in Vanilla's user table to your User table. Hope I didn't mix anyone up there. It's simple, just run the following SQL code in your favorite Mysql Database management software, most likely it will be phpmyadmin, (Pay close attention to the warning): WARNING: The "users" in this script should be replaced by your table name if it is something besides "users".

ALTER TABLE users
ADD RoleID int(2) NOT NULL default '3',
ADD StyleID int(3) NOT NULL default '1',
ADD CustomStyle varchar(255) default NULL,
ADD FirstName varchar(50) NOT NULL default '',
ADD LastName varchar(50) NOT NULL default '',
ADD VerificationKey varchar(50) NOT NULL default '',
ADD EmailVerificationKey varchar(50) default NULL,
ADD UtilizeEmail enum('1','0') NOT NULL default '0',
ADD ShowName enum('1','0') NOT NULL default '1',
ADD Icon varchar(255) default NULL,
ADD Picture varchar(255) default NULL,
ADD Attributes text NULL,
ADD CountVisit int(8) NOT NULL default '0',
ADD CountDiscussions int(8) NOT NULL default '0',
ADD CountComments int(8) NOT NULL default '0',
ADD DateFirstVisit datetime NOT NULL default '0000-00-00 00:00:00',
ADD DateLastActive datetime NOT NULL default '0000-00-00 00:00:00',
ADD RemoteIp varchar(100) NOT NULL default '',
ADD LastDiscussionPost datetime default NULL,
ADD DiscussionSpamCheck int(11) NOT NULL default '0',
ADD LastCommentPost datetime default NULL,
ADD CommentSpamCheck int(11) NOT NULL default '0',
ADD UserBlocksCategories enum('1','0') NOT NULL default '0',
ADD DefaultFormatType varchar(20) default NULL,
ADD Discovery text,
ADD Preferences text,
ADD SendNewApplicantNotifications enum('1','0') NOT NULL default '0',

ADD KEY `user_role` (`RoleID`),
ADD KEY `user_style` (`StyleID`),
ADD KEY `user_name` (`username`); 

Now you have to give your CI user the same Superadmin rights as the Vanilla Superadmin you created when you first installed Vanilla. Use the following SQL to achieve this and remember that we still need to change the "users" name here if our table uses a different name for "users".

update users set
    RoleID=(select RoleID from LUM_User where id=1),
    StyleID=(select StyleID from LUM_User where id=1),
    CustomStyle=(select CustomStyle from LUM_User where id=1),
    FirstName=(select FirstName from LUM_User where id=1),
    LastName=(select LastName from LUM_User where id=1),
    VerificationKey=(select VerificationKey from LUM_User where id=1),
    EmailVerificationKey=(select EmailVerificationKey from LUM_User where id=1),
    UtilizeEmail=(select UtilizeEmail from LUM_User where id=1),
    ShowName=(select ShowName from LUM_User where id=1),
    Icon=(select Icon from LUM_User where id=1),
    Picture=(select Picture from LUM_User where id=1),
    Attributes=(select Attributes from LUM_User where id=1),
    CountVisit=(select CountVisit from LUM_User where id=1),
    CountDiscussions=(select CountDiscussions from LUM_User where id=1),
    CountComments=(select CountComments from LUM_User where id=1),
    DateFirstVisit=(select DateFirstVisit from LUM_User where id=1),
    DateLastActive=(select DateLastActive from LUM_User where id=1),
    RemoteIp=(select RemoteIp from LUM_User where id=1),
    LastDiscussionPost=(select LastDiscussionPost from LUM_User where id=1),
    DiscussionSpamCheck=(select DiscussionSpamCheck from LUM_User where id=1),
    LastCommentPost=(select LastCommentPost from LUM_User where id=1),
    CommentSpamCheck=(select CommentSpamCheck from LUM_User where id=1),
    UserBlocksCategories=(select UserBlocksCategories from LUM_User where id=1),
    DefaultFormatType=(select DefaultFormatType from LUM_User where id=1),
    Discovery=(select Discovery from LUM_User where id=1),
    Preferences=(select Preferences from LUM_User where id=1),
    SendNewApplicantNotifications=(select SendNewApplicantNotifications from LUM_User where id=1)
    where id=1; 

Now for the business end of it all.

The authenticator class is the class that makes the magic happen in Vanilla. It handles the logging in and logging out of users, as well as their sessions and cookies while they are on the site.

Add the following to /conf/settings.php

// CI integration
$Configuration['AUTHENTICATION_MODULE'] = 'People/People.Class.CI_Authenticator.php';
$Configuration['SAFE_REDIRECT'] = '../index.php/auth/';

Now we must create the People.Class.CI_Authenticator.php. We are going to place this file in the /library/People/ folder.

&lt;?php
/*
* Copyright 2003 Mark O'Sullivan
* This file is part of People: The Lussumo User Management System.
* Lussumo's Software Library 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.
* Lussumo's Software Library 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 Vanilla; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
* The latest source code is available at www.lussumo.com
* Contact Mark O'Sullivan at mark [at] lussumo [dot] com
* 
* Description: Codeigniter authentication interface. Written in part by Christophe Gragnic (grahack) & Nial Grimes (Pligg community member).
* Also thanks to Mark O'Sullivan at Lussumo.com for his Wordpress Integration with Vanilla.
* 
* Devon Lambert (dnyce) - We've made changes to the authenticate, deauthenticate, and GetIdentity functions. 
* Authenticate and Deauthenticate will not be used and therefore should always return 1.
* 
* * * Applications utilizing this file: Vanilla;
*/
class Authenticator {
   var $Context;
 
   
   function Authenticator(&$Context) {   
      $this->Context = &$Context;
   }
   
   function GetIdentity() {

        if (!session_id()) {
         session_set_cookie_params(0, $this->Context->Configuration['COOKIE_PATH'], $this->Context->Configuration['COOKIE_DOMAIN']);
         session_start();
        }
        
          // We have a guest till proven a member
        $UserID = 0;
        
        // Check if CI cookie is available (i.e. user has logged into CI/Auth Program)
        
        // Include the CI settings
        require($this->Context->Configuration['APPLICATION_PATH'].'../system/cidip/cidip_index.php');
              $obj =& get_instance();
         
        $Userid = $obj->session->userdata('user_id'); 
        $Sessid = $obj->session->userdata('session_id');
        $Username = $obj->session->userdata('username');
        
         if(isset($_COOKIE['ci_session'])) {
        
        // Find user in the CI user table
        $s = $this->Context->ObjectFactory->NewContextObject($this->Context, 'SqlBuilder');
        $s->SetMainTable('User', 'u');
        $s->AddSelect('UserID', 'u');
        $s->AddSelect('Password', 'u');
        $s->AddWhere('u', 'Name', '', FormatStringForDatabaseInput($Username), '=');
          
        $Result = $this->Context->Database->Select($s,
         'Authenticator',
         'GetIdentity',
         'An error occurred while attempting to validate your remember me credentials');

        }
        
        if ($Result) {

                 // Retrieve the username and encrypted password from the database
                while ($rows = $this->Context->Database->GetRow($Result)) {
                $UserID = ForceInt($rows['UserID'], 0);
                $Password = $rows['Password'];
        }

            if ($UserID > 0) {
                 
                // 1. Update the user's information
                $this->UpdateLastVisit($UserID);
                                  
                // 2. Log the user's IP address
                $this->LogIp($UserID);
            }
        }
             
        // If it has now been found, set up the session.
        $this->AssignSessionUserID($UserID);
        return $UserID;
   }
    
   // All methods below this point are specific to this authenticator and
   // should not be treated as interface methods. The only required interface
   // properties and methods appear above.
   
    function AssignSessionUserID($UserID) {
      if ($UserID > 0) {
         @$_SESSION[$this->Context->Configuration['SESSION_USER_IDENTIFIER']] = $UserID;
      }
    }
   
   function LogIp($UserID) {
      if ($this->Context->Configuration['LOG_ALL_IPS']) {
         $s = $this->Context->ObjectFactory->NewContextObject($this->Context, 'SqlBuilder');
         $s->SetMainTable('IpHistory', 'i');
         $s->AddFieldNameValue('UserID', $UserID);
         $s->AddFieldNameValue('RemoteIp', GetRemoteIp(1));
         $s->AddFieldNameValue('DateLogged', MysqlDateTime());
 
         $this->Context->Database->Insert($s,
            'Authenticator',
            'LogIp',
            'An error occurred while logging your IP address.',
            false); // fail silently
      }
   }

   function SetCookieCredentials($CookieUserID, $VerificationKey) {
      // Note: 2592000 is 60*60*24*30 or 30 days
      setcookie($this->Context->Configuration['COOKIE_USER_KEY'],
         $CookieUserID,
         time()+2592000,
         $this->Context->Configuration['COOKIE_PATH'],
         $this->Context->Configuration['COOKIE_DOMAIN']);
      setcookie($this->Context->Configuration['COOKIE_VERIFICATION_KEY'],
         $VerificationKey,
         time()+2592000,
         $this->Context->Configuration['COOKIE_PATH'],
         $this->Context->Configuration['COOKIE_DOMAIN']);
   }
   
   function UpdateLastVisit($UserID, $VerificationKey = '') {
      $s = $this->Context->ObjectFactory->NewContextObject($this->Context, 'SqlBuilder');
      $s->SetMainTable('User', 'u');
      $s->AddFieldNameValue('DateLastActive', MysqlDateTime());
      if ($VerificationKey != '') $s->AddFieldNameValue('VerificationKey', $VerificationKey);
      $s->AddFieldNameValue('CountVisit', 'CountVisit + 1', 0);
      $s->AddWhere('u', 'UserID', '', $UserID, '=');
 
      $this->Context->Database->Update($s,
         'Authenticator',
         'UpdateLastVisit',
         'An error occurred while updating your profile.',
         false); // fail silently
   }
   
   function Authenticate() { 
      return 1;
   }
   
   function DeAuthenticate() {
      return 1;
   }
}
?&gt;

Finally, we need to place one final touch on it all. Go to your "themes" folder in Vanilla. Make a copy of the "vanilla" folder found there. Name this copy whatever you would like, for our purposes we will call this folder "Vanilla_2". This will provide you with a new theme/styling template that you can use to make changes to the look and feel of your forum.

Go back to the "themes" folder, make a copy of the head.php, menu.php, and foot.php and place the copies in your new "Vanilla_2" folder.

Now open up the menu.php in your new theme folder and find the section at the top that looks like this:

echo '<div id="Session">';
    if ($this->Context->Session->UserID > 0) {
        echo str_replace('//1',
            $this->Context->Session->User->Name,
            $this->Context->GetDefinition('SignedInAsX')).' (<a >Context->Configuration['SIGNOUT_URL'].'">'.$this->Context->GetDefinition('SignOut').'</a>)';
    } else {
        echo $this->Context->GetDefinition('NotSignedIn').' (<a >Context->Configuration['SIGNIN_URL'], 'ReturnUrl='.GetRequestUri()).'">'.$this->Context->GetDefinition('SignIn').'</a>)';
    }
    echo '</div>';

Replace it all with the following:

?&gt; 

&lt;?php echo '<div id="Session">'; ?&gt;

&lt;?php $obj =& get_instance(); ?&gt;

&lt;?php /*Login/Logout Loop */ ?&gt;
&lt;? if ( $obj->cl_auth->isValidUser() ) : ?&gt;
&lt;?=anchor($obj->config->item('CL_logout_uri'), 'Logout')?&gt;
&lt;? else: ?&gt;
&lt;?=anchor($obj->config->item('CL_login_uri'), 'Login')?&gt; - &lt;?=anchor($obj->config->item('CL_register_uri'), 'Register')?&gt;
&lt;? endif; ?&gt;

&lt;?php /*END Login/Logout Loop */ ?&gt;

&lt;?php  echo '</div>'; ?&gt; 

&lt;?php

If you've installed CL Auth and Codeigniter properly, then you should now be able to log into CL Auth using Your Website URL/auth/login and have your session/cookie carry over to Vanilla.

Go have fun, play around, test it, break it, and let me know if I've missed anything.

Clone this wiki locally