Appendix A. Single Sign-On in PhpBB3

Table of Contents

1. Overview
2. Configuring Cookies in PhpBB3
3. Who's logged into PhpBB3?
4. Getting PhpBB3 to return user after login
5. Algorithm for managing a remote session
Example Remote Session Class
Example Local Session Class

1. Overview

It is possible to implement SSO across machines with phpBB3 as long as the same primary domain name exists in all locations. PhpBB3 stores the session information and the user id in cookies. This section describes a way of making it all work together.

2. Configuring Cookies in PhpBB3

PhpBB3's cookies must be configured to ensure they will appear on other sites in the domain.

  • Enter the PhpBB3 admin panel

  • Click on General tab

  • Click on Cookie Settings link to the left.

  • Set the Cookie domain to the primary with no sub domain name like "mysite.com".

  • Set the Cookie name to something unique like "phpbb3_mysite"

  • Set the Cookie path to "/"

3. Who's logged into PhpBB3?

PhpBB3 creates a few cookies for different reasons all prefixed with the configured cookie name. The one that matters is the current user id which has the suffix _u. In the example above, the cookie name will be phpbb3_mysite_u. Anonymous, not logged in, users are identified with the value 1.

The user cookie only contains the user id number as it appears in the forum's private database. Convert this to the useful user name, using the PhpBB3Naruto::getUser() method.

4. Getting PhpBB3 to return user after login

PhpBB3 only redirects users to pages inside of PhpBB3 after login. To get around this limitation. Just create the following file in PhpBB3's root directory. For this example, this file will be called xlogin.php.


<?php
  define('COOKIE_DOMAIN', '.mysite.com');
  define('COOKIE_LOGIN_TO', 'xlogin_to'); 
  if (!empty($_COOKIE[COOKIE_LOGIN_TO])) {
      $loc = $_COOKIE[COOKIE_LOGIN_TO];
      setcookie(COOKIE_LOGIN_TO, '', 10, '/', COOKIE_DOMAIN);
  } else {
      $loc = '/';
  }
  header('Location: ' . $loc);
?>
<html>
<head>
<title>Successfully Logged IN</title>
<meta http-equiv="refresh" content="0; URL=<?=$loc?>"/>
</head>
<body>
Redirecting to <a href="<?=$loc?>"><?=$loc?></a>
</body>
</html>

This file simply grabs a cookie named xlogin_to and then redirects the user to that location. The simple example flow is:

  • www.mysite.com detects that the user is not logged in

  • www.mysite.com creates a cookie called xlogin_to setting the current URL as the value.

  • www.mysite.com redirects user to PhpBB3's login page (http://forum.mysite.com/ucp.php?mode=login&redirect=xlogin.php)

  • PhpBB3 logs the user in and redirects to xlogin.php

  • xlogin.php grabs the xlogin_to cookie, deletes it and redirects user back to original page as www.mysite.com

5. Algorithm for managing a remote session

The following pseudo code will provide a simple example how it manage a local session against PhpBB3 remote session. Consider that $remoteSession session in a class that just looks the PhpBB3's user cookie and redirects the user to login only when needed. Similarly, the $localSession uses the local php session tools to store login information.


    if ($remoteSession->isLoggedIn())
    {
        if ($localSession->remoteIsLoggedIn($remoteSession->getUserId()))
            return true;
        return $localSession->remoteLogin($remoteSession);
    }
    if ($localSession->isLoggedIn())
        $localSession->logout();
    if (!$required || !$remoteSession->login($url)) // may redirect
        return false;
    return $localSession->login($url);
    }

Example Remote Session Class

<?php
  class RemotePhpBB3Session
  {
      const COOKIE_LOGIN_TO = 'xlogin_to';
      
      public function RemotePhpBB3Session($cookie_domain, $cookie_sid_key, $cookie_uid_key, $forum_url)
      {
          $this->cookie_domain = $cookie_domain;
          $this->cookie_sid_key = $cookie_sid_key;
          $this->cookie_uid_key = $cookie_uid_key;
          $this->forum_url = $forum_url;
      }
      
      public function isLoggedIn()
      {
          global $_COOKIE;
          return !empty($_COOKIE[$this->cookie_uid_key]) && $_COOKIE[$this->cookie_uid_key] != 1;
      }
      
      public function login($url)
      {
          setcookie(RemotePhpBB3Session::COOKIE_LOGIN_TO, $url, 0, '/', $this->cookie_domain);
          $this->_redirect($this->forum_url . '/ucp.php?mode=login&redirect=xlogin.php');
      }
      
      
      public function getUserId()
      {
          global $_COOKIE;
          if (!$this->isloggedIn())
              return null;
          return $_COOKIE[$this->cookie_uid_key];
      }
      
      public function logout()
      {
          global $_COOKIE;
          if (empty($_COOKIE[$this->cookie_sid_key]))
              return true;
          $this->_redirect($this->forum_url . '/ucp.php?mode=logout&sid=' . $_COOKIE[$this->cookie_sid_key]);
      }
  }
?>
    

Example Local Session Class


<?php
  class LocalSession
  {
      public function LocalSession($session_name, $session_uid_key, $session_remote_uid_key)
      {
          $this->session_uid_key = $session_uid_key;
          $this->session_remote_uid_key = $session_remote_uid_key;
          session_name($session_name);
          session_start();
          if (!isset($_SESSION))
              $_SESSION = array();
      }
      
      public function isLoggedIn()
      {
          global $_SESSION;
          return isset($_SESSION[$this->session_uid_key]);
      }
      
      public function remoteIsLoggedIn($remote_id)
      {
          global $_SESSION;
          if ($remote_id !== false && (!isset($_SESSION[$this->session_remote_uid_key]) || $_SESSION[$this->session_remote_uid_key] != $remote_id))
              return false;
          return isset($_SESSION[$this->session_uid_key]);
      }
      
      public function remoteLogin($remoteSession)
      {
          global $_SESSION;
          if (($remoteId = $remoteSession->getUserId()) === null)
              return false;
          if (($localId = $this->_getLocalUserId($remoteId)) === false)
              return false;
          $_SESSION[$this->session_uid_key] = $localId;
          $_SESSION[$this->session_remote_uid_key] = $remoteSession->getUserId();
          return true;
      }
      
      public function logout()
      {
          global $_SESSION;
          $_SESSION = array();
          setcookie(session_name(), '', time() - 42000, '/');
          session_destroy();
      }
      
      public function getUserId()
      {
          global $_SESSION;
          if (empty($_SESSION[$this->session_uid_key]))
              return null;
          return $_SESSION[$this->session_uid_key];
      }
  }
?>