Welcome to the Question2Answer Q&A. There's also a demo if you just want to try it out.

How to integrate Joomla with Q2A single sign on? SOLVED

+6 votes
5,843 views
asked Jan 21, 2013 in Q2A Core by moomoochoo
edited Jan 28, 2013 by moomoochoo

I've started working through the single sign on tutorial at http://www.question2answer.org/single-sign-on.php in order to integrate Question2Answer with Joomla 2.5.x. I've noticed a few people have been asking how to do that in the forum, so I've decided to open this question and provide whatever answers I can as I work through it. Hopefully this will provide a central area for others to show what they have tried too.

LINKS FOR FILES

Here is the link for my modified qa-external-users.php file

http://sebsauvage.net/paste/?ec6b77e4137508b1#2JrSQ8DsIWpsEKg3vHJIjGlJp8xtEkZbxvNASAb2Sik=

Here is integrate.php

http://sebsauvage.net/paste/?dc9ce08b077d9c21#GlGPxU29gIue69B1pkMNZKkbccHL2qUdF7fLqbOooeM=

Q2A version: Q2A 1.5.4
commented Oct 26, 2015 by sc-sfw
It would be great to update this answer for Joomla 3. Also how to integrate search?

6 Answers

+3 votes
answered Jan 21, 2013 by moomoochoo
selected Jan 27, 2013 by moomoochoo
 
Best answer

PART 1

Please note, I'm not a programmer and I'm writing this as I go along. I may make mistakes along the way. Feel free to point them out as we go.

My answer assumes that you have been following the instructions for single sign on posted at http://www.question2answer.org/single-sign-on.php and that you are now editing qa-external-users.php

In qa-external-users.php you will need to make a few edits, but first I need to look at our Joomla table (I used phpmyadmin to do this).

Joomla user information is stored in abs_users table (note that the prefix abs will likely be different in each Joomla website.)

Joomla user information

You can see that the user is identified using id of type int(11). This information is important, because we need to add it to our qa-external-users.php file. Specifically you will need to edit   function qa_get_mysql_user_column_type() on line 57.

Change return null;     to      //return null;

Next delete lines 67-73

/*
        Example 2 - suitable if:
        
        * You use unsigned numerical user identifiers in an INT UNSIGNED column
        
        return 'INT UNSIGNED';
    */

and in their place put

return 'INT';

 

Next go to your website and get the address for the login, the address for the registration page and the address for the logout page.

Once you have done that you need to comment out lines 105-109

       /* return array(
            'login' => null,
            'register' => null,
            'logout' => null
        ); */

Then on line 111 add

        return array(
            'login' => 'http://www.mysite.com/login',
            'register' => 'http://www.mysite.com/register',
            'logout' => 'http://www.mysite.com/logout',
        );

Remember to substitute your login, registration and logout addresses for the ones above.

The next part we need to edit is the function qa_get_logged_in_user()

Unfortunately this is where it gets a bit harder.

If you read the example listed in qa-external-users.php example 2 best matches Joomla's situation. Unfortunately, when a user logs into Joomla, Joomla creates a cookie with a random cookie name. The Joomla session cookie contains only alphanumeric characters (0-9 and a-f) and is 32 characters long, e.g. a8a70d9559bc6548b1b2aed88c45753b.

The cookie name is important because if we don't know the visitors cookie name we can't look up the user's logged in status from the database (at least-not in a straight forward way). Visitor session data is stored in abs_session in the database.

So, I'm kind of stuck here. Since I don't know ahead of time what the cookie name will be, I guess I need to look at each cookie to see if its name is 32 characters long and is composed only of alphanumberic characters. If it fits that description it is a good guess that it is the joomla cookie.

There is an alternative way. That way would require including the Joomla framework into Q2A. The problem with this is that Joomla uses its own session management so I think it would cause problems with Q2A's sessions. I'm not sure though. I will continue this in PART 2.

commented Jan 21, 2013 by Waterfr Villa
+1 for your effort on helping others
commented Jan 21, 2013 by moomoochoo
Thanks! I hope someone finds it useful!
commented Jan 23, 2013 by moomoochoo
This code should help find joomla cookies
$cookie=$_COOKIE;

if (isset($cookie))
{
    foreach ($cookie as $key=>$val)
        if (strlen($key) ==32) //Check the cookie name is 32 characters in length
        {
            echo "<br>Found a Joomla cookie:  $key--> $val";
        }
}
+2 votes
answered Jan 21, 2013 by moomoochoo
edited Jan 26, 2013 by moomoochoo

PART 2

To include the Joomla framework I've CREATED A FILE in the Joomla root directory called integrate.php

Here is the code for integrate.php (please note that I'm using Joomla 2.5)

<?php
define( '_JEXEC', 1 );
define('JPATH_BASE', dirname(__FILE__));
define( 'DS', DIRECTORY_SEPARATOR );
require_once ( JPATH_BASE .DS.'includes'.DS.'defines.php' );
require_once ( JPATH_BASE .DS.'includes'.DS.'framework.php' );

/* Instantiate the application */
$app = &JFactory::getApplication('site');

//Initialise the application
$app->initialise();                        

?>

Then from line 34-37 of qa-external-users.php I've added

     //Integrate with Joomla
    $path = $_SERVER['DOCUMENT_ROOT'];            //Finds the root directory (the assumption here is that Joomla is in the root directory).
    $path .= "/integrate.php";
    include_once($path);

Continued in PART3

+1 vote
answered Jan 22, 2013 by moomoochoo
edited Jan 26, 2013 by moomoochoo

PART 3

Next we need to edit function qa_get_logged_in_user() in qa-external-users.php

change line 202 from

return null;

to

//return null;

Next, I've added the following code to lines 295-307

        $userID=JFactory::getUser()->id;
        $username= JFactory::getUser()->username;
        $useremail= JFactory::getUser()->email;    
        
        jimport( 'joomla.access.access' );
        $groups = JAccess::getGroupsByUser($userID, false);

                
        if ($userID!=0)
        {
                //Checks for super-users (= group 8)
                //You might want to create a new group specifically for administrating Q2A-if so you will need to change 8 to the number of the group you create.

                if(in_array(8, $groups)){
                   $usertype=QA_USER_LEVEL_ADMIN;
                }
                else
                {
                    $usertype=QA_USER_LEVEL_BASIC;
                }
                
            return array(
                'userid' => $userID,
                'publicusername' => $username,
                'email' => $useremail,
                'level' => $usertype
            );
        }
        else
        {
            return null;
        }

At the moment, we have only allowed the usertype to be either QA_USER_LEVEL_BASIC or QA_USER_LEVEL_ADMIN, but there are actually 4 different options a user could be (namely QA_USER_LEVEL_BASIC, QA_USER_LEVEL_EDITOR, QA_USER_LEVEL_ADMIN, QA_USER_LEVEL_SUPER).We will probably have to change this later.

You may be wondering why I didn't use $useremail= JFactory::getUser()->usertype;  The reason I didn't use it is because the usertype column in abs_users has been deprecated (it is no longer used in joomla 2.5).

To understand which group each id represents we need to take a look at abs_usergroups

ids and corresponding usergroup titles

The important thing to look at here is the id and the title. In my code, I was setting group 8 (Super Users) as administrators of Q2A (but you will notice Joomla Administrators are id=7). You can change the id number to match whichever group you want to be administrators of Q2A.

Continued in PART 4

+1 vote
answered Jan 22, 2013 by moomoochoo
edited Jan 26, 2013 by moomoochoo

PART 4

Next edit function qa_get_user_email($userid) on line 322

change from          return null;           to             //return null;

Add the following code to lines 344-352

if ($userid!=0)
        {
            $result=& JFactory::getUser($userid)->email;
            return $result;
        }
        else
        {
            return null;
        }

Next edit the function qa_get_userids_from_public($publicusernames) on line 378.

change it from             return null;        to             //return null;

Next remove           */          from line 420?? (sorry I lost the line number)

and put           */            on line 399   (by itself)

I'm not sure about this next bit, but anyway.

Replace the below code (lines 401-419 )

$publictouserid=array();
            
        if (count($publicusernames)) {
            $qa_db_connection=qa_db_connection();
            
            $escapedusernames=array();
            foreach ($publicusernames as $publicusername)
                $escapedusernames[]="'".mysql_real_escape_string($publicusername, $qa_db_connection)."'";
            
            $results=mysql_query(
                'SELECT username, userid FROM users WHERE username IN ('.implode(',', $escapedusernames).')',
                $qa_db_connection
            );
    
            while ($result=mysql_fetch_assoc($results))
                $publictouserid[$result['username']]=$result['userid'];
        }
        
        return $publictouserid;

with

        $publictouserid=array();
            
        if (count($publicusernames)) {
            $qa_db_connection=qa_db_connection();
            
            $escapedusernames=array();
            foreach ($publicusernames as $publicusername)
                $escapedusernames[]="'".mysql_real_escape_string($publicusername, $qa_db_connection)."'";
            
            $results=mysql_query(
                'SELECT username, id FROM abs_users WHERE username IN ('.implode(',', $escapedusernames).')',
                $qa_db_connection
            );
    
            while ($result=mysql_fetch_assoc($results))
                $publictouserid[$result['username']]=$result['id'];
        }
        
        return $publictouserid;

Continued in PART 5

+1 vote
answered Jan 22, 2013 by moomoochoo
edited Jan 26, 2013 by moomoochoo

PART5

NOTE- the table abs_users is going to have a slightly different name for each Joomla installation. The prefix abs will change but the _users part will remain the same. You will need to find the table name using a program like phpmyadmin.

Next, on line 447  change             return null;                to               //return null;

On line 488??, remove */            and insert   */    on line 468 (it should be on the line by itself);

Then change lines 469-487 from

        $useridtopublic=array();
        
        if (count($userids)) {
            $qa_db_connection=qa_db_connection();
            
            $escapeduserids=array();
            foreach ($userids as $userid)
                $escapeduserids[]="'".mysql_real_escape_string($userid, $qa_db_connection)."'";
            
            $results=mysql_query(
                'SELECT username, userid FROM users WHERE userid IN ('.implode(',', $escapeduserids).')',
                $qa_db_connection
            );
    
            while ($result=mysql_fetch_assoc($results))
                $useridtopublic[$result['userid']]=$result['username'];
        }
        
        return $useridtopublic;

to

        $useridtopublic=array();
        
        if (count($userids)) {
            $qa_db_connection=qa_db_connection();
            
            $escapeduserids=array();
            foreach ($userids as $userid)
                $escapeduserids[]="'".mysql_real_escape_string($userid, $qa_db_connection)."'";
            
            $results=mysql_query(
                'SELECT username, id FROM abs_users WHERE id IN ('.implode(',', $escapeduserids).')',
                $qa_db_connection
            );
    
            while ($result=mysql_fetch_assoc($results))
                $useridtopublic[$result['id']]=$result['username'];
        }
        
        return $useridtopublic;

Again you will need to change abs_users to match your Joomla site's table name.

 

Continued in PART6

+1 vote
answered Jan 26, 2013 by moomoochoo
edited Jan 26, 2013 by moomoochoo

PART6

I will add my qa-external-users.php file soon, but I still recommend reading through these answers to see what I've done. You will still need to make some modifications particularly wherever   abs_    is used.

 

Here is the link for my modified qa-external-users.php file

http://sebsauvage.net/paste/?e06021ea29c463c6#nOtYXsoGinXht64XsLMm9WHe9ohPizcfoQnHo12Iv+M=

Here is integrate.php

http://sebsauvage.net/paste/?bc83e2a89ba2c099#j5cKM9T6x1407tm75ZWmWotYXBj23+0Z9jHWw2sQ+P0=

...