Skip to content

Instantly share code, notes, and snippets.

@barryokane
Created May 17, 2012 11:08
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
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();
}
@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