Current Record: Authenticating_Against_the_Joomla!_Users_Table #93

Note: This article applies to Joomla! 2.5.17 and earlier. For version 2.5.18 and higher, see this note Xataface is able to use the jooml...

Current Record: Authenticating_Against_the_Joomla!_Users_Table #93

Note: This article applies to Joomla! 2.5.17 and earlier. For version 2.5.18 and higher, see this note Xataface is able to use the jooml...

Authenticating Against the Joomla Users Table

[Permalink]

Note: This article applies to Joomla! 2.5.17 and earlier. For version 2.5.18 and higher, see this note

Xataface is able to use the joomla users table to authenticate against so that, you can allow your users to log into your Xataface application using the same credentials as they use to access your joomla website. Achieving this level of integration requires 2 simple steps : 1 - Set up the [_auth] section of your conf.ini file to reference the joomla users table and the correct username and password columns. 2 - Create a delegate class for the joomla users table to be able to decrypt the password set in the table.

Configure the conf.ini file

Joomla users table is named jos_users. So you have to declare this table in the conf.ini file.
[_auth]
users_table = jos_users
username_column = username
password_column = password
Note that username_column and password_column are very simple...

Create a delegate class for your users table

Now we have to create a delegate class for the users table to decrypt the passwords set in joomla. Joomla uses a custom md5 encryption.

Joomla encryption

When a user is setting a password in joomla, the system does several things : 1 - generate a random key containing alphanumeric characters example :
8NdiRqLRKLHaNwudJ3InJknsew9sc7pL
2 - concate the clear entered password with the random key example :
password8NdiRqLRKLHaNwudJ3InJknsew9sc7pL
3 - doing a md5 encryption on the result string example :
md5(password8NdiRqLRKLHaNwudJ3InJknsew9sc7pL = f2b1fb3996442db549c1ed1a1eebbfe1
4 - concate the md5 string with the random key separated by ":" example :
f2b1fb3996442db549c1ed1a1eebbfe1:8NdiRqLRKLHaNwudJ3InJknsew9sc7pL
So it's a great encryption but xataface doesn't know how to do that. Here is the utility of the delegate class. We will define a function inside which could compare the entered password in xataface with the joomla stored password.

Creating the delegate class

1 - Add a jos_users directory in your directory table 2 - Create a jos_users.php file inside this new directory

Creating the decrypt password function

Before posting this code, I would like to thank fantomasdm who created this function. So here is the code of the function to paste directly in the jos_users delegate class :
<?
class tables_jos_users {
    
function password__serialize($password){

   $app =& Dataface_Application::getInstance(); 
   $query = "SELECT id, gid, block, password, usertype FROM jos_users where username='".$_POST['UserName']."'";
   $result = mysql_query($query,$app->db()) or die("Query failed" . mysql_error() );

   $line = mysql_fetch_array($result, MYSQL_ASSOC);
   mysql_free_result($result);

   $arraypass=explode(":", $linea['password']);
   $key=$arraypass[1];
   
   $ret = md5(trim($password).$key).":".$key;
   return $ret;
} 
}
?>

Save your file and test the result. Enjoy ! ;-)

Edit: Joomla 2.5.18 and higher

Anyone using Joomla ver 2.5 and the Joomla users table for authentication in to their Xataface app needs to be aware that the Joomla password hashing changed as of version 2.5.18. This also brought 2.5.x in line with the latest Joomla version 3.x (so the following also applies for version 3.x).

Essentially, Joomla now uses PHPass to replace the bespoke hashing routine used before. This means the routine above is probably redundant for you if you've installed all the recommended (security) updates. One problem you may encounter is that existing users' passwords are converted upon logging-in, however if you have users that access your Xataface app directly, they may not have had their password converted whereas others will. This means that you need a routine that handles both old and new formats. Thankfully, the new routine uses a prefixed identifier to flag it as a PHPass hash.

The following is a sample users table delegate class that should work with a Joomla! Users table and deal both types of password hash. Adapted from https://groups.google.com/d/msg/xataface/8DlkolDYkR4/RCuZxX91qFwJ?

<?
class tables_your_joomla_table_prefix_users {

function password__serialize($password){

   $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
   $app =& Dataface_Application::getInstance();
   $query = "SELECT id, block, password, usertype FROM your_joomla_table_prefix_users where username='".$_POST['UserName']."'";
   $result = mysql_query($query,$app->db()) or die("Query failed: " . mysql_error() );
//   $row = mysql_fetch_assoc($result);
   $line = mysql_fetch_array($result, MYSQL_ASSOC);
    /* Release resources */
    mysql_free_result($result);

   $arraypass=explode(":", $line['password']);
   $key=$arraypass[1];

   if (substr($line['password'],0,3) == '$P$') {

   $hash = $this->_hash_crypt_private($password, $line['password'], $itoa64);
   return $hash;
     }
   else {
   $ret = md5(trim($password).$key).":".$key;
   return $ret;

   }

}
    function _hash_crypt_private($password, $setting, &$itoa64)
    {
        $output = '*';

    // Check for correct hash
    if (substr($setting, 0, 3) != '$H$' && substr($setting, 0, 3) != '$P$')
    {
        return $output;
    }

        $count_log2 = strpos($itoa64, $setting[3]);

        if ($count_log2 < 7 || $count_log2 > 30)
        {
            return $output;
        }

        $count = 1 << $count_log2;
        $salt = substr($setting, 4, 8);

        if (strlen($salt) != 8)
        {
            return $output;
        }

        /**
        * We're kind of forced to use MD5 here since it's the only
        * cryptographic primitive available in all versions of PHP
        * currently in use.  To implement our own low-level crypto
        * in PHP would result in much worse performance and
        * consequently in lower iteration counts and hashes that are
        * quicker to crack (by non-PHP code).
        */
        if (PHP_VERSION >= 5)
        {
            $hash = md5($salt . $password, true);
            do
            {
                $hash = md5($hash . $password, true);
            }
            while (--$count);
        }
        else
        {
            $hash = pack('H*', md5($salt . $password));
            do
            {
                $hash = pack('H*', md5($hash . $password));
            }
            while (--$count);
        }

        $output = substr($setting, 0, 12);
        $output .= $this->_hash_encode64($hash, 16, $itoa64);

        return $output;
    }

    /**
    * Encode hash
    */
    function _hash_encode64($input, $count, &$itoa64)
    {
        $output = '';
        $i = 0;

        do
        {
            $value = ord($input[$i++]);
            $output .= $itoa64[$value & 0x3f];

            if ($i < $count)
            {
                $value |= ord($input[$i]) << 8;
            }

            $output .= $itoa64[($value >> 6) & 0x3f];

            if ($i++ >= $count)
            {
                break;
            }

            if ($i < $count)
            {
                $value |= ord($input[$i]) << 16;
            }

            $output .= $itoa64[($value >> 12) & 0x3f];

            if ($i++ >= $count)
            {
                break;
            }

            $output .= $itoa64[($value >> 18) & 0x3f];
        }
        while ($i < $count);

        return $output;
    }

}
?>
blog comments powered by Disqus
Powered by Xataface
(c) 2005-2024 All rights reserved