예제 #1
0
파일: Hawk.cs 프로젝트: lanicon/HawkNet
        /// <summary>
        /// Gets a new Bewit for Single URI authorization
        /// </summary>
        /// <param name="host">Host name</param>
        /// <param name="uri">Request uri</param>
        /// <param name="credential">Hawk credential</param>
        /// <param name="ttlSec">Time to live in seconds for the Bewit</param>
        /// <param name="ext">Extension attributes</param>
        /// <returns>A fresh Bewit</returns>
        public static string GetBewit(string host, Uri uri, HawkCredential credential, int ttlSec, string ext = null)
        {
            var now = ConvertToUnixTimestamp(DateTime.Now);

            var expiration = Math.Floor(now) + ttlSec;

            var mac = CalculateMac(host, "GET", uri, ext, expiration.ToString(), "", credential, "bewit");

            var bewit = Convert.ToBase64String(
                Encoding.UTF8.GetBytes(credential.Id + '\\' + expiration + '\\' + mac + '\\' + ext));

            return(bewit);
        }
예제 #2
0
파일: Hawk.cs 프로젝트: lanicon/HawkNet
        /// <summary>
        /// Authenticates a request message using a bewit
        /// </summary>
        /// <param name="bewit"></param>
        /// <param name="host"></param>
        /// <param name="uri"></param>
        /// <param name="credentials"></param>
        /// <param name="timestampSkewSec"></param>
        /// <returns></returns>
        public static IPrincipal AuthenticateBewit(string bewit, string host, Uri uri, Func <string, HawkCredential> credentials, int timestampSkewSec = 60)
        {
            if (Trace.CorrelationManager.ActivityId == Guid.Empty)
            {
                Trace.CorrelationManager.ActivityId = Guid.NewGuid();
            }

            var bewitParts = ValidateBewit(bewit);

            HawkCredential credential = null;

            try
            {
                credential = credentials(bewitParts[0]);
            }
            catch (Exception ex)
            {
                TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Unknow user {1} in bewit",
                                                                               Trace.CorrelationManager.ActivityId, bewitParts[0]));

                throw new SecurityException("Unknown user", ex);
            }

            ValidateCredentials(credential);

            var mac = CalculateMac(uri.Host, "GET", RemoveBewitFromQuery(uri),
                                   bewitParts[3], bewitParts[1], "", credential, "bewit");

            if (!IsEqual(mac, bewitParts[2]))
            {
                TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Bad mac in bewit. Received mac {1}. Calculated mac {2}",
                                                                               Trace.CorrelationManager.ActivityId, bewitParts[2], mac));

                throw new SecurityException("Bad mac");
            }


            var userClaim = new Claim(ClaimTypes.Name, credential.User);
            var allClaims = Enumerable.Concat(new Claim[] { userClaim },
                                              (credential.AdditionalClaims != null) ? credential.AdditionalClaims : Enumerable.Empty <Claim>());

            var identity  = new ClaimsIdentity(allClaims, "Hawk");
            var principal = new ClaimsPrincipal(new ClaimsIdentity[] { identity });

            return(principal);
        }
예제 #3
0
파일: Hawk.cs 프로젝트: lanicon/HawkNet
        private static void ValidateCredentials(HawkCredential credential)
        {
            if (credential == null)
            {
                throw new SecurityException("Missing credentials");
            }

            if (string.IsNullOrEmpty(credential.Algorithm) ||
                string.IsNullOrEmpty(credential.Key))
            {
                throw new SecurityException("Invalid credentials");
            }

            if (!SupportedAlgorithms.Any(a =>
                                         string.Equals(a, credential.Algorithm, StringComparison.InvariantCultureIgnoreCase)))
            {
                throw new SecurityException("Unknown algorithm");
            }
        }
예제 #4
0
파일: Hawk.cs 프로젝트: lanicon/HawkNet
        /// <summary>
        /// Generates a mac hash using the supplied payload and credentials
        /// </summary>
        /// <param name="payload"></param>
        /// <param name="credential"></param>
        /// <returns></returns>
        public static string CalculatePayloadHash(string payload, string mediaType, HawkCredential credential)
        {
            var normalized = "hawk.1.payload\n" +
                             mediaType + "\n" +
                             payload + "\n";

            TraceSource.TraceInformation(string.Format("Normalized Payload String: {0}",
                                                       normalized));

            var algorithm = HashAlgorithm.Create(credential.Algorithm);

            var encodedMac = Convert.ToBase64String(algorithm
                                                    .ComputeHash(Encoding.UTF8.GetBytes(normalized)));

            TraceSource.TraceInformation(string.Format("Calculated payload hash: {0}",
                                                       encodedMac));

            return(encodedMac);
        }
예제 #5
0
파일: Hawk.cs 프로젝트: lanicon/HawkNet
        /// <summary>
        /// Computes a mac following the Hawk rules
        /// </summary>
        /// <param name="host">Host header</param>
        /// <param name="method">Request method</param>
        /// <param name="uri">Request uri</param>
        /// <param name="ext">Extesion attribute</param>
        /// <param name="ts">Timestamp</param>
        /// <param name="nonce">Nonce</param>
        /// <param name="credential">Credential</param>
        /// <param name="payload">Hash of the request payload</param>
        /// <returns>Generated mac</returns>
        public static string CalculateMac(string host, string method, Uri uri, string ext, string ts, string nonce, HawkCredential credential, string type, string payloadHash = null)
        {
            HMAC hmac = null;

            if (credential.Algorithm.Equals("sha1", StringComparison.InvariantCultureIgnoreCase))
            {
                hmac = new HMACSHA1();
            }
            else if (credential.Algorithm.Equals("sha256", StringComparison.InvariantCultureIgnoreCase))
            {
                hmac = new HMACSHA256();
            }
            else
            {
                throw new Exception("Not supported algorithm");
            }

            hmac.Key = Encoding.UTF8.GetBytes(credential.Key);

            var sanitizedHost = (host.IndexOf(':') > 0) ?
                                host.Substring(0, host.IndexOf(':')) :
                                host;

            var normalized = "hawk.1." + type + "\n" +
                             ts + "\n" +
                             nonce + "\n" +
                             method.ToUpper() + "\n" +
                             uri.PathAndQuery + "\n" +
                             sanitizedHost + "\n" +
                             uri.Port.ToString() + "\n" +
                             ((!string.IsNullOrEmpty(payloadHash)) ? payloadHash : "") + "\n" +
                             ((!string.IsNullOrEmpty(ext)) ? ext : "") + "\n";

            TraceSource.TraceInformation(string.Format("Normalized String: {0}",
                                                       normalized));

            var messageBytes = Encoding.UTF8.GetBytes(normalized);

            var mac = hmac.ComputeHash(messageBytes);

            var encodedMac = Convert.ToBase64String(mac);

            TraceSource.TraceInformation(string.Format("Calculated mac: {0}",
                                                       encodedMac));

            return(encodedMac);
        }
예제 #6
0
파일: Hawk.cs 프로젝트: lanicon/HawkNet
        /// <summary>
        /// Authenticates an upcoming request message
        /// </summary>
        /// <param name="authorization">Authorization header</param>
        /// <param name="host">Host header</param>
        /// <param name="method">Request method</param>
        /// <param name="uri">Request Uri</param>
        /// <param name="credentials">A method for searching across the available credentials</param>
        /// <param name="timestampSkewSec">Accepted Time skew for timestamp verification</param>
        /// <param name="payloadHash">Hash of the request payload</param>
        /// <returns></returns>
        public static async Task <IPrincipal> AuthenticateAsync(string authorization, string host, string method, Uri uri, Func <string, Task <HawkCredential> > credentials, int timestampSkewSec = 60, Func <Task <string> > requestPayload = null, string mediaType = null)
        {
            if (Trace.CorrelationManager.ActivityId == Guid.Empty)
            {
                Trace.CorrelationManager.ActivityId = Guid.NewGuid();
            }

            TraceSource.TraceInformation(string.Format("{0} - Received Auth header: {1}",
                                                       Trace.CorrelationManager.ActivityId, authorization));

            if (string.IsNullOrEmpty(authorization))
            {
                TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Authorization parameter can not be null or empty",
                                                                               Trace.CorrelationManager.ActivityId));

                throw new ArgumentException("Authorization parameter can not be null or empty", "authorization");
            }

            if (string.IsNullOrEmpty(host))
            {
                TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Host header can not be null or empty",
                                                                               Trace.CorrelationManager.ActivityId));

                throw new ArgumentException("Host header can not be null or empty", "host");
            }

            var attributes = ParseAttributes(authorization);

            ValidateAttributes(timestampSkewSec, attributes);

            HawkCredential credential = null;

            try
            {
                credential = await credentials(attributes["id"]);
            }
            catch (Exception ex)
            {
                TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Unknown user",
                                                                               Trace.CorrelationManager.ActivityId));

                throw new SecurityException("Unknown user", ex);
            }

            ValidateCredentials(credential);

            if (!string.IsNullOrEmpty(attributes["hash"]))
            {
                if (requestPayload != null && string.IsNullOrEmpty(mediaType))
                {
                    TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Media Type can not be null when the payload hash must be calculated",
                                                                                   Trace.CorrelationManager.ActivityId));

                    throw new ArgumentException("MediaType can not be null or empty", "mediaType");
                }

                var hash = CalculatePayloadHash(await requestPayload(), mediaType, credential);

                if (attributes["hash"] != hash)
                {
                    TraceSource.TraceData(TraceEventType.Warning, 0,
                                          string.Format("{0} - Bad payload hash. Received hash {1}. Calculated hash {2}",
                                                        Trace.CorrelationManager.ActivityId, attributes["hash"], hash));

                    throw new SecurityException("Bad payload hash");
                }
            }

            var mac = CalculateMac(host,
                                   method,
                                   uri,
                                   attributes["ext"],
                                   attributes["ts"],
                                   attributes["nonce"],
                                   credential, "header",
                                   attributes["hash"]);

            if (!IsEqual(mac, attributes["mac"]))
            {
                TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Bad Mac. Received mac {1}. Calculated Mac {2}",
                                                                               Trace.CorrelationManager.ActivityId, attributes["mac"], mac));

                throw new SecurityException("Bad mac");
            }

            var userClaim = new Claim(ClaimTypes.Name, credential.User);
            var allClaims = Enumerable.Concat(new Claim[] { userClaim },
                                              (credential.AdditionalClaims != null) ? credential.AdditionalClaims : Enumerable.Empty <Claim>());

            var identity  = new ClaimsIdentity(allClaims, "Hawk");
            var principal = new ClaimsPrincipal(new ClaimsIdentity[] { identity });

            return(principal);
        }
예제 #7
0
파일: Hawk.cs 프로젝트: lanicon/HawkNet
        /// <summary>
        /// Creates a new Hawk Authorization header based on the provided parameters
        /// </summary>
        /// <param name="host">Host header</param>
        /// <param name="method">Request method</param>
        /// <param name="uri">Request uri</param>
        /// <param name="credential">Credential used to calculate the MAC</param>
        /// <param name="ext">Optional extension attribute</param>
        /// <param name="ts">Timestamp</param>
        /// <param name="nonce">Random Nonce</param>
        /// <param name="payloadHash">Hash of the request payload</param>
        /// <param name="type">Type used as header for the normalized string. Default value is 'header'</param>
        /// <returns>Hawk authorization header</returns>
        public static string GetAuthorizationHeader(string host, string method, Uri uri, HawkCredential credential, string ext = null, DateTime?ts = null, string nonce = null, string payloadHash = null, string type = null)
        {
            if (string.IsNullOrEmpty(host))
            {
                throw new ArgumentException("The host can not be null or empty", "host");
            }

            if (string.IsNullOrEmpty(method))
            {
                throw new ArgumentException("The method can not be null or empty", "method");
            }

            if (credential == null)
            {
                throw new ArgumentNullException("The credential can not be null", "credential");
            }

            if (string.IsNullOrEmpty(nonce))
            {
                nonce = GetRandomString(6);
            }

            if (string.IsNullOrEmpty(type))
            {
                type = "header";
            }

            var normalizedTs = ((int)Math.Floor((ConvertToUnixTimestamp((ts.HasValue)
                ? ts.Value : DateTime.UtcNow)))).ToString();

            var mac = CalculateMac(host,
                                   method,
                                   uri,
                                   ext,
                                   normalizedTs,
                                   nonce,
                                   credential,
                                   type,
                                   payloadHash);

            var authorization = string.Format("id=\"{0}\", ts=\"{1}\", nonce=\"{2}\", mac=\"{3}\", ext=\"{4}\"",
                                              credential.Id, normalizedTs, nonce, mac, ext);

            if (!string.IsNullOrEmpty(payloadHash))
            {
                authorization += string.Format(", hash=\"{0}\"", payloadHash);
            }

            return(authorization);
        }