Example #1
0
        /// <summary>
        /// Returns an AuthenticationResult object corresponding to the result of authentication done
        /// using the client supplied artifacts in the HTTP authorization header in hawk scheme.
        /// </summary>
        /// <param name="now">Current UNIX time in milliseconds.</param>
        /// <param name="request">Request object.</param>
        /// <param name="options">Hawk authentication options</param>
        /// <returns></returns>
        internal static async Task <AuthenticationResult> AuthenticateAsync(ulong now, IRequestMessage request, Options options)
        {
            ArtifactsContainer artifacts  = null;
            Credential         credential = null;

            if (request.HasValidHawkScheme())
            {
                if (ArtifactsContainer.TryParse(request.Authorization.Parameter, out artifacts))
                {
                    if (artifacts != null && artifacts.AreClientArtifactsValid)
                    {
                        credential = options.CredentialsCallback(artifacts.Id);
                        if (credential != null && credential.IsValid)
                        {
                            var normalizedRequest = new NormalizedRequest(request, artifacts);
                            var crypto            = new Cryptographer(normalizedRequest, artifacts, credential);

                            // Request body is needed only when payload hash is present in the request
                            string body = null;
                            if (artifacts.PayloadHash != null && artifacts.PayloadHash.Length > 0)
                            {
                                body = await request.ReadBodyAsStringAsync();
                            }

                            if (crypto.IsSignatureValid(body, request.ContentType)) // MAC and hash checks
                            {
                                if (IsTimestampFresh(now, artifacts, options))
                                {
                                    // If you get this far, you are authentic. Welcome and thanks for flying Hawk!
                                    return(new AuthenticationResult()
                                    {
                                        IsAuthentic = true,
                                        Artifacts = artifacts,
                                        Credential = credential,
                                        ApplicationSpecificData = artifacts.ApplicationSpecificData
                                    });
                                }
                                else
                                {
                                    // Authentic but for the timestamp freshness.
                                    // Give a chance to the client to correct the clocks skew.
                                    var timestamp = new NormalizedTimestamp(DateTime.UtcNow, credential, options.LocalTimeOffsetMillis);
                                    request.ChallengeParameter = timestamp.ToWwwAuthenticateHeaderParameter();
                                }
                            }
                        }
                    }
                }
            }

            return(new AuthenticationResult()
            {
                IsAuthentic = false
            });
        }
        /// <summary>
        /// Returns an AuthenticationResult object corresponding to the result of authentication done
        /// using the client supplied artifacts in the HTTP authorization header in hawk scheme.
        /// </summary>
        /// <param name="now">Current UNIX time in milliseconds.</param>
        /// <param name="request">Request object.</param>
        /// <param name="options">Hawk authentication options</param>
        /// <returns></returns>
        internal static async Task<AuthenticationResult> AuthenticateAsync(ulong now, IRequestMessage request, Options options)
        {
            ArtifactsContainer artifacts = null;
            Credential credential = null;

            if (request.HasValidHawkScheme())
            {
                if (ArtifactsContainer.TryParse(request.Authorization.Parameter, out artifacts))
                {
                    if (artifacts != null && artifacts.AreClientArtifactsValid)
                    {
                        credential = options.CredentialsCallback(artifacts.Id);
                        if (credential != null && credential.IsValid)
                        {
                            var normalizedRequest = new NormalizedRequest(request, artifacts);
                            var crypto = new Cryptographer(normalizedRequest, artifacts, credential);

                            // Request body is needed only when payload hash is present in the request
                            string body = null;
                            if (artifacts.PayloadHash != null && artifacts.PayloadHash.Length > 0)
                            {
                                body = await request.ReadBodyAsStringAsync();
                            }

                            if (crypto.IsSignatureValid(body, request.ContentType)) // MAC and hash checks
                            {
                                if (IsTimestampFresh(now, artifacts, options))
                                {
                                    // If you get this far, you are authentic. Welcome and thanks for flying Hawk!
                                    return new AuthenticationResult()
                                    {
                                        IsAuthentic = true,
                                        Artifacts = artifacts,
                                        Credential = credential,
                                        ApplicationSpecificData = artifacts.ApplicationSpecificData
                                    };
                                }
                                else
                                {
                                    // Authentic but for the timestamp freshness.
                                    // Give a chance to the client to correct the clocks skew.
                                    var timestamp = new NormalizedTimestamp(DateTime.UtcNow, credential, options.LocalTimeOffsetMillis);
                                    request.ChallengeParameter = timestamp.ToWwwAuthenticateHeaderParameter();
                                }
                            }
                        }
                    }
                }
            }

            return new AuthenticationResult() { IsAuthentic = false };
        }
Example #3
0
        /// <summary>
        /// Returns an AuthenticationResult object corresponding to the result of authentication done
        /// using the client supplied artifacts in the HTTP authorization header in hawk scheme.
        /// </summary>
        /// <param name="now">Current UNIX time in milliseconds.</param>
        /// <param name="request">Request object.</param>
        /// <param name="callback">The callback function that returns a Credential object corresponding to the identifier passed in.</param>
        /// <returns></returns>
        internal static async Task <AuthenticationResult> AuthenticateAsync(ulong now, HttpRequestMessage request,
                                                                            Func <string, Credential> callback)
        {
            ArtifactsContainer artifacts  = null;
            Credential         credential = null;

            if (request.HasValidHawkScheme())
            {
                if (ArtifactsContainer.TryParse(request.Headers.Authorization.Parameter, out artifacts))
                {
                    if (artifacts != null && artifacts.AreClientArtifactsValid)
                    {
                        credential = callback(artifacts.Id);
                        if (credential != null && credential.IsValid)
                        {
                            var normalizedRequest = new NormalizedRequest(request, artifacts);
                            var crypto            = new Cryptographer(normalizedRequest, artifacts, credential);

                            if (await crypto.IsSignatureValidAsync(request.Content)) // MAC and hash checks
                            {
                                if (IsTimestampFresh(now, artifacts))
                                {
                                    // If you get this far, you are authentic. Welcome and thanks for flying Hawk!
                                    return(new AuthenticationResult()
                                    {
                                        IsAuthentic = true,
                                        Artifacts = artifacts,
                                        Credential = credential,
                                        ApplicationSpecificData = artifacts.ApplicationSpecificData
                                    });
                                }
                                else
                                {
                                    // Authentic but for the timestamp freshness.
                                    // Give a chance to the client to correct the clocks skew.
                                    var timestamp = new NormalizedTimestamp(DateTime.UtcNow, credential);
                                    request.PutChallengeParameter(timestamp.ToWwwAuthenticateHeaderParameter());
                                }
                            }
                        }
                    }
                }
            }

            return(new AuthenticationResult()
            {
                IsAuthentic = false
            });
        }
        /// <summary>
        /// Returns an AuthenticationResult object corresponding to the result of authentication done
        /// using the client supplied artifacts in the HTTP authorization header in hawk scheme.
        /// </summary>
        /// <param name="now">Current UNIX time in milliseconds.</param>
        /// <param name="request">Request object.</param>
        /// <param name="callback">The callback function that returns a Credential object corresponding to the identifier passed in.</param>
        /// <returns></returns>
        internal static async Task<AuthenticationResult> AuthenticateAsync(ulong now, HttpRequestMessage request,
                                            Func<string, Credential> callback)
        {
            ArtifactsContainer artifacts = null;
            Credential credential = null;

            if (request.HasValidHawkScheme())
            {
                if (ArtifactsContainer.TryParse(request.Headers.Authorization.Parameter, out artifacts))
                {
                    if (artifacts != null && artifacts.AreClientArtifactsValid)
                    {
                        credential = callback(artifacts.Id);
                        if (credential != null && credential.IsValid)
                        {
                            var normalizedRequest = new NormalizedRequest(request, artifacts);
                            var crypto = new Cryptographer(normalizedRequest, artifacts, credential);

                            if (await crypto.IsSignatureValidAsync(request.Content)) // MAC and hash checks
                            {
                                if (IsTimestampFresh(now, artifacts))
                                {
                                    // If you get this far, you are authentic. Welcome and thanks for flying Hawk!
                                    return new AuthenticationResult()
                                    {
                                        IsAuthentic = true,
                                        Artifacts = artifacts,
                                        Credential = credential,
                                        ApplicationSpecificData = artifacts.ApplicationSpecificData
                                    };
                                }
                                else
                                {
                                    // Authentic but for the timestamp freshness.
                                    // Give a chance to the client to correct the clocks skew.
                                    var timestamp = new NormalizedTimestamp(DateTime.UtcNow, credential);
                                    request.PutChallengeParameter(timestamp.ToWwwAuthenticateHeaderParameter());
                                }
                            }
                        }
                    }
                }
            }

            return new AuthenticationResult() { IsAuthentic = false };
        }
        public async Task TimestampInSubsequentRequestMustBeAdjustedBasedOnTimestampInWwwAuthenticateHeaderOfPrevious()
        {
            using (var invoker = new HttpMessageInvoker(server))
            {
                using (var request = new HttpRequestMessage(HttpMethod.Get, URI))
                {
                    var client = new HawkClient(() => ServerFactory.DefaultCredential);
                    await client.CreateClientAuthorizationAsync(request);

                    using (var response = await invoker.SendAsync(request, CancellationToken.None))
                    {
                        // Simulate server clock running 5 minutes slower than client and 
                        // produce the parameter with ts and tsm
                        var timestamp = new NormalizedTimestamp(DateTime.UtcNow.AddMinutes(-5), ServerFactory.DefaultCredential);
                        string timestampHeader = timestamp.ToWwwAuthenticateHeaderParameter();

                        // Add that to the WWW-Authenticate before authenticating with the
                        // client, to simulate clock skew
                        response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue("hawk", timestampHeader));

                        // Client must have now calculated an offset of -300 seconds approx
                        Assert.IsTrue(await client.AuthenticateAsync(response));
                        Assert.IsTrue(HawkClient.CompensatorySeconds <= -299 && HawkClient.CompensatorySeconds >= -301);

                        // Create a fresh request and see if this offset is applied to the timestamp
                        using (var subsequentRequest = new HttpRequestMessage(HttpMethod.Get, URI))
                        {
                            await client.CreateClientAuthorizationAsync(subsequentRequest);

                            string header = subsequentRequest.Headers.Authorization.Parameter;

                            ArtifactsContainer artifacts = null;
                            Assert.IsTrue(ArtifactsContainer.TryParse(header, out artifacts));

                            var timestampInSubsequentRequest = artifacts.Timestamp;
                            var now = DateTime.UtcNow.ToUnixTime();

                            // Since server clock is slow, the timestamp going out must be offset by the same 5 minutes
                            // or 300 seconds. Give leeway of a second while asserting.
                            ulong difference = now - timestampInSubsequentRequest;
                            Assert.IsTrue(difference >= 299 && difference <= 301);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Returns true, if there is a WWW-Authenticate header containing ts and tsm but mac
        /// computed for ts does not match tsm, indicating possible tampering. Otherwise, returns false.
        /// This method also sets the compensation field so that the timestamp in the subsequent requests
        /// are adjusted to reduce the clock skew.
        /// </summary>
        private bool IsTimestampResponseTampered(ArtifactsContainer artifacts, IResponseMessage response)
        {
            var wwwHeader = response.WwwAuthenticate;

            if (wwwHeader != null)
            {
                string parameter = wwwHeader.Parameter;

                ArtifactsContainer timestampArtifacts;
                if (!String.IsNullOrWhiteSpace(parameter) &&
                                ArtifactsContainer.TryParse(parameter, out timestampArtifacts))
                {
                    var ts = new NormalizedTimestamp(timestampArtifacts.Timestamp, options.CredentialsCallback(), options.LocalTimeOffsetMillis);

                    if (!ts.IsValid(timestampArtifacts.TimestampMac))
                        return true;

                    lock (myPrecious)
                        HawkClient.CompensatorySeconds = (int)(timestampArtifacts.Timestamp - DateTime.UtcNow.ToUnixTime());

                    Tracing.Information("HawkClient.CompensatorySeconds set to " + HawkClient.CompensatorySeconds);
                }
            }

            return false;
        }