User Voice and SSO behind a firewall

Thursday, 12 March 2009


Hi,
Our company is having a trial for a User Voice system that will be used for our internal apps and other things.

We ran into a few issues while getting our User Voice account up and running. The main problem was getting our User Voice to work from behind a firewall. We have a very strict security policy and we wanted to perform
the security checks using our SSO system from behind our firewall on our intranet and then forward users on to our User Voice account as an authorised user.

The problem: Up until a couple of weeks ago there was no way of doing this with a User Voice account. In order to get SSO to work with User Voice it was only possible using a cookie and to have domain aliasing set up.
This meant that we could not use our intranet to forward authorised users on to our User Voice account as the domain forwarding needed a valid contactable URL. (Note: There is also an API that you can use to validate and create users, but we had little success with getting this to work.
I could not find a working example anywhere and could only get back errors. Although I did manage to query an existing user.)

After sending an email to the team at User Voice they got back to us immediately with a solution! They were just in the middle of implementing a solution and had almost finished.

The solution is simple and easy to implement. Here is how it works:

* Validate the user behind the firewall
* Use your Account Key and API Key provided to encrypt the user information
* Pass the encrypted data along in the URL to your User Voice account
* This will either create the user if it doesn't exist or will log the user in automatically
* A cookie is generated on the user machine so they can access different areas of the site as necessary
* SSO attempt is also logged in the admin area
* User activity is also logged in the admin area

These are the steps that are used for passing our validated user through to our User Voice account:
* User goes to a specific URL on our intranet that has our php script to create the forwarding URL. The user includes a variable in the URL indicate which uservoice forum they would like to go to.
* User is validated by our SSO system
* Database query is performed to verify user has an active account, retrieves their email and display name (this could also be used to restrict access to a specific forum based upon user access level and the forum they specified in the URL)
* If user is valid send them through to the specified forum, if no forum was specified pass them through to our User Voice account general page
* User is created / logged in at User Voice site and log in attempt is recorded


Before I get in to the example, here is the link to user to view the SSO setup pdf which is good background information and will also explain about what attributes can be passed for the user, remember to replace:

http://uservoice.uservoice.com/files/sso_setup.pdf

Also note that SSO is only available for certain levels of account. Make sure you have a valid account and you can log in normally using your administrator account before trying to set up SSO.

Your Account Key and API Key are available from the Admin section under Setup >> Single Sign-On e.g. yoursite.uservoice.com/sso

OK, now let's see our example:

Firstly I set up a couple of functions; validateUser and getEncryptedData

validateUser is used to query the database and retrieve some details about our user base upon their $_SERVER['AUTH_USER'] value. Here is an example, but you will definitely need to cusomtise this.


function validateUser($auth_user, &$sqlsrv) {
if (!$auth_user) return false;

$strSQL = "SELECT * FROM person WHERE AuthName = '{$auth_user}' AND Active = 1";
$user = $sqlsrv->fetchrow($strSQL);

if ($user) {
return $user;
} else {
return false;
}
}


Here is getEncryptedData. Note, most of this comes from the SSO setup pdf document.


function getEncryptedData($username, $email, $displayname) {
$password = "<< ACCOUNT KEY GOES IN HERE! >>";
$salt = "<< API KEY GOES IN HERE! >>";
$salted = $salt . $password;
$hash = hash('sha1',$salted,true);
$saltedHash = substr($hash,0,16);

$expires = date('Y-m-d 00:00:00', strtotime('+14 days')); // expire the cookie in 14 days from now

$iv = "OpenSSL for Ruby";
$data = array(
"expires" => $expires,
"username" => $username,
"email" => $email,
"display_name" => $displayname
);
$data = json_encode($data);
// double XOR first block
for ($i = 0; $i < 16; $i++) {
$data[$i] = $data[$i] ^ $iv[$i];
}
$pad = 16 - (strlen($data) % 16);
$data = $data . str_repeat(chr($pad), $pad);
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'','cbc','');
mcrypt_generic_init($cipher, $saltedHash, $iv);
$encryptedData = mcrypt_generic($cipher,$data);
mcrypt_generic_deinit($cipher);
$encryptedData = urlencode(urlencode($encryptedData));

return $encryptedData;
}


So call validateUser first to validate the user and get their details.

Then pass these details in to getEncrypted data.

The final step is moving your validate user on (or some other message if they didn't validate).



$enckey = getEncryptedData($username, $email, $displayname);

header("Location: http://yoursite.uservoice.com/pages/{$forum}?sso={$enckey}");


Take note that the encrypted data goes into the sso variable of the URL.

I also add the following:


if (!$forum) $forum = 'general';


So that we just pass the user on to the main page if they didn't specify which forum they want to go to.

Filling in the rest should be straight forward.
blog comments powered by Disqus