Getting CakePHP to use phpBB3 users and passwords

I'm tinkering with a small CakePHP app and I want to add users but allow them to authenticate against my phpBB3 forum credentials.  I found a few attempts and suggestions that didn't work for me and the bridge available in the Bakery isn't wwhat I wanted either.

After banging my head against a bit of stupid, I found it to be easy by just copying over some phpBB3 functions and following the CakePHP manual pages on changing Auth's hash function

User model (app/models/user.php)

class User extends AppModel {

	var $name = 'Users';

	var $useDbConfig  = 'phpbbdb'; // for users
	var $tablePrefix  = 'phpbb_';
	var $primaryKey   = 'user_id';
	var $displayField = 'username';

	// from phpbb code
	function _phpbb_check_hash($password, $hash)
	{
		$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
		if (strlen($hash) == 34)
		{
			return ($this->_hash_crypt_private($password, $hash, $itoa64) === $hash) ? true : false;
		}

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

	// from phpbb code
	function _phpbb_hash($password)
	{
		$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

		// customized here
		$random_state = $this->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($this->unique_id() . $random_state);
				$random .= pack('H*', md5($random_state));
			}
			$random = substr($random, 0, $count);
		}

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

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

		return md5($password);
	}

	// from phpbb code
	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 .= $this->_hash_encode64($hash, 16, $itoa64);

		return $output;
	}

	// from phpbb code
	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 .= $this->_hash_encode64($input, 6, $itoa64);

		return $output;
	}

	// from phpbb code
	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;
	}

    private 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 );
        
        $dss_seeded = true;
        return substr ( $val, 4, 16 );
    } 

	function hashPasswords($data)
	{
		if (isset($data['User']['user_password']))
		{
			$phpbb_pw = $this->field('user_password', array('username' => $data['User']['username']));
			if ($this->_phpbb_check_hash($data['User']['user_password'], $phpbb_pw))
			{
				$data['User']['user_password'] = $phpbb_pw;
			}

			return $data;
		}
		return $data;
	}

}

User controller (app/controllers/user_controller.php)

class UsersController extends AppController {

    var $name = 'Users';
    var $helpers = array('Html', 'Form');

    function beforeFilter()
    {
        $this->Auth->authenticate = ClassRegistry::init('User');

        $this->Auth->fields = array(
            'username' => 'username',
            'password' => 'user_password'
        );

        parent::beforeFilter();
    }

    function login()
    {
    }

    function logout()
    {
        $this->redirect($this->Auth->logout());
    }
}

Make sure to set up the login view and follow the other general instructions for auth in the CakePHP manual.

Comments

Look for the Authsome plugin. It will provide the same functionality

Thanks for this topic. It was helpfull.
But I would like to integrate my site into phpBB3 and when users were logged in forum then they automatically logged in site. Site placed in /some_folder in root directory of phpBB3. Can You propably help?

Add new comment