Skip to content

Instantly share code, notes, and snippets.

@eleven41
Last active December 27, 2015 00:39
Show Gist options
  • Save eleven41/7239505 to your computer and use it in GitHub Desktop.
Save eleven41/7239505 to your computer and use it in GitHub Desktop.
ASP.NET MVC controller for handling multipass authentication with Desk.com
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using System.Web.Security;
namespace MvcApplication1.Controllers
{
public class DeskController : Controller
{
#region Desk.com
//
// GET: /Desk/Login
[Authorize]
public ActionResult Login()
{
return RedirectToDesk(null);
}
//
// GET: /Desk/Logout
[Authorize]
public ActionResult Logout()
{
FormsAuthentication.SignOut();
// Redirect back to Desk.com
string siteKey = ConfigurationManager.AppSettings["DeskSiteKey"];
string redirectUrl = string.Format("https://{0}.desk.com", siteKey);
return Redirect(redirectUrl);
}
//
// GET: /Desk/RedirectTo
public ActionResult RedirectTo(string path)
{
// Perform a redirect to Desk.com's help center.
// If the user is currently logged in here, then redirect using multipass so the user is
// logged in there too.
string siteKey = ConfigurationManager.AppSettings["DeskSiteKey"];
string redirectUrl = string.Format("https://{0}.desk.com/{1}", siteKey, path);
if (User == null)
return Redirect(redirectUrl);
if (User.Identity == null)
return Redirect(redirectUrl);
if (!User.Identity.IsAuthenticated)
return Redirect(redirectUrl);
return RedirectToDesk(redirectUrl);
}
private ActionResult RedirectToDesk(string toUrl)
{
// Get the current authenticated user id
MembershipUser currentUser = Membership.GetUser();
object userId = currentUser.ProviderUserKey;
string email = currentUser.Email;
string username = currentUser.UserName;
// Fill in the desk data structure
DeskUserData userData = new DeskUserData();
userData.uid = userId.ToString();
userData.expires = DateTime.Now.AddMinutes(2).ToString("yyyy-MM-ddTHH:mm:sszzz"); // ISO 8601 like 2011-12-29T10:25:28-08:00
userData.customer_email = email;
userData.customer_name = username;
userData.customer_custom_userid = userId.ToString(); // This is our custom field which we added in the Desk.com admin
if (!String.IsNullOrWhiteSpace(toUrl))
userData.to = toUrl.Trim();
// Generate a multipass and signature
string multipass;
string signature;
encryptUserData(userData, out multipass, out signature);
string siteKey = ConfigurationManager.AppSettings["DeskSiteKey"];
// Redirect back to Desk.com
string redirectUrl = string.Format("https://{0}.desk.com/customer/authentication/multipass/callback?multipass={1}&signature={2}",
siteKey, multipass, signature);
return Redirect(redirectUrl);
}
protected static bool encryptUserData(DeskUserData userData, out string multipass, out string signature)
{
string siteKey = ConfigurationManager.AppSettings["DeskSiteKey"];
string apiKey = ConfigurationManager.AppSettings["DeskApiKey"];
// Create the encryption key using a 16 byte SHA1 digest of your api key and subdomain
string salted = apiKey + siteKey;
SHA1 sha1 = SHA1.Create();
var bytesToHash = Encoding.ASCII.GetBytes(salted);
byte[] hash = sha1.ComputeHash(bytesToHash);
Array.Resize(ref hash, 16);
var digest = Convert.ToBase64String(hash);
// Build json data
JavaScriptSerializer s = new JavaScriptSerializer();
string jsonData = s.Serialize(userData);
var data = Encoding.ASCII.GetBytes(jsonData);
byte[] multipassBytes;
// Encrypt data using AES128-cbc
using (AesManaged aesAlg = new AesManaged())
{
// Generate a random 16 byte IV
aesAlg.GenerateIV();
aesAlg.KeySize = 16 * 8; // = 128-bit, originally defaulted to 256
aesAlg.Key = hash;
aesAlg.Mode = CipherMode.CBC;
// Encrypt using the AES Managed object
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(data, 0, data.Length);
csEncrypt.FlushFinalBlock();
}
byte[] encrypted = msEncrypt.ToArray();
multipassBytes = new byte[16 + encrypted.Length];
// Prepend the IV to the encrypted data
// This will be extracted and used for decryption
aesAlg.IV.CopyTo(multipassBytes, 0);
encrypted.CopyTo(multipassBytes, 16);
}
}
// Base64 encode the encrypted data
multipass = Convert.ToBase64String(multipassBytes);
// Build an HMAC-SHA1 signature using the encoded string and your api key
HMACSHA1 hmacsha1 = new HMACSHA1(Encoding.ASCII.GetBytes(apiKey));
hash = hmacsha1.ComputeHash(Encoding.ASCII.GetBytes(multipass));
// Base64 encode the signature
signature = Convert.ToBase64String(hash);
// Finally, URL encode the multipass and signature
multipass = HttpUtility.UrlEncode(multipass);
signature = HttpUtility.UrlEncode(signature);
return true;
}
protected class DeskUserData
{
public string uid;
public string expires;
public string customer_email;
public string customer_name;
public string customer_custom_userid; // custom fields
public string to; // redirect to after login
}
#endregion
}
}
@eleven41
Copy link
Author

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