Skip to content

Instantly share code, notes, and snippets.

@BertCraven
Created March 27, 2011 16:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BertCraven/889325 to your computer and use it in GitHub Desktop.
Save BertCraven/889325 to your computer and use it in GitHub Desktop.
// ----------------------------------------------------------------------------------
// Microsoft Developer & Platform Evangelism
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// ----------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
// ----------------------------------------------------------------------------------
namespace MySolution.Interceptors
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
public class TokenValidator
{
private const string IssuerLabel = "Issuer";
private const string ExpiresLabel = "ExpiresOn";
private const string AudienceLabel = "Audience";
private const string HMACSha256Label = "HMACSHA256";
private readonly byte[] trustedSigningKey;
private readonly string trustedTokenIssuer;
private readonly Uri trustedAudienceValue;
public TokenValidator(string issuerName, string trustedAudienceValue, byte[] trustedSigningKey)
{
this.trustedSigningKey = trustedSigningKey;
this.trustedTokenIssuer = issuerName.ToLowerInvariant();
this.trustedAudienceValue = new Uri(trustedAudienceValue);
}
public bool Validate(string token)
{
if (!this.IsHMACValid(token, this.trustedSigningKey))
{
return false;
}
if (this.IsExpired(token))
{
return false;
}
if (!this.IsIssuerTrusted(token))
{
return false;
}
if (!this.IsAudienceTrusted(token))
{
return false;
}
return true;
}
public Dictionary<string, string> GetNameValues(string token)
{
if (string.IsNullOrEmpty(token))
{
throw new ArgumentException();
}
return
token
.Split('&')
.Aggregate(
new Dictionary<string, string>(),
(dict, rawNameValue) =>
{
if (rawNameValue == string.Empty)
{
return dict;
}
string[] nameValue = rawNameValue.Split('=');
if (nameValue.Length != 2)
{
throw new ArgumentException("Invalid formEncodedstring - contains a name/value pair missing an = character");
}
if (dict.ContainsKey(nameValue[0]))
{
throw new ArgumentException("Repeated name/value pair in form");
}
dict.Add(HttpUtility.UrlDecode(nameValue[0]), HttpUtility.UrlDecode(nameValue[1]));
return dict;
});
}
private static ulong GenerateTimeStamp()
{
// Default implementation of epoch time
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToUInt64(ts.TotalSeconds);
}
private bool IsAudienceTrusted(string token)
{
Dictionary<string, string> tokenValues = this.GetNameValues(token);
string audienceValue;
tokenValues.TryGetValue(AudienceLabel, out audienceValue);
if (!string.IsNullOrEmpty(audienceValue))
{
var audienceValueUri = new Uri(audienceValue);
if (audienceValueUri.Equals(this.trustedAudienceValue))
{
return true;
}
}
return false;
}
private bool IsIssuerTrusted(string token)
{
Dictionary<string, string> tokenValues = this.GetNameValues(token);
string issuerName;
tokenValues.TryGetValue(IssuerLabel, out issuerName);
if (!string.IsNullOrEmpty(issuerName))
{
if (issuerName.Equals(this.trustedTokenIssuer))
{
return true;
}
}
return false;
}
private bool IsHMACValid(string swt, byte[] sha256HMACKey)
{
string[] swtWithSignature = swt.Split(new[] { "&" + HMACSha256Label + "=" }, StringSplitOptions.None);
if ((swtWithSignature.Length != 2))
{
return false;
}
var hmac = new HMACSHA256(sha256HMACKey);
byte[] locallyGeneratedSignatureInBytes = hmac.ComputeHash(Encoding.ASCII.GetBytes(swtWithSignature[0]));
string locallyGeneratedSignature = HttpUtility.UrlEncode(Convert.ToBase64String(locallyGeneratedSignatureInBytes));
return locallyGeneratedSignature == swtWithSignature[1];
}
private bool IsExpired(string swt)
{
try
{
Dictionary<string, string> nameValues = this.GetNameValues(swt);
string expiresOnValue = nameValues[ExpiresLabel];
ulong expiresOn = Convert.ToUInt64(expiresOnValue);
ulong currentTime = Convert.ToUInt64(GenerateTimeStamp());
if (currentTime > expiresOn)
{
return true;
}
return false;
}
catch (KeyNotFoundException)
{
throw new ArgumentException();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment