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

1

12

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)

Addition answered 19/6, 2016 at 16:12 Comment(2)
If I am completely off track with what I want to do I would also like your feedback. I have very limited resources at my disposal, which is my most pressing reason for trying to incorporate an existing sollution into my application.Addition
Please view my answer below. I think you'll find it useful.Torpid
T
3

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.

Torpid answered 8/7, 2016 at 9:4 Comment(6)
Thank you for the Answer. It will take me some time to make the best of your analysis, but I have awarded you the bounty nontheless since it would expire soon otherwise. This will give me some new venues of approach to my problem and will help me greatly.Addition
Thank you! If you have any other questions or need me to clarify anything let me know and I will edit the answer as appropriate.Torpid
Creating a new auth provider would replace the existing one for phpbb as far as the documentation says since only one provider can be active at a time (which is managed through phpbb acp). So - would I have to create a whole new authentication scheme for use with both phpbb and my own application, or is there a way to include/use the existing defaut authentication provider used in phpbb? If so I would have to get a reference to phpbb_container in order to retrieve the provider. I cannot see what the difference would be between the existing and a possible new provider. I will look further.Addition
I do not have a complete understanding of the matter, so I assume that authentication providers are primarily used to integrate enterprise authentication sollutions and replace the default authentication. If I make my own implementation I would still have an authentication that is used in the scope of phpbb only and would have to be implemented separately for my own application - as long as I do not have direct access to the active phpbb session and it's variables. I will continue to do my research...Addition
@elfwyn, it is correct that the authentication providers are used to integrate different solutions together. Since I do not know the scope of your Zend Project, this is the one solution that will be more likely to succeed. You will always have two separate tables/sessions going on. It's a matter of having both work for each other (including the logout) if you want a seamless experience. E.g. signing in on the Zend App will also sign you into the forum, and viceversa. The only way around this would be to rewrite the session management for phpBB (which i don't think is what you're looking for)Torpid
This phpbb3 article still states the above approach as a viable route: phpbb.com/support/docs/en/3.0/kb/article/… - sadly thats not compatible with Zend it seems. I guess - since I do not find anything on the matter of cross-session communication that this is not possible by design in PHP. Since the user has both session cookies from the same domain I could have had access the login data from the phpbb session otherwise.Addition

© 2022 - 2024 — McMap. All rights reserved.