Пример #1
0
        /// <summary>
        ///   Performs the actiosn needed to process a request to compile the needed artifacts
        ///   for performing authentication operations.
        /// </summary>
        ///
        /// <param name="request">The request to be processed.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <param name="challengeGenerationRequired"><c>true</c> if the handler is required to be able to generate a challenge reponse; othewise, <c>false</c>.</param>
        /// <param name="authorizationnHeaderName">The name of the HTTP header expected to hold the authentication data; this will be used as the token key to the requested authentication scheme in the result.</param>
        ///
        /// <returns>The result of the processing.</returns>
        ///
        private static ProcessResult ProcessRequest(HttpRequestMessage request,
                                                    CancellationToken cancellationToken,
                                                    bool challengeGenerationRequired = false,
                                                    string authorizationnHeaderName  = HttpHeaders.Authorization)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var locator = request.GetDependencyScope();

            // If there was a client certificate present, and processing does not require challenge generation, then attempt to locate a handler for client certificate
            // authentication and give it precedence.

            if ((!challengeGenerationRequired) && (request.GetClientCertificate() != null))
            {
                var certHandler = OrderFulfillmentAuthenticateAttributeAttribute.SelectHandler(request, cancellationToken, locator, AuthenticationType.ClientCertificate.ToString(), challengeGenerationRequired);

                if (certHandler != null)
                {
                    return(new ProcessResult(OrderFulfillmentAuthenticateAttributeAttribute.EmptyStringDictionary, certHandler));
                }
            }

            // Attempt to locate the value of the HTTP authorization header.  There may only be a single instance of the standard header, by spec
            // (see: http://tools.ietf.org/html/rfc7235#section-4.1) and the same semantics will be applied to any custom authorization headers that
            // may be used.

            IEnumerable <string> headerValues;

            // If a value was not available for the expected HTTP Authorization header, then a result cannot be determined.

            if ((cancellationToken.IsCancellationRequested) || (!request.Headers.TryGetValues(authorizationnHeaderName, out headerValues)))
            {
                return(null);
            }

            var headerValue = headerValues.FirstOrDefault();

            if (String.IsNullOrEmpty(headerValue))
            {
                return(null);
            }

            // Parse the authorization header into its composite tokens; if there was no entry for the header name, than the
            // desired authentiation scheme was not present in the header and a result cannot be determined.

            var parser = locator.GetService(typeof(IHttpHeaderParser)) as IHttpHeaderParser;

            if (parser == null)
            {
                throw new MissingDependencyException("An IHttpParser could not be located");
            }

            var headerTokens = parser.ParseAuthorization(headerValue, authorizationnHeaderName);

            if (!headerTokens.ContainsKey(authorizationnHeaderName))
            {
                return(null);
            }

            // If there was no available handler for the desired authentication scheme, a result cannot be determined.

            var handler = OrderFulfillmentAuthenticateAttributeAttribute.SelectHandler(request, cancellationToken, locator, headerTokens[authorizationnHeaderName], challengeGenerationRequired);

            if ((cancellationToken.IsCancellationRequested) || (handler == null))
            {
                return(null);
            }

            return(new ProcessResult(headerTokens, handler));
        }
Пример #2
0
        /// <summary>
        ///   Performs the actions needed to authenticate the request.
        /// </summary>
        ///
        /// <param name="context">The authentication context to consider.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        ///
        /// <returns>A Task that will perform the authentication challenge.</returns>
        ///
        public async Task AuthenticateAsync(HttpAuthenticationContext context,
                                            CancellationToken cancellationToken)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var request        = context.Request;
            var locator        = request.GetDependencyScope();
            var logger         = (locator.GetService(typeof(ILogger)) as ILogger)?.WithCorrelationId(request?.GetOrderFulfillmentCorrelationId());
            var certThumbprint = request.GetClientCertificate()?.Thumbprint;
            var body           = await request.SafeReadContentAsStringAsync();

            var result = OrderFulfillmentAuthenticateAttributeAttribute.ProcessRequest(request, cancellationToken);

            // If there was no available result after processing the request, authentication is not possible.

            if (result == null)
            {
                try
                {
                    logger.Information($"Authentication is not possible because No authentication handler was available for {{Route}} with Headers: [{{Headers}}] { Environment.NewLine }Client Certificate: [{{ClientCertificateThumbprint}}]",
                                       request?.RequestUri,
                                       request?.Headers,
                                       certThumbprint);
                }

                catch
                {
                    // Do nothing; logging is a non-critical operation that should not cause
                    // cascading failures.
                }

                return;
            }

            // If the handler was able to produce a principal, then set it on the authentication context.  This will indicate to the hosting
            // infrastructure that there is an authenticated entity.

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }

            var principal = result.AuthenticationHandler.Authenticate(result.AuthenticationTokens, context);

            if (principal != null)
            {
                context.Principal = principal;
            }
            else
            {
                try
                {
                    logger.Information($"Unable to authenticate for {{Route}} with Headers: [{{Headers}}]{ Environment.NewLine }Client Certificate: [{{ClientCertificateThumbprint}}]",
                                       request?.RequestUri,
                                       request?.Headers,
                                       certThumbprint);
                }

                catch
                {
                    // Do nothing; logging is a non-critical operation that should not cause
                    // cascading failures.
                }
            }
        }
Пример #3
0
        /// <summary>
        ///   Performs the actions needed to add an authentication challenge to the inner IHttpActionResult, if needed.
        /// </summary>
        ///
        /// <param name="context">The authentication challenge context to consider.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        ///
        /// <returns>A Task that will perform the authentication challenge.</returns>
        ///
        /// <remarks>
        ///   This method will be executed by the framework after the action has executed, regardless of whether or not a challenge
        ///   should be generated.  Before generating the challenge, determine if it
        /// </remarks>
        ///
        public async Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var request = context.Request;

            // If there was an authenticated principal associated with the request or there was a result generated that should not
            // overridden, then no challenge is needed.

            if ((cancellationToken.IsCancellationRequested) || (request.GetRequestContext()?.Principal != null) || (!OrderFulfillmentAuthenticateAttributeAttribute.ShouldOverrideResponse(context)))
            {
                return;
            }

            var result = OrderFulfillmentAuthenticateAttributeAttribute.ProcessRequest(request, cancellationToken, true);

            // If there was no available handler located after processing the request, then attempt to retrieve the
            // default challenge handler.

            if (result == null)
            {
                var handler = OrderFulfillmentAuthenticateAttributeAttribute.SelectDefaultChallengeHandler(request.GetDependencyScope());

                if (handler != null)
                {
                    result = new ProcessResult(OrderFulfillmentAuthenticateAttributeAttribute.EmptyStringDictionary, handler);
                }
            }

            // If there was no available challenge handler, authentication is not possible.  Make
            // no alterations to the current response.

            if ((cancellationToken.IsCancellationRequested) || (result == null))
            {
                return;
            }

            // If the handler was able to produce a challenge, then clear any existing result/response and
            // set the new Unauthorized with the correct challenge.

            var challenge = result.AuthenticationHandler.GenerateChallenge(result.AuthenticationTokens, context);

            if (challenge != null)
            {
                context.ActionContext.Response?.Dispose();
                context.ActionContext.Response = null;

                context.Result = new UnauthorizedResult(new[] { challenge }, request);

                try
                {
                    var locator = request.GetDependencyScope();
                    var logger  = (locator.GetService(typeof(ILogger)) as ILogger);

                    if (logger != null)
                    {
                        var body = await request.SafeReadContentAsStringAsync();

                        logger.WithCorrelationId(request?.GetOrderFulfillmentCorrelationId())
                        .Information($"Response: {{Response}} { Environment.NewLine } Authentication is needed; a challenge was issued for {{Route}} with Headers: [{{Headers}}]",
                                     HttpStatusCode.Unauthorized,
                                     request?.RequestUri,
                                     request?.Headers);
                    }
                }

                catch
                {
                    // Do nothing; logging is a non-critical operation that should not cause
                    // cascading failures.
                }
            }
        }