{"id":26031,"date":"2016-04-18T12:57:32","date_gmt":"2016-04-18T10:57:32","guid":{"rendered":"https:\/\/mamchenkov.net\/wordpress\/?p=26031"},"modified":"2016-12-12T11:31:01","modified_gmt":"2016-12-12T09:31:01","slug":"single-sign-on-between-sugarcrm-and-request-tracker","status":"publish","type":"post","link":"https:\/\/mamchenkov.net\/wordpress\/2016\/04\/18\/single-sign-on-between-sugarcrm-and-request-tracker\/","title":{"rendered":"Single Sign-On Between SugarCRM and Request Tracker"},"content":{"rendered":"<!-- google_ad_section_start -->\n<p>As mentioned\u00a0before,\u00a0over the last few month I&#8217;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.<\/p>\n<p><!--more--><\/p>\n<p>The interesting bit comes from these facts:<\/p>\n<ul>\n<li>Different technologies: SugarCRM is written in PHP, while Request Tracker is in Perl.<\/li>\n<li>SugarCRM uses PHP sessions, which are <a href=\"https:\/\/mamchenkov.net\/wordpress\/2015\/07\/28\/php-session-encoding\/\">not very useful for other languages<\/a>.<\/li>\n<li>Request Tracker supports multiple external authentication mechanisms, but nothing that fits well with SugarCRM.<\/li>\n<\/ul>\n<p>Firstly, let&#8217;s see which mechanisms Request Tracker supports for external authentication. \u00a0For that, we need the documentation for <a href=\"http:\/\/search.cpan.org\/~falcone\/RT-Authen-ExternalAuth-0.25\/lib\/RT\/Authen\/ExternalAuth.pm\">RT::Authen::ExternalAuth<\/a> module. \u00a0The choices are:<\/p>\n<ol>\n<li>LDAP<\/li>\n<li>Database<\/li>\n<li>SSO Cookie<\/li>\n<\/ol>\n<p>LDAP was not an option in this project, so it was dismissed pretty much immediately. \u00a0SSO Cookie sounded like the best option, but after some poking around was also dismissed. \u00a0Firstly, SugarCRM does not set the SSO cookie, as it uses sessions, and modifying it to do so didn&#8217;t sound elegant. \u00a0Secondly, I couldn&#8217;t quite make all the sense out of the rather brief documentation for the\u00a0<a href=\"http:\/\/search.cpan.org\/~falcone\/RT-Authen-ExternalAuth-0.25\/lib\/RT\/Authen\/ExternalAuth\/DBI\/Cookie.pm\">RT::Authen::ExternalAuth::DBI::Cookie<\/a> module. \u00a0So I settled on the external MySQL database option.<\/p>\n<p><a href=\"http:\/\/search.cpan.org\/~falcone\/RT-Authen-ExternalAuth-0.25\/lib\/RT\/Authen\/ExternalAuth\/DBI.pm\">RT::Authen::ExternalAuth::DBI<\/a> module is well documented and provides some examples of how to handle the passwords. \u00a0The nice feature of Request Tracker authentication that not many people know about is that you can send\u00a0<em><strong>user<\/strong><\/em> and <em><strong>pass<\/strong><\/em> GET parameters to pretty much any RT page. \u00a0 If the user is not authenticated, than these parameters will be used to authenticate him. \u00a0If the user is already authenticated, than these will be ignored.<\/p>\n<p>That sounds like a nice and easy way to link to RT from SugarCRM, where the user is already logged in. \u00a0But we need to look into more details here, and also consider the security aspect. \u00a0Even if RT instance runs on HTTPS, there is still a chance of one user sending a URL with credentials to another by email or chat.<\/p>\n<p>Before we get into that though, let&#8217;s look at the value of password. \u00a0We can fetch the password value stored in the database for the current SugarCRM user. \u00a0But the password is not stored in clear text &#8211; it&#8217;s in a form of a hash. \u00a0So we can send an encrypted hash value as a parameter, and nobody will guess what the password is, right?<\/p>\n<p>Well, maybe. \u00a0Especially after <a href=\"https:\/\/developer.sugarcrm.com\/2012\/05\/16\/new-for-sugar-6-5-stronger-password-storage-encryption\/\">SugarCRM 6.5 introduced stronger password hashes<\/a>. \u00a0But maybe we still shouldn&#8217;t send those all over. \u00a0Let&#8217;s encrypt the hash once over anyway.<\/p>\n<p>If we are to use encryption, we need to find one that we can use both in PHP and Perl. \u00a0PHP will be encrypting the password hash, and Perl will be decrypting it, before comparing to the value in the database.<\/p>\n<p>Tinkering with different encryption methods and their parameters took me a while. \u00a0Security in general, and cryptography in particular aren&#8217;t my strongest suits. \u00a0<a href=\"https:\/\/www.perturb.org\/display\/823_PHP_to_Perl_encryption.html\">This blog post<\/a>, however, was quite useful. \u00a0For simplicity sake, here&#8217;s what I did:<\/p>\n<ul>\n<li>Blowfish algorithm with CDC mode was chosen as the cryptography mechanism.<\/li>\n<li>Created a random string of 32 bytes long, which was added to the configuration of both SugarCRM and Request Tracker. \u00a0I call it seed, just because I don&#8217;t know any better.<\/li>\n<li>First 24 bytes of the string were used as the key. \u00a0Last 8 bytes of the string were used as IV.<\/li>\n<li>Encrypted string was base64 encoded to avoid binary data in the URLs.<\/li>\n<li>Base64-encrypted string was URL-encoded on top.<\/li>\n<\/ul>\n<p>Here&#8217;s the sample PHP code:<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n\r\n&lt;?php\r\n\/**\r\n* Encryption helper\r\n*\/\r\nclass EncryptHelper {\r\n\r\n  protected static function getKeyFromSeed($seed) {\r\n    $result = substr($seed, 0, 24);\r\n    return $result;\r\n  }\r\n\r\n  protected static function getIvFromSeed($seed) {\r\n    $result = substr($seed, -8, 8);\r\n    return $result;\r\n  }\r\n\r\n  public static function encrypt($seed, $string) {\r\n    $key = self::getKeyFromSeed($seed);\r\n    $iv = self::getIvFromSeed($seed);\r\n\r\n    $result = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $string, MCRYPT_MODE_CBC, $iv);\r\n    $result = base64_encode($result);\r\n    $result = urlencode($result);\r\n\r\n    return $result;\r\n  }\r\n\r\n  public static function decrypt($seed, $string) {\r\n    $key = self::getKeyFromSeed($seed);\r\n    $iv = self::getIvFromSeed($seed);\r\n\r\n    $result = urldecode($string);\r\n    $result = base64_decode($result);\r\n    $result = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $result, MCRYPT_MODE_CBC, $iv);\r\n\r\n    return $result;\r\n  }\r\n}\r\n?&gt;\r\n<\/pre>\n<p>On the Request Tracker side, I followed the documentation to configure external database authentication. \u00a0Which also provided a handy <em>p_check<\/em> function, where I could decrypt the password hash before checking. \u00a0Here&#8217;s configuration snippet from <em>etc\/RT_SiteConfig.pm<\/em>:<\/p>\n<pre class=\"brush: perl; title: ; notranslate\" title=\"\">\r\n\r\nSet($ExternalSettings, {\r\n  'My_MySQL' =&gt; {\r\n    'type' =&gt; 'db',\r\n    'dbi_driver' =&gt; 'mysql',\r\n    'server' =&gt; 'localhost',\r\n    'port' =&gt; '3306',\r\n    'user' =&gt; 'root',\r\n    'pass' =&gt; '',\r\n    'database' =&gt; 'sugarcrm',\r\n    'table' =&gt; 'users',\r\n    'u_field' =&gt; 'user_name',\r\n    'p_field' =&gt; 'user_hash',\r\n    'p_check' =&gt; sub {\r\n      my ($hash_from_db, $password) = @_;\r\n\r\n      $password = uri_unescape($password);\r\n      $password = decode_base64($password);\r\n\r\n      my $seed = &quot;my_seed_string_of_at_least_32_bytes_goes_here&quot;;\r\n\r\n      my $key = substr $seed, 0, 24;\r\n      my $iv = substr $seed, -8, 8;\r\n\r\n      my $cipher = Crypt::CBC-&gt;new(\r\n        -key =&gt; $key,\r\n        -cipher =&gt; 'Blowfish',\r\n        -iv =&gt; $iv,\r\n        -header =&gt; 'none',\r\n        -padding =&gt; 'null',\r\n        -literal_key =&gt; 1,\r\n        -keysize =&gt; length($key),\r\n      );\r\n      my $password = $cipher-&gt;decrypt($password);\r\n\r\n      return $hash_from_db eq $password;\r\n    },\r\n    'attr_match_list' =&gt; &#x5B;\r\n      'Gecos',\r\n      'Name',\r\n      'EmailAddress',\r\n    ],\r\n    'attr_map' =&gt; {\r\n      'Name' =&gt; 'user_name',\r\n      'Gecos' =&gt; 'user_name',\r\n      'Nickname' =&gt; 'user_name',\r\n      'HomePhone' =&gt; 'phone_home',\r\n      'WorkPhone' =&gt; 'phone_work',\r\n      'MobilePhone' =&gt; 'phone_mobile',\r\n      'Address1' =&gt; 'address_street',\r\n      'City' =&gt; 'address_city',\r\n      'State' =&gt; 'address_state',\r\n      'Zip' =&gt; 'address_postalcode',\r\n      'Country' =&gt; 'address_country',\r\n    },\r\n  }\r\n});\r\n<\/pre>\n<p>Now the above sorts the problem of us sending around the password hash value from the database. It&#8217;s well encrypted now, and we can authenticate just fine.<\/p>\n<p>But the problem of one user sending the URL with the credentials to another user &#8211; accidental or not &#8211; is still not solved. So, what can we do here?<\/p>\n<p>As I mentioned earlier, we can&#8217;t really read the PHP session from Perl. But we can read the session cookie. SugarCRM starts the user session and stores the ID of the session in PHPSESSID cookie. So, we can use that as part of our seed to make sure that user and pass parameters only work properly if they are used in the same browser during the same session. Session ID by itself is too short to be our seed string, but we can complete it with random seed characters, like the above examples show, or we can throw in some more strings related to the current session &#8211; like the user&#8217;s IP address, or browser&#8217;s User-Agent, etc. I&#8217;ll leave this for you to figure out.<\/p>\n<p>The next problem, is &#8220;how can we read the session cookie from RT_SiteConfig.pm?&#8221;. It&#8217;s not a true CGI script. We don&#8217;t have any global request variables or anything like that. This part took the most time to figure out in this whole setup.<\/p>\n<p>Dumping out the environment variables, I didn&#8217;t see any web request server variables, except QUERY_STRING. No cookies, no user-agent, no remote IP address. This was weird. But the QUERY_STRING was there, so that gave me a lead. Digging through the Request Tracker source code, <a href=\"https:\/\/mamchenkov.net\/wordpress\/2016\/04\/12\/open-source-software-is-so-reassuring\/\">I found the place<\/a>, where my problem was.<\/p>\n<p>Gladly, Request Tracker provides an easy way to modify it. Simply copy the <em>lib\/RT\/Interface\/Web\/Handler.pm<\/em> to <em>local\/lib\/RT\/Interface\/Web\/Handler.pm<\/em> (created the folders, if needed), and add additional variables as needed. Here&#8217;s an example:<\/p>\n<pre class=\"brush: perl; first-line: 273; title: ; notranslate\" title=\"\">\r\n# HTML::Mason::Utils::cgi_request_args uses $ENV{QUERY_STRING} to\r\n# determine if to call url_param or not\r\n# (see comments in HTML::Mason::Utils::cgi_request_args)\r\n$ENV{QUERY_STRING} = $env-&gt;{QUERY_STRING};\r\n# Remote IP address\r\n$ENV{REMOTE_ADDR} = $env-&gt;{REMOTE_ADDR};\r\n# Cookie header\r\n$ENV{HTTP_COOKIE} = $env-&gt;{HTTP_COOKIE};\r\n<\/pre>\n<p>With this now, you can update the <em>p_check<\/em> subroutine in the <em>etc\/RT_SiteConfig.pm<\/em> file, to match the key and IV to the ones used in SugarCRM.<\/p>\n<p>As always, if you know of a better or more elegant way to solve the above, please let me know.<\/p>\n<!-- google_ad_section_end -->\n","protected":false},"excerpt":{"rendered":"<!-- google_ad_section_start -->\n<p>As mentioned\u00a0before,\u00a0over the last few month I&#8217;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.<\/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 Between SugarCRM and Request Tracker #SugarCRM #RT #security","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,133,62],"tags":[1264,3150,200,3474,1538],"keyring_services":[],"class_list":["post-26031","post","type-post","status-publish","format-standard","hentry","category-general","category-programming","category-sysadmin","category-technology","tag-integration","tag-request-tracker","tag-security","tag-single-sign-on","tag-sugarcrm"],"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":26031,"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":25961,"url":"https:\/\/mamchenkov.net\/wordpress\/2016\/03\/20\/single-sign-on-sugarcrm-roundcube-multiple-php-sessions\/","url_meta":{"origin":26031,"position":1},"title":"Single Sign-On with SugarCRM and RoundCube Using Multiple PHP Sessions","author":"Leonid Mamchenkov","date":"March 20, 2016","format":false,"excerpt":"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\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":11210,"url":"https:\/\/mamchenkov.net\/wordpress\/2008\/05\/29\/toolbox-wordpress-cakephp-sugarcrm-rt\/","url_meta":{"origin":26031,"position":2},"title":"Toolbox : WordPress, CakePHP, SugarCRM, RT","author":"Leonid Mamchenkov","date":"May 29, 2008","format":false,"excerpt":"Over the last couple of years I've been working a lot with these four applications - WordPress, CakePHP, SugarCRM, and RT.\u00a0 Each of these is beautiful in its own way.\u00a0 Each of these tools is an Open Source Software. Each of these tools has a large community. Each of these\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":8827,"url":"https:\/\/mamchenkov.net\/wordpress\/2005\/04\/14\/managing-customer-relations-with-open-source\/","url_meta":{"origin":26031,"position":3},"title":"Managing customer relations with open source","author":"Leonid Mamchenkov","date":"April 14, 2005","format":false,"excerpt":"If you are looking for CRM software, make sure you try SugarCRM. It is professionally done piece of software which is available both as a commercial option and free software. Free version has practically all the functionality of the commercial one. Commerical version features more reports and statistics, interface translated\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":11207,"url":"https:\/\/mamchenkov.net\/wordpress\/2008\/05\/20\/annoying-software\/","url_meta":{"origin":26031,"position":4},"title":"Annoying software","author":"Leonid Mamchenkov","date":"May 20, 2008","format":false,"excerpt":"Slashdot is running the post about annoying software.\u00a0 The fact that Slashdot crowd mostly consists of computer geeks is sort of a guarantee for some interesting comments. With my Fedora 9 saga I had to review and try a lot of new software.\u00a0 Needless to say, I found quite a\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":26031,"position":5},"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":[]}],"jetpack_sharing_enabled":true,"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/posts\/26031","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=26031"}],"version-history":[{"count":0,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/posts\/26031\/revisions"}],"wp:attachment":[{"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/media?parent=26031"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/categories?post=26031"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/tags?post=26031"},{"taxonomy":"keyring_services","embeddable":true,"href":"https:\/\/mamchenkov.net\/wordpress\/wp-json\/wp\/v2\/keyring_services?post=26031"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}