Revision [19914]

This is an old revision of WikkaWithphpBB3 made by WebHorn on 2008-05-12 19:01:17.

 

Using Wikka PHPBB 3.x

Contributed by Paul Young, using the example code by JeremyCoates .

phpBB3 changed its user authentication mechanism. phpBB3 no longer stores MD5 hashes of passwords; instead it does a "true" one-way, one-time, non-recoverable hash of the password using phpass. The output of the hash is different each time, so you can't just select the password in the phpBB database and do a compare against a MD5 of the submitted password anymore - you have to algorithmically compare them using phpass. They also changed how and where they indicate if a user is active or inactive.

It's not difficult, but you will need to bring in code from phpBB to your Wikka files.

One final note, this code works for me on my server, but could stand to be further tested. Feel free to correct if you find a bug.

Wakka.class.php

Find:
 { return $this->LoadSingle("select * from ".$this->config['table_prefix']."users where name = '".mysql_real_escape_string($name)."' ".($password === 0 ? "" : "and password = '".mysql_real_escape_string($password)."'")." limit 1"); }


Replace With:

/**
    * PHPBB Integration
    *
    * function LoadUser($name, $password = 0) { return $this->LoadSingle("select * from ".$this->config['table_prefix']."users where name = '".mysql_real_escape_string($name)."' ".($password === 0 ? "" : "and password = '".mysql_real_escape_string($password)."'")." limit 1"); }
    */

    function LoadUser($name, $password = 0) {
           
            $user = $this->LoadSingle("select
         p.username as name
        ,p.user_password as password
        ,p.user_email as email
        ,p.user_regdate as signuptime
        ,w.revisioncount
        ,w.changescount
        ,w.doubleclickedit
        ,w.show_comments
        from "
.phpbb3_."users p
        left join "
. $this->config['table_prefix'] . "users w ON p.username = w.name
        where p.username = '"
.mysql_real_escape_string($name)."' and p.user_type != 1 limit 1");        
       
        if (isset($user['signuptime'])) {
            $user['signuptime'] = date('Y-m-d H:i:s', $user['signuptime']);
        }              
        return $user;


Find:
function LoadUsers() { return $this->LoadAll("select * from ".$this->config['table_prefix']."users order by name"); }


Replace With:
/**
    * PHPBB Integration
    *
    * function LoadUsers() { return $this->LoadAll("select * from ".$this->config['table_prefix']."users order by name"); }
    */

    function LoadUsers() { $users = $this->LoadAll("select
        p.username as name
        ,p.user_password as password
        ,p.user_email as email
        ,p.user_regdate as signuptime
        ,w.revisioncount
        ,w.changescount
        ,w.doubleclickedit
        ,w.show_comments
        from "
.phpbb3_."users p
        left join "
. $this->config['table_prefix'] . "users w ON p.username = w.name
        where p.user_type != 1
        order by username"
);

        foreach ($users as $key => $user) {

            if (isset($user['signuptime'])) {
                $user['signuptime'] = date('Y-m-d H:i:s', $user['signuptime']);
            }
            $users[$key] = $user;
        }

        return $users;
    }


Finally, add this block from phpass (via phpBB) right before the
?>
at the end of the file.
/**
*
* @version Version 0.1 / $Id: functions.php 8491 2008-04-04 11:41:58Z acydburn $
*
* Portable PHP password hashing framework.
*
* Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
* the public domain.
*
* There's absolutely no warranty.
*
* The homepage URL for this framework is:
*
*   http://www.openwall.com/phpass/
*
* Please be sure to update the Version line if you edit this file in any way.
* It is suggested that you leave the main version number intact, but indicate
* your project name (after the slash) and add your own revision information.
*
* Please do not change the "private" password hashing method implemented in
* here, thereby making your hashes incompatible.  However, if you must, please
* change the hash type identifier (the "$P$") to something different.
*
* Obviously, since this code is in the public domain, the above are not
* requirements (there can be none), but merely suggestions.
*
*
* Hash the password
*/

function phpbb_hash($password)
{
    $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

    $random_state = unique_id();
    $random = '';
    $count = 6;

    if (($fh = @fopen('/dev/urandom', 'rb')))
    {
        $random = fread($fh, $count);
        fclose($fh);
    }

    if (strlen($random) < $count)
    {
        $random = '';

        for ($i = 0; $i < $count; $i += 16)
        {
            $random_state = md5(unique_id() . $random_state);
            $random .= pack('H*', md5($random_state));
        }
        $random = substr($random, 0, $count);
    }

    $hash = _hash_crypt_private($password, _hash_gensalt_private($random, $itoa64), $itoa64);

    if (strlen($hash) == 34)
    {
        return $hash;
    }

    return md5($password);
}

/**
* Check for correct password
*/

function phpbb_check_hash($password, $hash)
{
    $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    if (strlen($hash) == 34)
    {
        return (_hash_crypt_private($password, $hash, $itoa64) === $hash) ? true : false;
    }

    return (md5($password) === $hash) ? true : false;
}

/**
* Generate salt for hash generation
*/

function _hash_gensalt_private($input, &$itoa64, $iteration_count_log2 = 6)
{
    if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
    {
        $iteration_count_log2 = 8;
    }

    $output = '$H$';
    $output .= $itoa64[min($iteration_count_log2 + ((PHP_VERSION >= 5) ? 5 : 3), 30)];
    $output .= _hash_encode64($input, 6, $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;
}

/**
* The crypt function/replacement
*/

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

    // Check for correct hash
    if (substr($setting, 0, 3) != '$H$')
    {
        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 .= _hash_encode64($hash, 16, $itoa64);

    return $output;
}

/**
* Return unique id
* @param string $extra additional entropy
*/

function unique_id($extra = 'c')
{
    static $dss_seeded = false;
    global $config;

    $val = $config['rand_seed'] . microtime();
    $val = md5($val);
    /*
    $config['rand_seed'] = md5($config['rand_seed'] . $val . $extra);

    if ($dss_seeded !== true && ($config['rand_seed_last_update'] < time() - rand(1,10)))
    {
        set_config('rand_seed', $config['rand_seed'], true);
        set_config('rand_seed_last_update', time(), true);
        $dss_seeded = true;
    }
    */

    return substr($val, 4, 16);
}


/actions/usersettings.php

Find:
            default: // input is valid
                $this->Query('UPDATE '.$this->config['table_prefix'].'users SET '.
                    "email = '".mysql_real_escape_string($email)."', ".
                    "doubleclickedit = '".mysql_real_escape_string($doubleclickedit)."', ".
                    "show_comments = '".mysql_real_escape_string($show_comments)."', ".
                    "revisioncount = '".mysql_real_escape_string($revisioncount)."', ".
                    "changescount = '".mysql_real_escape_string($changescount)."' ".
                    "WHERE name = '".$user['name']."' LIMIT 1");


Replace With:
  default: // input is valid
                /**
                * PHPBB Integration
                *
                * Insert the user into the Wakka users table
                */

                $tmpUser = $this->LoadUser($user['name']);
                if (is_null($tmpUser['show_comments'])) {
                    $this->Query("INSERT INTO ".$this->config['table_prefix']."users SET ".
                        "signuptime = '".mysql_real_escape_string($user['signuptime'])."',".
                        "name = '".mysql_real_escape_string($user['name'])."', ".
                        "email = '".mysql_real_escape_string($user['email'])."'");
                }
                /**
                * End PHPBB Integration
                */


Find:
case (md5($_POST['password']) != $existingUser['password']):                   
                    $error = ERROR_WRONG_PASSWORD;
                    $password_highlight = INPUT_ERROR_STYLE;
                    break;


Replace With:
                case (!phpbb_check_hash($_POST['password'],$existingUser['password'])):                
                    $error = ERROR_WRONG_PASSWORD;
                    $password_highlight = INPUT_ERROR_STYLE;
                    break;


/actions/highscores.php

Find:
    $str = 'SELECT Count(*) AS cnt, `name`  FROM ';
    $str .= $this->config["table_prefix"] . 'users, ' ;
    $str .= $this->config["table_prefix"].'pages ';
    $str .= "WHERE `name` = `owner` AND `latest` = 'Y' GROUP BY name ORDER BY cnt DESC;";


Replace with:
    $str = 'SELECT Count(*) AS cnt, `username` AS name  FROM phpbb3_users, ' ;
    $str .= $this->config["table_prefix"].'pages ';
    $str .= "WHERE `username` = `owner` AND `latest` = 'Y' GROUP BY username ORDER BY cnt DESC;";



Configuration to disable UserRegistration is still required, either patch for 1.1.6.2 or update config setting in 1.1.6.3 (or later) see UserRegistration for more details. See the phpBB 2.x integration page for info about how to edit phpBB to force Wiki-style usernames. On my install this works fine with usernames containing spaces, no caps, etc.

There are 5 comments on this page. [Show comments]
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki