Пример #1
0
        /// <inheritDoc/>
        protected override Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            // Add custom username header if it doesn't exist already.
            if (!request.Headers.Contains(HmacApiAuthConfiguration.UsernameHeader))
            {
                request.Headers.Add(HmacApiAuthConfiguration.UsernameHeader, Username);
            }

            // Set the Date field in the header.
            request.Headers.Date = DateTimeOffset.Now;

            // Build out the string representation of the request.
            var representation = _representationBuilder.BuildRequestRepresentation(request);

            // Retrieve the user secret key from the secrets repository.
            var secret = _secretRepository.GetSecretForUser(Username);

            // Calculate the digital signature.
            string signature = _signatureCalculator.Signature(secret, representation);

            // Add signature to the header of the request message.
            var header = new AuthenticationHeaderValue(HmacApiAuthConfiguration.AuthenticationScheme, signature);

            request.Headers.Authorization = header;

            // Call inner message handler for response.
            return(base.SendAsync(request, cancellationToken));
        }
Пример #2
0
        /// <summary>
        /// Validates the HMAC digital signature of the API request.
        /// </summary>
        /// <param name="requestMessage">The API request message to be validated for authenticity.</param>
        /// <returns><c>true</c> if authenticated successfully, <c>false</c> otherwise.</returns>
        protected async Task <bool> IsAuthenticated(HttpRequestMessage requestMessage)
        {
            // No username, no authentication.
            if (!requestMessage.Headers.Contains(HmacApiAuthConfiguration.UsernameHeader))
            {
                return(false);
            }

            // No date, no authentication.
            if (!IsDateValid(requestMessage))
            {
                return(false);
            }

            // No Authorization header or wrong type, no authentication.
            if (requestMessage.Headers.Authorization == null ||
                requestMessage.Headers.Authorization.Scheme != HmacApiAuthConfiguration.AuthenticationScheme)
            {
                return(false);
            }

            // No ContentMD5 header yet there is Content available, no authentication.
            // No match between ContentMD5 header and actual Content MD5 hash, no authentication.
            if (!await IsMd5Valid(requestMessage))
            {
                return(false);
            }

            // Using the user's key we will now calculate what the HMAC signature should be based on the provided request message.
            // After building our own copy of the signature we will compare it to the signature provided in the API request.

            // Retrieve the username and validate user has a registered key.
            string username = requestMessage.Headers.GetValues(HmacApiAuthConfiguration.UsernameHeader).First();
            var    secret   = _secretRepository.GetSecretForUser(username);

            if (secret == null)
            {
                return(false);
            }

            // Build string representation of request. The client should have built their request the same way.
            var representation = _representationBuilder.BuildRequestRepresentation(requestMessage);

            if (representation == null)
            {
                return(false);
            }

            // Calculate our version of the HMAC signature and compare it to the request message signature to validate authentication.
            var signature = _signatureCalculator.Signature(secret, representation);
            var result    = requestMessage.Headers.Authorization.Parameter == signature;

            return(result);
        }
Пример #3
0
        protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            string reqSignature          = "";
            HttpResponseMessage response = null;

            // Get digital signature if available.
            if (request.Headers?.Authorization != null && request.Headers?.Authorization.Scheme == HmacApiAuthConfiguration.AuthenticationScheme)
            {
                reqSignature = request.Headers.Authorization.Parameter;
            }
            else
            {
                // We should just return here if there is no signature.
                return(request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Unauthorized request : Missing or invalid signature"));
            }

            // TODO : Check to see if signature is currently in cache. If so return now.

            // TODO : Cache signature in memory for the validity period (5 mins) to ensure no request gets replayed.

            try
            {
                // Call the base authentication handler.
                response = await base.SendAsync(request, cancellationToken);
            }
            catch (Exception exception)
            {
                // Catch any authentication error messages and provide custom error message response.
                response = request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Error authenticating");
                var respMsg = new StringBuilder();
                respMsg.AppendLine("Error authenticating...");

                respMsg.AppendLine("StatusCode            : " + response.StatusCode);
                respMsg.AppendLine("ReasonPhrase          : " + response.ReasonPhrase);
                respMsg.AppendLine("WwwAuthenticate       : " + response.Headers.WwwAuthenticate.FirstOrDefault().ToString());
                respMsg.AppendLine("RequestDate           : " + request.Headers.Date.GetValueOrDefault().UtcDateTime.ToString(CultureInfo.InvariantCulture));
                respMsg.AppendLine("ServerDate            : " + (DateTimeOffset.Now));

                respMsg.AppendLine();

                respMsg.AppendLine("ExceptionMessage      : " + exception.Message);
                respMsg.AppendLine("ExceptionSource       : " + exception.Source);
                respMsg.AppendLine("ExceptionInnerMessage : " + exception.InnerException?.Message);
                respMsg.AppendLine("ExceptionStackTrace   : " + exception.StackTrace);
                response.Content = new StringContent(respMsg.ToString());
            }

            // Catch any authentication failure message and provide custom error message response.
            if (response != null && response.StatusCode == HttpStatusCode.Unauthorized)
            {
                var serverDate = DateTimeOffset.Now;
                var respMsg    = new StringBuilder();

                respMsg.AppendLine("Authentication failed");

                respMsg.AppendLine();

                respMsg.AppendLine("Basic Details\n");

                respMsg.AppendLine("URL              : " + request.RequestUri.AbsoluteUri.ToLower());
                respMsg.AppendLine("StatusCode       : " + response.StatusCode);
                respMsg.AppendLine("ReasonPhrase     : " + response.ReasonPhrase);
                //respMsg.AppendLine("WwwAuthenticate  : " + response.Headers.WwwAuthenticate.FirstOrDefault().ToString());
                respMsg.AppendLine("RequestDate      : " + request.Headers.Date.GetValueOrDefault().ToString("r"));
                respMsg.AppendLine("ServerDate       : " + serverDate.ToString("r"));
                respMsg.AppendLine("DateDifference   : " + (serverDate - request.Headers.Date.GetValueOrDefault()));

                respMsg.AppendLine();

                string username = "";
                if (request.Headers.Contains(HmacApiAuthConfiguration.UsernameHeader))
                {
                    username = request.Headers.GetValues(HmacApiAuthConfiguration.UsernameHeader).First();
                }
                string signature = "";
                if (request.Headers.Authorization != null && request.Headers.Authorization.Scheme == HmacApiAuthConfiguration.AuthenticationScheme)
                {
                    signature = request.Headers.Authorization.Parameter;
                }
                string md5           = "";
                string serverMd5     = "";
                long?  contentLength = 0;
                if (request.Content != null)
                {
                    contentLength = request.Content.Headers.ContentLength;
                    serverMd5     = Convert.ToBase64String(await MD5Helper.ComputeHash(request.Content)) == "1B2M2Y8AsgTpgAmY7PhCfg==" ? "" : Convert.ToBase64String(await MD5Helper.ComputeHash(request.Content));
                    if (request.Content.Headers.ContentMD5 != null && request.Content.Headers.ContentMD5.Length > 0)
                    {
                        md5 = Convert.ToBase64String(request.Content.Headers.ContentMD5);
                    }
                }
                bool   validRequest    = IsRequestValid(request);
                string msgSigRep       = _representBuilder.BuildRequestRepresentation(request);
                string serverSignature = _sigCalc.Signature(_secretRepo.GetSecretForUser(username), msgSigRep);

                respMsg.AppendLine("Auth Details\n");

                respMsg.AppendLine("RequestValid     : " + validRequest.ToString());
                respMsg.AppendLine("Username         : "******"ApiKey           : " + _secretRepo.GetSecretForUser(username));
                respMsg.AppendLine("Signature        : " + signature);
                respMsg.AppendLine("ServerSignature  : " + serverSignature);

                respMsg.AppendLine();

                respMsg.AppendLine("Content Details\n");

                respMsg.AppendLine("ContentMd5       : " + md5);
                respMsg.AppendLine("ServerContentMd5 : " + serverMd5);
                respMsg.AppendLine("CannonicalRep    :\n" + msgSigRep);

                respMsg.AppendLine("ContentLength    : " + contentLength);
                respMsg.AppendLine("ContentType      : " + request.Content.Headers.ContentType);
                respMsg.AppendLine("ContentMediaType : " + request.Content.Headers.ContentType.MediaType.ToLower());
                respMsg.AppendLine("Content          : \"" + await request.Content.ReadAsStringAsync() + "\"");

                response.Content = new StringContent(respMsg.ToString());
            }

            return(response);
        }