/// <summary>
    /// Derived types may override this method to handle access denied errors.
    /// </summary>
    /// <param name="properties">The <see cref="AuthenticationProperties"/>.</param>
    /// <returns>The <see cref="HandleRequestResult"/>.</returns>
    protected virtual async Task <HandleRequestResult> HandleAccessDeniedErrorAsync(AuthenticationProperties properties)
    {
        Logger.AccessDeniedError();
        var context = new AccessDeniedContext(Context, Scheme, Options)
        {
            AccessDeniedPath   = Options.AccessDeniedPath,
            Properties         = properties,
            ReturnUrl          = properties?.RedirectUri,
            ReturnUrlParameter = Options.ReturnUrlParameter
        };
        await Events.AccessDenied(context);

        if (context.Result != null)
        {
            if (context.Result.Handled)
            {
                Logger.AccessDeniedContextHandled();
            }
            else if (context.Result.Skipped)
            {
                Logger.AccessDeniedContextSkipped();
            }

            return(context.Result);
        }

        // If an access denied endpoint was specified, redirect the user agent.
        // Otherwise, invoke the RemoteFailure event for further processing.
        if (context.AccessDeniedPath.HasValue)
        {
            string uri = context.AccessDeniedPath;
            if (!string.IsNullOrEmpty(context.ReturnUrlParameter) && !string.IsNullOrEmpty(context.ReturnUrl))
            {
                uri = QueryHelpers.AddQueryString(uri, context.ReturnUrlParameter, context.ReturnUrl);
            }
            Response.Redirect(BuildRedirectUri(uri));

            return(HandleRequestResult.Handle());
        }

        return(HandleRequestResult.NoResult());
    }
        protected override Task <HandleRequestResult> HandleRemoteAuthenticateAsync()
        {
            var result = HandleRequestResult.NoResult();

            return(Task.FromResult(result));
        }
Beispiel #3
0
        /// <summary>
        /// Invoked to process incoming authentication messages.
        /// </summary>
        /// <returns></returns>
        protected override async Task <HandleRequestResult> HandleRemoteAuthenticateAsync()
        {
            WsFederationMessage wsFederationMessage = null;

            // assumption: if the ContentType is "application/x-www-form-urlencoded" it should be safe to read as it is small.
            if (HttpMethods.IsPost(Request.Method) &&
                !string.IsNullOrWhiteSpace(Request.ContentType)
                // May have media/type; charset=utf-8, allow partial match.
                && Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase) &&
                Request.Body.CanRead)
            {
                var form = await Request.ReadFormAsync();

                wsFederationMessage = new WsFederationMessage(form.Select(pair => new KeyValuePair <string, string[]>(pair.Key, pair.Value)));
            }

            if (wsFederationMessage == null || !wsFederationMessage.IsSignInMessage)
            {
                if (Options.SkipUnrecognizedRequests)
                {
                    // Not for us?
                    return(HandleRequestResult.SkipHandler());
                }

                return(HandleRequestResult.Fail("No message."));
            }

            try
            {
                // Retrieve our cached redirect uri
                string state = wsFederationMessage.Wctx;
                // WsFed allows for uninitiated logins, state may be missing.
                var properties = GetPropertiesFromWctx(state);

                var messageReceivedContext = new MessageReceivedContext(Context, Scheme, Options, properties)
                {
                    ProtocolMessage = wsFederationMessage
                };
                await Options.Events.MessageReceived(messageReceivedContext);

                if (messageReceivedContext.Result != null)
                {
                    return(messageReceivedContext.Result);
                }

                if (wsFederationMessage.Wresult == null)
                {
                    Logger.LogWarning("Received a sign-in message without a WResult.");
                    return((HandleRequestResult)HandleRequestResult.NoResult());
                }

                string token = wsFederationMessage.GetToken();
                if (string.IsNullOrWhiteSpace(token))
                {
                    Logger.LogWarning("Received a sign-in message without a token.");
                    return((HandleRequestResult)HandleRequestResult.NoResult());
                }

                var securityTokenReceivedContext = new SecurityTokenReceivedContext(Context, Scheme, Options, properties)
                {
                    ProtocolMessage = wsFederationMessage
                };
                await Options.Events.SecurityTokenReceived(securityTokenReceivedContext);

                if (securityTokenReceivedContext.Result != null)
                {
                    return(securityTokenReceivedContext.Result);
                }

                if (_configuration == null)
                {
                    _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted);
                }

                // Copy and augment to avoid cross request race conditions for updated configurations.
                var tvp = Options.TokenValidationParameters.Clone();
                IEnumerable <string> issuers = new[] { _configuration.Issuer };
                tvp.ValidIssuers      = (tvp.ValidIssuers == null ? issuers : tvp.ValidIssuers.Concat(issuers));
                tvp.IssuerSigningKeys = (tvp.IssuerSigningKeys == null ? _configuration.SigningKeys : tvp.IssuerSigningKeys.Concat(_configuration.SigningKeys));

                ClaimsPrincipal principal   = null;
                SecurityToken   parsedToken = null;
                foreach (var validator in Options.SecurityTokenHandlers)
                {
                    if (validator.CanReadToken(token))
                    {
                        principal = validator.ValidateToken(token, tvp, out parsedToken);
                        break;
                    }
                }

                if (principal == null)
                {
                    throw new SecurityTokenException("no validator found");
                }

                if (Options.UseTokenLifetime)
                {
                    // Override any session persistence to match the token lifetime.
                    DateTime issued = parsedToken.ValidFrom;
                    if (issued != DateTime.MinValue)
                    {
                        properties.IssuedUtc = issued.ToUniversalTime();
                    }
                    DateTime expires = parsedToken.ValidTo;
                    if (expires != DateTime.MinValue)
                    {
                        properties.ExpiresUtc = expires.ToUniversalTime();
                    }
                    properties.AllowRefresh = false;
                }

                var securityTokenValidatedContext = new SecurityTokenValidatedContext(Context, Scheme, Options, principal, properties)
                {
                    ProtocolMessage = wsFederationMessage,
                };

                await Options.Events.SecurityTokenValidated(securityTokenValidatedContext);

                if (securityTokenValidatedContext.Result != null)
                {
                    return(securityTokenValidatedContext.Result);
                }

                // Flow possible changes
                principal  = securityTokenValidatedContext.Principal;
                properties = securityTokenValidatedContext.Properties;

                return(HandleRequestResult.Success(new AuthenticationTicket(principal, properties, Scheme.Name)));
            }
            catch (Exception exception)
            {
                Logger.LogError("Exception occurred while processing message: ", exception);

                // Refresh the configuration for exceptions that may be caused by key rollovers. The user can also request a refresh in the notification.
                if (Options.RefreshOnIssuerKeyNotFound && exception.GetType().Equals(typeof(SecurityTokenSignatureKeyNotFoundException)))
                {
                    Options.ConfigurationManager.RequestRefresh();
                }

                var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options)
                {
                    ProtocolMessage = wsFederationMessage,
                    Exception       = exception
                };
                await Options.Events.AuthenticationFailed(authenticationFailedContext);

                if (authenticationFailedContext.Result != null)
                {
                    return(authenticationFailedContext.Result);
                }

                throw;
            }
        }