Skip to content

Instantly share code, notes, and snippets.

@barryokane
Created May 17, 2012 11:08
Show Gist options
  • Save barryokane/2718191 to your computer and use it in GitHub Desktop.
Save barryokane/2718191 to your computer and use it in GitHub Desktop.
SSO Login for Freshdesk support portal - ASP.Net C# Sample Code
protected void Page_Load(object sender, EventArgs e)
{
string url = GetSsoUrl(ConfigurationManager.AppSettings["FreshDesk.BaseUrl"], //including trailing slash
ConfigurationManager.AppSettings["FreshDesk.Secert"], user.UserName, user.Email);
Response.Redirect(url);
}
string GetSsoUrl(string baseUrl, string secert, string name, string email)
{
return String.Format("{0}login/sso/?name={1}&email={2}&hash={3}", baseUrl, Server.UrlEncode(name),
Server.UrlEncode(email), GetHash(secert, name, email));
}
static string GetHash(string secert, string name, string email)
{
string input = name + email + secert;
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hash = md5.ComputeHash(inputBytes);
StringBuilder sb = new StringBuilder();
foreach (byte b in hash)
{
string hexValue = b.ToString("X").ToLower(); // Lowercase for compatibility on case-sensitive systems
sb.Append((hexValue.Length == 1 ? "0" : "") + hexValue);
}
return sb.ToString();
}
@kellyelton
Copy link

Here is an updated version with the latest requirements => https://gist.github.com/kellyelton/8776309

@gauravkaushik18
Copy link

Hi Barryokane,
i think this is what i am looking for. I have logged in www.abc.com. and by clicking on a link say "generate ticket" from abc website i want to get log-in in freshdesk portal automatically with help of enabling simple SSO.
but in freshdesk support portal in SSO portion there are 2 textboxes. i dont know what url should i write in those text boxes.
1.) Remote login URL 2.)Remote logout URL

@SandeshSarfare
Copy link

How do I set remote login url dynamically through code....for example if its abc.com then abc.support.com

@pariesz
Copy link

pariesz commented Apr 27, 2016

I believe GetHash needs to be updated for the recent changes:

hash value:
"An HMAC-MD5 encryption of Name, Secret key, Email and Timestamp done using the shared secret key."
https://support.freshdesk.com/support/solutions/articles/31166

shouldn't it be string input = name + secretKey + email + timems

@ianleeder
Copy link

ianleeder commented Apr 28, 2016

Seconded @parlesz, this example code needs update. We've just received an email giving us 28 hours to update our implementation before cutoff (it came in at midnight, wasting a third of our time), and the example code doesn't work. The documentation states:

The UTC timestamp of when the user attempts to log in remotely in seconds since epoch.

Which epoch? Unix? .NET? Cocoa? Excel? Wiki lists 16 different notable epochs. Time for trial-and-error...

@42degrees
Copy link

42degrees commented Apr 28, 2016

Some other comments on the code.

You are using the "X" as a format string for ToString() and then you are calling ToLower() when you could have just used "x" to get the lower-case hexadecimal value.

You are also then creating a leading zero in the loop, when you could have just used a format string "x2" (hexadecimal padded with leading zeroes to a minimum length of 2).

Here is some updated code (also adding the new hash and URL requirements):

    string GetSsoUrl(string baseUrl, string secret, string name, string email)
    {
        var timems = (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds.ToString();
        return String.Format("{0}login/sso?name={1}&email={2}&timestamp={3}&hash={4}", 
                             baseUrl, 
                             Server.UrlEncode(name),
                             Server.UrlEncode(email),
                             timems, 
                             GetHash(secret, name, email, timems));
    }

    private static string GetHash(string secret, string name, string email, string timems)
    {
        var input = name + secret + email + timems;
        var keybytes = Encoding.Default.GetBytes(secret);
        var inputBytes = Encoding.Default.GetBytes(input);

        var crypto = new HMACMD5(keybytes);
        var hash = crypto.ComputeHash(inputBytes);

        return hash.Select(b => b.ToString("x2"))
                   .Aggregate(new StringBuilder(), 
                              (current, next) => current.Append(next),
                              current => current.ToString());
    }

@darkpssngr
Copy link

@42degrees a small bug in your code. you forgot to add timestamp in the string interpolation parameters for generating the url.
@barryokane can you please update the gist to reflect the new code ? (my fork with the fixed code https://gist.github.com/darkpssngr/726162ed0bd67ffdd616370c65a17e68 )


static string GetSsoUrl(string baseUrl, string secret, string name, string email) {
    var timems = (DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds.ToString();
    return String.Format("{0}/login/sso?name={1}&email={2}×tamp={3}&hash={4}",
        baseUrl, Server.UrlEncode(name), Server.UrlEncode(email), timems, GetHash(secret, name, email, timems));
}

private static string GetHash(string secret, string name, string email, string timems) {
    var input = name + secret + email + timems;
    var keybytes = Encoding.Default.GetBytes(secret);
    var inputBytes = Encoding.Default.GetBytes(input);
    var crypto = new HMACMD5(keybytes);
    var hash = crypto.ComputeHash(inputBytes);
    return hash.Select(b => b.ToString("x2"))
        .Aggregate(new StringBuilder(),
            (current, next) => current.Append(next),
            current => current.ToString());
}

@GrahamEHughes
Copy link

I've dropped Freshdesk an email to see how we can test etc. This all seems very rushed, so my guess is they are plugging a security hole, but right now we need a test rig to know if our implementations will work once they flick the Big Red Switch!
If we have a test rig, we can just see what works. Really appreciate the comments above, hopefully one of them is the solution.

@42degrees
Copy link

Thanks @darkpssngr, fixed.

@GrahamEHughes
Copy link

Well, they gave us a test environment by flicking the Big Red Switch and letting us test in a live environment whilst our users couldn't login! Nice.

I'm now up and running, borrowing code from above, but very slightly different. Just in case it helps anyone, but the harder work was done by those people above, not me!

I have timestamp in the return url, not tamp.

        const string key = "XXXXXXXXXXXXXXXXXXXXXXX";
        const string pathTemplate = "https://support.XXXX.com/login/sso?name={0}&email={1}&timestamp={2}&hash={3}";
        string timems = (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds.ToString();
        var hash = GetHash(key, alias, tbEmail.Text, timems);
        var path = String.Format(pathTemplate, Server.UrlEncode(alias), Server.UrlEncode(tbEmail.Text), timems, hash);
        Response.Redirect(path);

Same GetHash as above:
private static string GetHash(string secret, string name, string email, string timems)
{
var input = name + secret + email + timems;
var keybytes = Encoding.Default.GetBytes(secret);
var inputBytes = Encoding.Default.GetBytes(input);
var crypto = new HMACMD5(keybytes);
var hash = crypto.ComputeHash(inputBytes);
return hash.Select(b => b.ToString("x2"))
.Aggregate(new StringBuilder(),
(current, next) => current.Append(next),
current => current.ToString());
}

@johannesstock
Copy link

johannesstock commented Jun 26, 2018

I had some Encoding trouble with European Culture and Special Characters.
Here is a "Global" working version of @GrahamEHughes Code.
There are two Changes:

  1. Usage of Encoding.UTF8 instead of Encoding.Default in GetHash
private static string GetHash(string secret, string name, string email, string timems)
        {
            var input = name + secret + email + timems;
            var keybytes = Encoding.UTF8.GetBytes(secret);
            var inputBytes = Encoding.UTF8.GetBytes(input);
            var crypto = new HMACMD5(keybytes);
            var hash = crypto.ComputeHash(inputBytes);
            return hash.Select(b => b.ToString("x2"))
                .Aggregate(new StringBuilder(),
                    (current, next) => current.Append(next),
                    current => current.ToString());
        }
  1. Change of datetime Calculation:
    string timems = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment