Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is "a" correct way to integrate a Zend2 application with PHPBB3 authentication?

Ok, this is a bit complicated, so bear with me.

I'm running a PHPBB Forum for some time now and my goal is to create a Zend2 PHP Application using its User Administration and Authentication Features instead of building up a completely new Authorization component which would in turn need to synchronize with the Forum again.

Following Components will be used in the live environment: PHPBB3, Zend Framework 2 (latest stable), Apache, PHP 5.6+, MySQL running on a virtual Linux server without root access.

My Development Environment (running all examples below)is: PHPBB3, Zend Framework 2 (latest stable), XAMPP 3.2.2, PHP 5.6.21 with xdebug enabled, MariaDB running on Windows 8.

Whenever integration of PHPBB is asked for the following lines inevitably turn up in searches:

global $phpbb_root_path, $phpEx, $user, $db, $config, $cache, $template;
define('IN_PHPBB', true);
$phpbb_root_path = './forum/phpBB3/'; // this path is from an external example
$phpEx = substr(strrchr(__FILE__, '.'), 1);
$phpBBFile = $phpbb_root_path . 'common.' . $phpEx;
include($phpBBFile);

// Start session management
$user->session_begin();
$auth->acl($user->data);
$user->setup();

I have already had success including those without using a framework or by calling php directly through ajax, but now - using the Zend 2 Framework - there are multiple problems surfacing when including native PHPBB3 code.

I have to say I am not an experienced PHP programmer and I have been learning about Zend for just a couple of days now.

My first try centered on integrating the above code before the Zend Application is called in Zends index.php:

....
// Setup autoloading
require 'init_autoloader.php';

global $phpbb_root_path, $phpEx, $user, $db, $config, $cache, $template;
define('IN_PHPBB', true);
$phpbb_root_path = 'public/forums/';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
$phpBBFile = $phpbb_root_path . 'common.' . $phpEx;
include($phpBBFile);

// Run the application!
Zend\Mvc\Application::init(require 'config/application.config.php')->run();
....

Resulting in this error:

Catchable fatal error: Argument 1 passed to Zend\Stdlib\Parameters::__construct() must be of the type array, object given, called in C:\xampp\htdocs\myZendApp\vendor\zendframework\zend-http\src\PhpEnvironment\Request.php on line 72 and defined in C:\xampp\htdocs\myZendApp\vendor\zendframework\zend-stdlib\src\Parameters.php on line 24

So calling PHPBB this early on seems to mess up Zend in a bad way I went on to other implementations.

My favored design would include a separate Authentication Zend Module which handles PHPBB authentication and is available as a service for all routes and their controllers. Including and calling the phpbb scripts however lead to various problems probably related to the heavy use of globals.

Here some example code from the checkAction in the PhpbbAuthController:

public function checkAction(){
    global $phpbb_root_path, $phpEx, $user, $db, $config, $cache, $template;
    define('IN_PHPBB', true);
    $phpbb_root_path = 'public/forums/';
    $phpEx = substr(strrchr(__FILE__, '.'), 1);
    $phpBBFile = $phpbb_root_path . 'common.' . $phpEx;
    include($phpBBFile);

    $user->session_begin();
    $auth->acl($user->data);
    $user->setup();

    $response = array();
    if ($user->data['user_id'] == ANONYMOUS) {
        $response['loginState'] = "logged_out";
    } else {
        $response['loginState'] = "logged_in";
    }
    return new ViewModel($response);
}

And here the error from executing session_begin()

Fatal error: Call to a member function header() on null in C:\xampp\htdocs\myZendApp\public\forums\phpbb\session.php on line 228

After debugging into it it seemed that all references to the $request and $symfony_request inside those authentication functions where NULL.

After sinking lots of hours into discerning a way to execute the scripts from Zend context I have set my eyes on a way to execute the scripts in a separate context. The easiest way that came to my mind was to call the script from an HttpClient and use the Result text to drive my Authentication Service. To do that I would need to retrieve the session cookie from the called scripts and store it for use in the Zend application.

If I channel the scripts through the Zend Framework I seem to run into the same problem again (having PHBB code in a Zend Controller), so I can't use Zends routing to access them. Since I am using an http request I have to store the scripts in the public directory or a subdirectory of it.

And that is where I am right now. The internal call to the php files that use PHPBB work fine on their own, but the HttpClient I use (from a Zend Controller class for now) does run into a timeout at every turn, which I formulated into another question here: Zend 2 Http Client Request times out when requesting php file from localhost/public directory.

I would appreciate your views, hints and possible architectures or even part solutions to my problem/s mentioned above.

What I do not want to do under any circumstances is to invent my own authentication and user administration as it would always be inferior to the complex but proven system which is already in PHPBB and lead to security issues in the long run. Also the Zend application is considered an "Extra" since the Forum is the core of the site as things stand now.

Thank you very much for your time and please ask for additional information. (I couldn't possible include all the code and I don't know what else would be relevant to you at this point)

like image 562
elfwyn Avatar asked Jun 19 '16 16:06

elfwyn


1 Answers

PHPBB 3.x is based on symfony and uses symfony components. The posts you are referencing are extremely outdated.

Please take a look at: https://github.com/phpbb/phpbb/blob/3.1.x/phpBB/config/auth.yml (the container's definition of authentication providers for PHPBB3)

Version on master https://github.com/phpbb/phpbb/blob/master/phpBB/config/default/container/services_auth.yml

AND

https://github.com/phpbb/phpbb/blob/3.1.x/phpBB/phpbb/auth/provider/provider_interface.php (shown below)

<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\auth\provider;
/**
* The interface authentication provider classes have to implement.
*/
interface provider_interface
{
    /**
     * Checks whether the user is currently identified to the authentication
     * provider.
     * Called in acp_board while setting authentication plugins.
     * Changing to an authentication provider will not be permitted in acp_board
     * if there is an error.
     *
     * @return  boolean|string  False if the user is identified, otherwise an
     *                          error message, or null if not implemented.
     */
    public function init();
    /**
     * Performs login.
     *
     * @param   string  $username   The name of the user being authenticated.
     * @param   string  $password   The password of the user.
     * @return  array   An associative array of the format:
     *                      array(
     *                          'status' => status constant
     *                          'error_msg' => string
     *                          'user_row' => array
     *                      )
     *                  A fourth key of the array may be present:
     *                  'redirect_data' This key is only used when 'status' is
     *                  equal to LOGIN_SUCCESS_LINK_PROFILE and its value is an
     *                  associative array that is turned into GET variables on
     *                  the redirect url.
     */
    public function login($username, $password);
    /**
     * Autologin function
     *
     * @return  array|null  containing the user row, empty if no auto login
     *                      should take place, or null if not impletmented.
     */
    public function autologin();
    /**
     * This function is used to output any required fields in the authentication
     * admin panel. It also defines any required configuration table fields.
     *
     * @return  array|null  Returns null if not implemented or an array of the
     *                      configuration fields of the provider.
     */
    public function acp();
    /**
     * This function updates the template with variables related to the acp
     * options with whatever configuraton values are passed to it as an array.
     * It then returns the name of the acp file related to this authentication
     * provider.
     * @param   array   $new_config Contains the new configuration values that
     *                              have been set in acp_board.
     * @return  array|null      Returns null if not implemented or an array with
     *                          the template file name and an array of the vars
     *                          that the template needs that must conform to the
     *                          following example:
     *                          array(
     *                              'TEMPLATE_FILE' => string,
     *                              'TEMPLATE_VARS' => array(...),
     *                          )
     *                          An optional third element may be added to this
     *                          array: 'BLOCK_VAR_NAME'. If this is present,
     *                          then its value should be a string that is used
     *                          to designate the name of the loop used in the
     *                          ACP template file. When this is present, an
     *                          additional key named 'BLOCK_VARS' is required.
     *                          This must be an array containing at least one
     *                          array of variables that will be assigned during
     *                          the loop in the template. An example of this is
     *                          presented below:
     *                          array(
     *                              'BLOCK_VAR_NAME'    => string,
     *                              'BLOCK_VARS'        => array(
     *                                  'KEY IS UNIMPORTANT' => array(...),
     *                              ),
     *                              'TEMPLATE_FILE' => string,
     *                              'TEMPLATE_VARS' => array(...),
     *                          )
     */
    public function get_acp_template($new_config);
    /**
    * Returns an array of data necessary to build custom elements on the login
    * form.
    *
    * @return   array|null  If this function is not implemented on an auth
    *                       provider then it returns null. If it is implemented
    *                       it will return an array of up to four elements of
    *                       which only 'TEMPLATE_FILE'. If 'BLOCK_VAR_NAME' is
    *                       present then 'BLOCK_VARS' must also be present in
    *                       the array. The fourth element 'VARS' is also
    *                       optional. The array, with all four elements present
    *                       looks like the following:
    *                       array(
    *                           'TEMPLATE_FILE'     => string,
    *                           'BLOCK_VAR_NAME'    => string,
    *                           'BLOCK_VARS'        => array(...),
    *                           'VARS'              => array(...),
    *                       )
    */
    public function get_login_data();
    /**
     * Performs additional actions during logout.
     *
     * @param   array   $data           An array corresponding to
     *                                  \phpbb\session::data
     * @param   boolean $new_session    True for a new session, false for no new
     *                                  session.
     */
    public function logout($data, $new_session);
    /**
     * The session validation function checks whether the user is still logged
     * into phpBB.
     *
     * @param   array   $user
     * @return  boolean true if the given user is authenticated, false if the
     *                  session should be closed, or null if not implemented.
     */
    public function validate_session($user);
    /**
    * Checks to see if $login_link_data contains all information except for the
    * user_id of an account needed to successfully link an external account to
    * a forum account.
    *
    * @param    array   $login_link_data    Any data needed to link a phpBB account to
    *                               an external account.
    * @return   string|null Returns a string with a language constant if there
    *                       is data missing or null if there is no error.
    */
    public function login_link_has_necessary_data($login_link_data);
    /**
    * Links an external account to a phpBB account.
    *
    * @param    array   $link_data  Any data needed to link a phpBB account to
    *                               an external account.
    */
    public function link_account(array $link_data);
    /**
    * Returns an array of data necessary to build the ucp_auth_link page
    *
    * @param int $user_id User ID for whom the data should be retrieved.
    *                       defaults to 0, which is not a valid ID. The method
    *                       should fall back to the current user's ID in this
    *                       case.
    * @return   array|null  If this function is not implemented on an auth
    *                       provider then it returns null. If it is implemented
    *                       it will return an array of up to four elements of
    *                       which only 'TEMPLATE_FILE'. If 'BLOCK_VAR_NAME' is
    *                       present then 'BLOCK_VARS' must also be present in
    *                       the array. The fourth element 'VARS' is also
    *                       optional. The array, with all four elements present
    *                       looks like the following:
    *                       array(
    *                           'TEMPLATE_FILE'     => string,
    *                           'BLOCK_VAR_NAME'    => string,
    *                           'BLOCK_VARS'        => array(...),
    *                           'VARS'              => array(...),
    *                       )
    */
    public function get_auth_link_data($user_id = 0);
    /**
    * Unlinks an external account from a phpBB account.
    *
    * @param    array   $link_data  Any data needed to unlink a phpBB account
    *                               from a phpbb account.
    */
    public function unlink_account(array $link_data);
}

The interface you can implement to create a provider for your Zend framework project.

You can see how the providers are used when a session is created

https://github.com/phpbb/phpbb/blob/master/phpBB/phpbb/session.php#L560

    /* @var $provider_collection \phpbb\auth\provider_collection */
    $provider_collection = $phpbb_container->get('auth.provider_collection');
    $provider = $provider_collection->get_provider();
    $this->data = $provider->autologin();

Make sure both projects use the same cookies, or that zend is also setting the phpBB cookies and session when a user is logging in as session_start uses this to look for session ids:

    if ($request->is_set($config['cookie_name'] . '_sid', \phpbb\request\request_interface::COOKIE) || $request->is_set($config['cookie_name'] . '_u', \phpbb\request\request_interface::COOKIE))
    {
        $this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0, false, true);
        $this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', '', false, true);
        $this->session_id       = request_var($config['cookie_name'] . '_sid', '', false, true);

        $SID = (defined('NEED_SID')) ? '?sid=' . $this->session_id : '?sid=';
        $_SID = (defined('NEED_SID')) ? $this->session_id : '';

        if (empty($this->session_id))
        {
            $this->session_id = $_SID = request_var('sid', '');
            $SID = '?sid=' . $this->session_id;
            $this->cookie_data = array('u' => 0, 'k' => '');
        }
    }
    else
    {
        $this->session_id = $_SID = request_var('sid', '');
        $SID = '?sid=' . $this->session_id;
    }

Thank you.

like image 110
vpassapera Avatar answered Nov 05 '22 10:11

vpassapera