{"id":25961,"date":"2016-03-20T18:39:10","date_gmt":"2016-03-20T16:39:10","guid":{"rendered":"https:\/\/mamchenkov.net\/wordpress\/?p=25961"},"modified":"2016-12-12T11:32:45","modified_gmt":"2016-12-12T09:32:45","slug":"single-sign-on-sugarcrm-roundcube-multiple-php-sessions","status":"publish","type":"post","link":"https:\/\/mamchenkov.net\/wordpress\/2016\/03\/20\/single-sign-on-sugarcrm-roundcube-multiple-php-sessions\/","title":{"rendered":"Single Sign-On with SugarCRM and RoundCube Using Multiple PHP Sessions"},"content":{"rendered":"<!-- google_ad_section_start -->\n<p>I am currently involved in an interesting integration project at work. \u00a0As part of it, we need to create a single sign-on process between\u00a0<a href=\"https:\/\/www.sugarcrm.com\/\">SugarCRM<\/a> (version 6.5.20) and <a href=\"https:\/\/roundcube.net\/\">RoundCube<\/a> (version 1.1.4) webmail application. \u00a0RoundCube webmail is being displayed within the iframe inside the SugarCRM user interface, so it would help if users didn&#8217;t have to login to RoundCube since they are already authenticated in SugarCRM.<\/p>\n<p>Once the user is authenticated in the SugarCRM, a PHP session is created with, among other information, authenticated user ID. \u00a0Using that ID, we can fetch the full user record and get his IMAP credentials, necessary for the RoundCube login. \u00a0While this wasn&#8217;t too difficult, there were a couple of road bumps that I&#8217;d like to document here, so that next time I won&#8217;t have to work it all out from scratch again.<\/p>\n<p><!--more--><\/p>\n<p>So, first of all, the most obvious. \u00a0Both systems should use the same domain for cookies. \u00a0This is easy, if each one resides on it&#8217;s own sub-domain. \u00a0RoundCube provides a configuration variable that can be set in <em>config\/config.inc.php<\/em>:<\/p>\n<pre class=\"brush: php; light: true; title: ; notranslate\" title=\"\">\r\n$config&#x5B;'session_domain'] = 'example.com';\r\n<\/pre>\n<p>SugarCRM is a bit dirtier and requires a modification in the core file <em>include\/MVC\/SugarApplication.php<\/em>, in function <em>setCookie()<\/em>. \u00a0Since hard-coding values is a really bad practice, we use <a href=\"https:\/\/github.com\/vlucas\/phpdotenv\">phpdotenv<\/a> library to load configuration variables from <em>.env<\/em> file into the environment. \u00a0This is trivial, so I&#8217;m not going into the details. \u00a0Here&#8217;s the code snippet that we had to modify in the SugarCRM. From this:<\/p>\n<pre class=\"brush: php; light: true; title: ; notranslate\" title=\"\">\r\nif ( is_null($domain) )\r\n  if ( isset($_SERVER&#x5B;&quot;HTTP_HOST&quot;]) )\r\n    $domain = $_SERVER&#x5B;&quot;HTTP_HOST&quot;];\r\n  else\r\n    $domain = 'localhost';\r\n<\/pre>\n<p>to this:<\/p>\n<pre class=\"brush: php; light: true; title: ; notranslate\" title=\"\">\r\nif ( is_null($domain) )\r\n  $cookie_domain = getenv('COOKIE_DOMAIN');\r\n  if (!empty($cookie_domain))\r\n    $domain = getenv('COOKIE_DOMAIN');\r\n  else if ( isset($_SERVER&#x5B;&quot;HTTP_HOST&quot;]) )\r\n    $domain = $_SERVER&#x5B;&quot;HTTP_HOST&quot;];\r\n  else\r\n    $domain = 'localhost';\r\n<\/pre>\n<p>Now, if we set <em>COOKIE_DOMAIN=example.com<\/em> in the <em>.env<\/em> file, both systems use the same domain for cookies.<\/p>\n<p>Next we need to look at how to hook into the RoundCube initialization process, so that we could authenticate the user. \u00a0Gladly, RoundCube provides plugin functionality, and a number of <a href=\"http:\/\/trac.roundcube.net\/wiki\/Plugin_Hooks\">plugin hooks<\/a> that allow us to inject code easily. \u00a0Not only that, but there is an <a href=\"https:\/\/github.com\/roundcube\/roundcubemail\/blob\/master\/plugins\/autologon\/autologon.php\">example autologon plugin<\/a>, which demonstrates exactly the functionality that we need.<\/p>\n<p>Now for the tricky part. \u00a0Both applications use PHP sessions. \u00a0SugarCRM defaults to the regular &#8216;<em>PHPSESSID<\/em>&#8216; session, while RoundCube uses its own &#8216;<em>round_sessid<\/em>&#8216; session. \u00a0Of 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. \u00a0It is better to keep them as they are. \u00a0But how can we work with both? \u00a0First of all, let&#8217;s see what exactly is that we are doing. \u00a0The flow is the like so:<\/p>\n<ol>\n<li>User navigates to the SugarCRM home page.<\/li>\n<li>SugarCRM starts the session named <em>PHPSESSID<\/em>.<\/li>\n<li>SugarCRM checks if the user is logged in. \u00a0He is not. \u00a0So the redirect to the login page is triggered.<\/li>\n<li>User inputs credentials and submits the login form.<\/li>\n<li>SugarCRM validates the credentials and if they are correct, populates the session (named &#8216;<em>PHPSESSID<\/em>&#8216;) with user information (<em>authenticated_user_id<\/em> is what we are after).<\/li>\n<li>User is redirected to the home page of SugarCRM.<\/li>\n<li>User navigates to the SugarCRM page, which includes the iframe with RoundCube.<\/li>\n<li>Iframe initiates RoundCube.<\/li>\n<li>RoundCube starts the session named <em>roundcube_sessid<\/em>.<\/li>\n<li>RoundCube checks if the user is logged in. This is where we need to inject our code to help RoundCube do the correct checks.<\/li>\n<li>If the user is not logged, the redirect to the RoundCube login page (inside the iframe) is triggered. \u00a0If the user is logged in, he is redirected to his mailbox.<\/li>\n<\/ol>\n<p>So, using the example logic of the autologon plugin, we need to do the following in the &#8216;authenticate&#8217; hook:<\/p>\n<ol>\n<li>Save the current session ID (session name &#8216;<em>roundcube_sessid<\/em>&#8216;).<\/li>\n<li>Switch to the session named <em>PHPSESSID<\/em>.<\/li>\n<li>Read the <em>authenticated_user_id<\/em> value from the session data.<\/li>\n<li>Switch back to the session named <em>roundcube_sessid<\/em>.<\/li>\n<li>Fetch the IMAP credentials from the SugarCRM for the RoundCube login.<\/li>\n<li>Let RoundCube continue with the authentication and the redirect to either the login form or user&#8217;s mailbox.<\/li>\n<\/ol>\n<p>I am not going to go into the details of how to fetch the IMAP credentials, as this depends on each particular environment. \u00a0But what I want to leave here for the future reference is the example of how to switch between PHP sessions. \u00a0<a href=\"http:\/\/stackoverflow.com\/\">Stack Overflow<\/a> was as useful as usual, thanks to <a href=\"http:\/\/stackoverflow.com\/a\/24965106\/151647\">this answer<\/a>. \u00a0I had to slightly modify it though. \u00a0He is how the code looks in my case:<\/p>\n<pre class=\"brush: php; light: true; title: ; notranslate\" title=\"\">\r\nfunction authenticate($args)\r\n{\r\n  \/\/ Save RoundCube session ID\r\n  $roundCubeSessionId = session_id();\r\n  session_write_close();\r\n\r\n  \/\/ Switch to PHPSESSID\r\n  $phpSessionId = $_COOKIE&#x5B;'PHPSESSID'];\r\n  session_id($phpSessionId);\r\n  session_start();\r\n\r\n  \/\/ Get SugarCRM user ID\r\n  $username = $_SESSION&#x5B;'authenticated_user_id'];\r\n  session_write_close();\r\n\r\n  \/\/ Switch back to RoundCube session ID\r\n  session_id($roundCubeSessionId);\r\n  session_start();\r\n\r\n  if (empty($username)) {\r\n    return $args;\r\n  }\r\n\r\n  \/\/ proceed with fetching the IMAP credentials\r\n<\/pre>\n<p>That&#8217;s about it.<\/p>\n<p>&nbsp;<\/p>\n<!-- google_ad_section_end -->\n","protected":false},"excerpt":{"rendered":"<!-- google_ad_section_start -->\n<p>I am currently involved in an interesting integration project at work. \u00a0As part of it, we need to create a single sign-on process between\u00a0SugarCRM (version 6.5.20) and RoundCube (version 1.1.4) webmail application. \u00a0RoundCube webmail is being displayed within the iframe inside the SugarCRM user interface, so it would help if users didn&#8217;t have to login &hellip; <a href=\"https:\/\/mamchenkov.net\/wordpress\/2016\/03\/20\/single-sign-on-sugarcrm-roundcube-multiple-php-sessions\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Single Sign-On with SugarCRM and RoundCube Using Multiple PHP Sessions<\/span><\/a><\/p>\n<!-- google_ad_section_end -->\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Single Sign-On with SugarCRM and RoundCube Using Multiple PHP Sessions #SugarCRM #RoundCube #PHP #WebDev","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_links_to":"","_links_to_target":""},"categories":[1,18,62,1334],"tags":[38,3411,3474,1538,1330],"keyring_services":[],"class_list":["post-25961","post","type-post","status-publish","format-standard","hentry","category-general","category-programming","category-technology","category-web-work","tag-php","tag-roundcube","tag-single-sign-on","tag-sugarcrm","tag-web-development"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":26001,"url":"https:\/\/mamchenkov.net\/wordpress\/2016\/04\/06\/sugarcrm-roundcube-and-request-tracker-integration-on-a-single-domain\/","url_meta":{"origin":25961,"position":0},"title":"SugarCRM, RoundCube and Request Tracker integration on a single domain","author":"Leonid Mamchenkov","date":"April 6, 2016","format":false,"excerpt":"In my years of working as a system administrator I've done some pretty complex setups and integration solutions, but I don't think I've done anything as twisted as this one recently. \u00a0The setup is part of the large and complex client project, built on their infrastructure, with quite a few\u2026","rel":"","context":"In &quot;All&quot;","block_context":{"text":"All","link":"https:\/\/mamchenkov.net\/wordpress\/category\/general\/"},"img":{"alt_text":"SAML workflow","src":"https:\/\/i0.wp.com\/mamchenkov.net\/wordpress\/wp-content\/uploads\/2016\/04\/saml_workflow_vertical-500x469.gif?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":26031,"url":"https:\/\/mamchenkov.net\/wordpress\/2016\/04\/18\/single-sign-on-between-sugarcrm-and-request-tracker\/","url_meta":{"origin":25961,"position":1},"title":"Single Sign-On Between SugarCRM and Request Tracker","author":"Leonid Mamchenkov","date":"April 18, 2016","format":false,"excerpt":"As mentioned\u00a0before,\u00a0over the last few month I've been involved in quite a few integration projects, using mostly SugarCRM and Request Tracker. \u00a0One of the interesting challenges was the Single Sign-On (SSO) between the two. The interesting bit comes from these facts: Different technologies: SugarCRM is written in PHP, while Request\u2026","rel":"","context":"In &quot;All&quot;","block_context":{"text":"All","link":"https:\/\/mamchenkov.net\/wordpress\/category\/general\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":26165,"url":"https:\/\/mamchenkov.net\/wordpress\/2016\/06\/06\/rainloop-simple-modern-and-fast-web-based-email-client\/","url_meta":{"origin":25961,"position":2},"title":"RainLoop &#8211; simple, modern, and fast web-based email client","author":"Leonid Mamchenkov","date":"June 6, 2016","format":false,"excerpt":"For those of you who want something more than the classic-looking RoundCube, here's the RainLoop - simple, modern, and fast web-based email client. \u00a0The feature list is very comparable, yet the interface is somewhat different, looking more like Gmail, than the Outlook Express.","rel":"","context":"In &quot;All&quot;","block_context":{"text":"All","link":"https:\/\/mamchenkov.net\/wordpress\/category\/general\/"},"img":{"alt_text":"rainloop","src":"https:\/\/i0.wp.com\/mamchenkov.net\/wordpress\/wp-content\/uploads\/2016\/06\/rainloop-500x376.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":11326,"url":"https:\/\/mamchenkov.net\/wordpress\/2008\/08\/03\/innodb-is-better-for-sugarcrm\/","url_meta":{"origin":25961,"position":3},"title":"InnoDB is better for SugarCRM","author":"Leonid Mamchenkov","date":"August 3, 2008","format":false,"excerpt":"After SugarCRM was deployed, we were experiencing some lock ups.\u00a0 Not frequent or dangerous, but annoying.\u00a0 About once a week or every ten days or so, SugarCRM would lock up and won't answer any queries at all.\u00a0 Not even the login was possible.\u00a0 A brief investigation showed that somehow it\u2026","rel":"","context":"In &quot;All&quot;","block_context":{"text":"All","link":"https:\/\/mamchenkov.net\/wordpress\/category\/general\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":26232,"url":"https:\/\/mamchenkov.net\/wordpress\/2016\/07\/13\/sugarcrm-cache-directory-it-is-not-a-cache-directory\/","url_meta":{"origin":25961,"position":4},"title":"SugarCRM cache directory \u2013 it is NOT a cache directory!","author":"Leonid Mamchenkov","date":"July 13, 2016","format":false,"excerpt":"Here is a useful reminder from a few years back - \"SugarCRM cache directory \u2013 it is NOT a cache directory!\". \u00a0 Unlike most modern day web applications, which use cache\/ folder for temporary files, which are safe to delete, SugarCRM keeps a bunch of stuff in there, which, if\u2026","rel":"","context":"In &quot;All&quot;","block_context":{"text":"All","link":"https:\/\/mamchenkov.net\/wordpress\/category\/general\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":26028,"url":"https:\/\/mamchenkov.net\/wordpress\/2016\/04\/18\/working-with-encrypted-values-in-sugarcrm-6-5\/","url_meta":{"origin":25961,"position":5},"title":"Working with encrypted values in SugarCRM 6.5","author":"Leonid Mamchenkov","date":"April 18, 2016","format":false,"excerpt":"SugarCRM comes with a variety of modules that store values in the database. \u00a0Some of those values are encrypted. \u00a0For example, mailbox passwords for inbound and outbound email configurations. When you create this configurations through the web interface or the API, you don't need to worry about encryption, as SugarCRM\u2026","rel":"","context":"In &quot;All&quot;","block_context":{"text":"All","link":"https:\/\/mamchenkov.net\/wordpress\/category\/general\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_sharing_enabled":true,"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/posts\/25961","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/comments?post=25961"}],"version-history":[{"count":0,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/posts\/25961\/revisions"}],"wp:attachment":[{"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/media?parent=25961"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/categories?post=25961"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/tags?post=25961"},{"taxonomy":"keyring_services","embeddable":true,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/keyring_services?post=25961"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}