Last active
December 27, 2015 00:39
-
-
Save eleven41/7239505 to your computer and use it in GitHub Desktop.
ASP.NET MVC controller for handling multipass authentication with Desk.com
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Based on the following: