Single Sign-On with SugarCRM and RoundCube Using Multiple PHP Sessions

I am currently involved in an interesting integration project at work.  As part of it, we need to create a single sign-on process between SugarCRM (version 6.5.20) and RoundCube (version 1.1.4) webmail application.  RoundCube webmail is being displayed within the iframe inside the SugarCRM user interface, so it would help if users didn’t have to login to RoundCube since they are already authenticated in SugarCRM.

Once the user is authenticated in the SugarCRM, a PHP session is created with, among other information, authenticated user ID.  Using that ID, we can fetch the full user record and get his IMAP credentials, necessary for the RoundCube login.  While this wasn’t too difficult, there were a couple of road bumps that I’d like to document here, so that next time I won’t have to work it all out from scratch again.

So, first of all, the most obvious.  Both systems should use the same domain for cookies.  This is easy, if each one resides on it’s own sub-domain.  RoundCube provides a configuration variable that can be set in config/config.inc.php:

$config['session_domain'] = 'example.com';

SugarCRM is a bit dirtier and requires a modification in the core file include/MVC/SugarApplication.php, in function setCookie().  Since hard-coding values is a really bad practice, we use phpdotenv library to load configuration variables from .env file into the environment.  This is trivial, so I’m not going into the details.  Here’s the code snippet that we had to modify in the SugarCRM. From this:

if ( is_null($domain) )
  if ( isset($_SERVER["HTTP_HOST"]) )
    $domain = $_SERVER["HTTP_HOST"];
  else
    $domain = 'localhost';

to this:

if ( is_null($domain) )
  $cookie_domain = getenv('COOKIE_DOMAIN');
  if (!empty($cookie_domain))
    $domain = getenv('COOKIE_DOMAIN');
  else if ( isset($_SERVER["HTTP_HOST"]) )
    $domain = $_SERVER["HTTP_HOST"];
  else
    $domain = 'localhost';

Now, if we set COOKIE_DOMAIN=example.com in the .env file, both systems use the same domain for cookies.

Next we need to look at how to hook into the RoundCube initialization process, so that we could authenticate the user.  Gladly, RoundCube provides plugin functionality, and a number of plugin hooks that allow us to inject code easily.  Not only that, but there is an example autologon plugin, which demonstrates exactly the functionality that we need.

Now for the tricky part.  Both applications use PHP sessions.  SugarCRM defaults to the regular ‘PHPSESSID‘ session, while RoundCube uses its own ‘round_sessid‘ session.  Of course, we can reconfigure these applications to use the same session, but this causes a variety of issues, as they start, destroy, and overwrite session data without any concern for other involved parties.  It is better to keep them as they are.  But how can we work with both?  First of all, let’s see what exactly is that we are doing.  The flow is the like so:

  1. User navigates to the SugarCRM home page.
  2. SugarCRM starts the session named PHPSESSID.
  3. SugarCRM checks if the user is logged in.  He is not.  So the redirect to the login page is triggered.
  4. User inputs credentials and submits the login form.
  5. SugarCRM validates the credentials and if they are correct, populates the session (named ‘PHPSESSID‘) with user information (authenticated_user_id is what we are after).
  6. User is redirected to the home page of SugarCRM.
  7. User navigates to the SugarCRM page, which includes the iframe with RoundCube.
  8. Iframe initiates RoundCube.
  9. RoundCube starts the session named roundcube_sessid.
  10. RoundCube checks if the user is logged in. This is where we need to inject our code to help RoundCube do the correct checks.
  11. If the user is not logged, the redirect to the RoundCube login page (inside the iframe) is triggered.  If the user is logged in, he is redirected to his mailbox.

So, using the example logic of the autologon plugin, we need to do the following in the ‘authenticate’ hook:

  1. Save the current session ID (session name ‘roundcube_sessid‘).
  2. Switch to the session named PHPSESSID.
  3. Read the authenticated_user_id value from the session data.
  4. Switch back to the session named roundcube_sessid.
  5. Fetch the IMAP credentials from the SugarCRM for the RoundCube login.
  6. Let RoundCube continue with the authentication and the redirect to either the login form or user’s mailbox.

I am not going to go into the details of how to fetch the IMAP credentials, as this depends on each particular environment.  But what I want to leave here for the future reference is the example of how to switch between PHP sessions.  Stack Overflow was as useful as usual, thanks to this answer.  I had to slightly modify it though.  He is how the code looks in my case:

function authenticate($args)
{
  // Save RoundCube session ID
  $roundCubeSessionId = session_id();
  session_write_close();

  // Switch to PHPSESSID
  $phpSessionId = $_COOKIE['PHPSESSID'];
  session_id($phpSessionId);
  session_start();

  // Get SugarCRM user ID
  $username = $_SESSION['authenticated_user_id'];
  session_write_close();

  // Switch back to RoundCube session ID
  session_id($roundCubeSessionId);
  session_start();

  if (empty($username)) {
    return $args;
  }

  // proceed with fetching the IMAP credentials

That’s about it.

 

One thought on “Single Sign-On with SugarCRM and RoundCube Using Multiple PHP Sessions”

Leave a Comment