123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Security.Cryptography;
- using System.Text;
- using System.Threading.Tasks;
- namespace AipGateway.DRM
- {
- /// <summary>
- /// Token-based authentication for ASP .NET MVC REST web services.
- /// Copyright (c) 2015 Kory Becker
- /// http://primaryobjects.com/kory-becker
- /// License MIT
- /// </summary>
- public static class SecurityManager
- {
- private const string _alg = "HmacSHA256";
- private const string _salt = "rz8LuOtFBXphj9WQfvFh";
- private static int _expirationMinutes = 10;
- /// <summary>
- /// Generates a token to be used in API calls.
- /// The token is generated by hashing a message with a key, using HMAC SHA256.
- /// The message is: username:ip:userAgent:timeStamp
- /// The key is: password:ip:salt
- /// The resulting token is then concatenated with username:timeStamp and the result base64 encoded.
- ///
- /// API calls may then be validated by:
- /// 1. Base64 decode the string, obtaining the token, username, and timeStamp.
- /// 2. Ensure the timestamp is not expired.
- /// 2. Lookup the user's password from the db (cached).
- /// 3. Hash the username:ip:userAgent:timeStamp with the key of password:salt to compute a token.
- /// 4. Compare the computed token with the one supplied and ensure they match.
- /// </summary>
- public static string GenerateToken(string username, string password, string ip, string userAgent, long ticks)
- {
- string hash = string.Join(":", new string[] { username, ip, userAgent, ticks.ToString() });
- string hashLeft = "";
- string hashRight = "";
- using (HMAC hmac = HMACSHA256.Create(_alg))
- {
- hmac.Key = Encoding.UTF8.GetBytes(GetHashedPassword(password));
- hmac.ComputeHash(Encoding.UTF8.GetBytes(hash));
- hashLeft = Convert.ToBase64String(hmac.Hash);
- hashRight = string.Join(":", new string[] { username, ticks.ToString() });
- }
- return Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Join(":", hashLeft, hashRight)));
- }
- /// <summary>
- /// Returns a hashed password + salt, to be used in generating a token.
- /// </summary>
- /// <param name="password">string - user's password</param>
- /// <returns>string - hashed password</returns>
- public static string GetHashedPassword(string password)
- {
- string key = string.Join(":", new string[] { password, _salt });
- using (HMAC hmac = HMACSHA256.Create(_alg))
- {
- // Hash the key.
- hmac.Key = Encoding.UTF8.GetBytes(_salt);
- hmac.ComputeHash(Encoding.UTF8.GetBytes(key));
- return Convert.ToBase64String(hmac.Hash);
- }
- }
- /// <summary>
- /// Checks if a token is valid.
- /// </summary>
- /// <param name="token">string - generated either by GenerateToken() or via client with cryptojs etc.</param>
- /// <param name="ip">string - IP address of client, passed in by RESTAuthenticate attribute on controller.</param>
- /// <param name="userAgent">string - user-agent of client, passed in by RESTAuthenticate attribute on controller.</param>
- /// <returns>bool</returns>
- public static bool IsTokenValid(string token, string ip, string userAgent)
- {
- bool result = false;
- try
- {
- // Base64 decode the string, obtaining the token:username:timeStamp.
- string key = Encoding.UTF8.GetString(Convert.FromBase64String(token));
- // Split the parts.
- string[] parts = key.Split(new char[] { ':' });
- if (parts.Length == 3)
- {
- // Get the hash message, username, and timestamp.
- string hash = parts[0];
- string username = parts[1];
- long ticks = long.Parse(parts[2]);
- DateTime timeStamp = new DateTime(ticks);
- // Ensure the timestamp is valid.
- bool expired = Math.Abs((DateTime.UtcNow - timeStamp).TotalMinutes) > _expirationMinutes;
- if (!expired)
- {
- //
- // Lookup the user's account from the db.
- //
- if (username == "john")
- {
- string password = "password";
- // Hash the message with the key to generate a token.
- string computedToken = GenerateToken(username, password, ip, userAgent, ticks);
- // Compare the computed token with the one supplied and ensure they match.
- result = (token == computedToken);
- }
- }
- }
- }
- catch
- {
- }
- return result;
- }
- }
- }
|