protected override Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            var header = Request.Headers["Authorization"].ToString();

            if (string.IsNullOrEmpty(header) || !header.StartsWith("Bearer "))
            {
                return(Task.FromResult(AuthenticateResult.Skip()));
            }

            var userName = header.Substring(7);
            var claims   = new List <Claim>();

            claims.Add(new Claim(ClaimTypes.Name, userName, ClaimValueTypes.String, "https://contoso.com/"));
            var identity = new ClaimsIdentity(
                claims,
                Options.AuthenticationScheme,
                ClaimTypes.Name,
                ClaimTypes.Role);
            var principal = new ClaimsPrincipal(identity);

            var ticket = new AuthenticationTicket(
                principal,
                new AuthenticationProperties(),
                Options.AuthenticationScheme);

            return(Task.FromResult(AuthenticateResult.Success(ticket)));
        }
Beispiel #2
0
        /// <summary>
        /// Searches the 'Authorization' header for a 'Bearer' token. If the 'Bearer' token is found, it is validated using <see cref="TokenValidationParameters"/> set in the options.
        /// </summary>
        /// <returns></returns>
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            var token = ExtractToken(Request);

            // If no token found, no further work possible
            if (string.IsNullOrEmpty(token))
            {
                return(AuthenticateResult.Skip());
            }

            var validationParameters = Options.TokenValidationParameters.Clone();

            SecurityToken validatedToken;
            var           validators = Options.SecurityTokenValidatorsFactory();

            foreach (var validator in validators)
            {
                if (validator.CanReadToken(token))
                {
                    var principal = validator.ValidateToken(token, validationParameters, out validatedToken);
                    var ticket    = new AuthenticationTicket(principal, new AuthenticationProperties(), Options.AuthenticationScheme);
                    return(AuthenticateResult.Success(ticket));
                }
            }

            // Ugly patch to make this method should to be async in order to allow result caching by caller
            await DoneTask;

            // Not so nice, but AuthenticateResult.Fail does not allow us to show the error
            throw new AuthenticationException("Authorization token has been detected but it cannot be read.");
        }
Beispiel #3
0
        private async Task <AuthenticateResult> ReadHeaderTicket()
        {
            if (!Context.Request.Headers.ContainsKey("Authorization"))
            {
                return(AuthenticateResult.Skip());
            }
            var headerValue = Context.Request.Headers["Authorization"].First();

            var ticket = Options.TicketDataFormat.Unprotect(headerValue, GetTlsTokenBinding());

            if (ticket == null)
            {
                return(AuthenticateResult.Fail("Unprotect ticket failed"));
            }

            var currentUtc = DateTimeOffset.UtcNow;
            var issuedUtc  = ticket.Properties.IssuedUtc;
            var expiresUtc = ticket.Properties.ExpiresUtc;

            if (expiresUtc != null && expiresUtc.Value < currentUtc)
            {
                return(AuthenticateResult.Fail("Ticket expired"));
            }

            return(AuthenticateResult.Success(ticket));
        }
Beispiel #4
0
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            AuthenticateResult result = null;

            bool isValid = true;

            if (isValid)
            {
                //assigning fake identity, just for illustration
                ClaimsIdentity claimsIdentity = new ClaimsIdentity("Custom");

                var claims = new List <Claim>();
                claims.Add(new Claim(ClaimTypes.Name, "admin"));
                claims.Add(new Claim(ClaimTypes.GivenName, "God"));
                claims.Add(new Claim(ClaimTypes.Email, "*****@*****.**"));
                claims.Add(new Claim(ClaimTypes.NameIdentifier, "admin"));
                claims.Add(new Claim(ClaimTypes.Role, "admin"));
                claims.Add(new Claim("oko:zone", "*"));

                claimsIdentity.AddClaims(claims);

                ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);

                result =
                    AuthenticateResult.Success(new AuthenticationTicket(claimsPrincipal,
                                                                        new AuthenticationProperties(), Options.AuthenticationScheme));
            }
            else
            {
                result = AuthenticateResult.Skip();
            }

            return(result);
        }
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            var request = Context.GetOpenIdConnectRequest();

            if (request == null)
            {
                throw new InvalidOperationException("An identity cannot be extracted from this request.");
            }

            if (request.IsAuthorizationRequest() || request.IsLogoutRequest())
            {
                if (string.IsNullOrEmpty(request.IdTokenHint))
                {
                    return(AuthenticateResult.Skip());
                }

                var ticket = await DeserializeIdentityTokenAsync(request.IdTokenHint, request);

                if (ticket == null)
                {
                    Logger.LogWarning("The identity token extracted from the id_token_hint " +
                                      "parameter was invalid and has been ignored.");

                    return(AuthenticateResult.Skip());
                }

                // Tickets are returned even if they
                // are considered invalid (e.g expired).
                return(AuthenticateResult.Success(ticket));
            }

            throw new InvalidOperationException("An identity cannot be extracted from this request.");
        }
    protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
    {
        string             token  = null;
        AuthenticateResult result = null;
        string             token  = Helper.GetTokenFromHEader(Request.Headers["Authorization"]);

        // If no token found, no further work possible
        if (string.IsNullOrEmpty(token))
        {
            result = AuthenticateResult.Skip();
        }
        else
        {
            bool isValid = await _tokenService.IsValidAsync(token);

            if (isValid)
            {
                ClaimsIdentity claimsIdentity = new ClaimsIdentity("Custom");
                var            claims         = new List <Claim>();
                claims.Add(new Claim(ClaimTypes.Name, "admin"));
                claims.Add(new Claim(ClaimTypes.NameIdentifier, "admin"));
                claims.Add(new Claim(ClaimTypes.Role, "admin"));
                ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
                result =
                    AuthenticateResult.Success(new AuthenticationTicket(claimsPrincipal,
                                                                        new AuthenticationProperties(), Options.AuthenticationScheme));
            }
            else
            {
                result = AuthenticateResult.Skip();
            }
        }
        return(result);
    }
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            var    keyword       = Options.AuthenticationScheme + " ";
            string authorization = Request.Headers["Authorization"];

            if (string.IsNullOrEmpty(authorization))
            {
                return(await Task.FromResult(AuthenticateResult.Skip()));
            }

            if (!authorization.StartsWith(keyword))
            {
                return(await Task.FromResult(AuthenticateResult.Skip()));
            }

            var authValue = authorization.Substring(keyword.Length).Trim();

            if (string.IsNullOrEmpty(authValue))
            {
                return(await Task.FromResult(AuthenticateResult.Skip()));
            }

            if (authValue.Equals(Options.SecurityKey))
            {
                return(await Task.FromResult(AuthenticateResult.Success(
                                                 new AuthenticationTicket(new System.Security.Claims.ClaimsPrincipal(new ClaimsIdentity(new[]
                {
                    new Claim(ClaimsIdentity.DefaultRoleClaimType, Roles.MatRegisteredUser, ClaimValueTypes.String)
                }, Options.AuthenticationScheme)), new AuthenticationProperties(), Options.AuthenticationScheme))));
            }
            else
            {
                return(await Task.FromResult(AuthenticateResult.Fail("Incorrenct key")));
            }
        }
Beispiel #8
0
        /// <inheritdoc />
        protected override sealed async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            // get authorization header
            string auth = Request.Headers[AuthorizationHeader];

            if (auth == null)
            {
                return(AuthenticateResult.Skip());
            }

            // confirm authorization scheme
            string[] authParts = auth.Split(' ');
            if (authParts.Length != 2)
            {
                return(AuthenticateResult.Fail("Invalid authorization header"));
            }
            else if (!ShouldHandleScheme(authParts[0], Options.AutomaticAuthenticate))
            {
                return(AuthenticateResult.Fail($"Authorization scheme \"{authParts[0]}\" is not supported"));
            }

            // extract user and password
            string base64 = authParts[1];
            string authValue;

            try
            {
                byte[] bytes = Convert.FromBase64String(base64);
                authValue = Encoding.ASCII.GetString(bytes);
            }
            catch
            {
                authValue = null;
            }
            if (string.IsNullOrEmpty(authValue))
            {
                return(AuthenticateResult.Fail("Invalid authorization header base64 value"));
            }

            // find and validate user
            var user = await HandleAuthenticateHeaderAsync(authValue);

            if (user == null)
            {
                return(AuthenticateResult.Fail("User was not found"));
            }

            string validationResult = await ValidateUserAsync(user);

            if (validationResult != null)
            {
                return(AuthenticateResult.Fail(validationResult));
            }

            // create authentication ticket
            var ticket = await CreateAuthenticationTicketAsync(user);

            return(AuthenticateResult.Success(ticket));
        }
 protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
 {
     if (Context.User.Identity.IsAuthenticated)
     {
         return(await Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(Context.User, new AuthenticationProperties(), Options.AuthenticationScheme))));
     }
     return(await Task.FromResult(AuthenticateResult.Skip()));
 }
Beispiel #10
0
        protected override Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            var authorizationHeader = Context.Request.Headers["Authorization"];

            if (!authorizationHeader.Any())
            {
                return(Task.FromResult(AuthenticateResult.Skip()));
            }

            var value = authorizationHeader.ToString();

            if (string.IsNullOrWhiteSpace(value))
            {
                return(Task.FromResult(AuthenticateResult.Skip()));
            }

            // place logic here to validate the header value (decrypt, call db etc)
            var token         = value.Replace(Scheme.Custom, string.Empty).Trim();
            var authorization = Encoding.UTF8.GetString(Convert.FromBase64String(token)).Split(':');

            if (!authorization.Any())
            {
                return(Task.FromResult(AuthenticateResult.Skip()));
            }

            if (authorization.Length != 2)
            {
                return(Task.FromResult(AuthenticateResult.Skip()));
            }

            var user = authorization[0];
            var pass = authorization[1];

            var valid = user.Equals("Aladdin") && pass.Equals("open sesame");

            if (!valid)
            {
                return(Task.FromResult(AuthenticateResult.Skip()));
            }

            // create a new claims identity and return an AuthenticationTicket
            // with the correct scheme

            var claims = new[]
            {
                new Claim(ClaimTypes.Name, user)
            };

            var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, Scheme.Custom));

            var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Custom);

            return(Task.FromResult(AuthenticateResult.Success(ticket)));
        }
Beispiel #11
0
 protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
 {
     if (Request.Query.ContainsKey("$tweeklegacy"))
     {
         return(AuthenticateResult.Success(
                    new AuthenticationTicket(
                        new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim("iss", "TweekLegacy") })), null,
                        "TweekLegacy")));
     }
     return(AuthenticateResult.Skip());
 }
Beispiel #12
0
        private async Task <AuthenticateResult> ReadCookieTicket()
        {
            var cookie = Options.CookieManager.GetRequestCookie(Context, Options.CookieName);

            if (string.IsNullOrEmpty(cookie))
            {
                return(AuthenticateResult.Skip());
            }

            var ticket = Options.TicketDataFormat.Unprotect(cookie, GetTlsTokenBinding());

            if (ticket == null)
            {
                return(AuthenticateResult.Fail("Unprotect ticket failed"));
            }

            if (Options.SessionStore != null)
            {
                var claim = ticket.Principal.Claims.FirstOrDefault(c => c.Type.Equals(SessionIdClaim));
                if (claim == null)
                {
                    return(AuthenticateResult.Fail("SessionId missing"));
                }
                _sessionKey = claim.Value;
                ticket      = await Options.SessionStore.RetrieveAsync(_sessionKey);

                if (ticket == null)
                {
                    return(AuthenticateResult.Fail("Identity missing in session store"));
                }
            }

            var currentUtc = DateTimeOffset.UtcNow;
            var issuedUtc  = ticket.Properties.IssuedUtc;
            var expiresUtc = ticket.Properties.ExpiresUtc;

            if (expiresUtc != null && expiresUtc.Value < currentUtc)
            {
                if (Options.SessionStore != null)
                {
                    await Options.SessionStore.RemoveAsync(_sessionKey);
                }
                return(AuthenticateResult.Fail("Ticket expired"));
            }

            CheckForRefresh(ticket);

            // Finally we have a valid ticket
            return(AuthenticateResult.Success(ticket));
        }
        private Task <AuthenticateResult> ReadPlatformTicket()
        {
            //读取平台Cookie
            var platformCookie = Options.CookieManager.GetRequestCookie(Context, Options.PlatformName);

            if (string.IsNullOrEmpty(platformCookie))
            {
                return(Task.FromResult(AuthenticateResult.Skip()));
            }

            //==============================模拟操作,=================================
            //此处应该和平台约定一套加密解密的算法,然后实现掉IDataProtectionProvider接口
            var principal = new ClaimsPrincipal();
            var authProp  = new AuthenticationProperties();

            var claims = new List <Claim>();

            claims.Add(new Claim(ClaimTypes.Name, "zhangsan"));
            claims.Add(new Claim(ClaimTypes.Email, "*****@*****.**"));
            var identity = new ClaimsIdentity(claims, Options.PlatformName);

            principal.AddIdentity(identity);

            principal.Claims.Append(new Claim(SessionIdClaim, "SessionId"));

            var myTicket = new AuthenticationTicket(principal, authProp, Options.AuthenticationScheme);

            var myPlatformCookie = Options.TicketDataFormat.Protect(myTicket);
            //==============================END 模拟操作=================================


            //解析Cookie中加密的票据
            var ticket = Options.TicketDataFormat.Unprotect(myPlatformCookie);

            if (ticket == null)
            {
                return(Task.FromResult(AuthenticateResult.Fail("解密平台票据失败")));
            }

            //验证票据是否过期或有效
            var issuedUtc  = ticket.Properties.IssuedUtc;
            var expiresUtc = ticket.Properties.ExpiresUtc;

            if (issuedUtc != null && expiresUtc != null && expiresUtc.Value < DateTime.UtcNow)
            {
                return(Task.FromResult((AuthenticateResult.Fail("票据过期"))));
            }

            return(Task.FromResult(AuthenticateResult.Success(ticket)));
        }
        protected override Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            var ticketData = Context.Session.GetString(Options.CookieName(Context));

            if (ticketData == null)
            {
                return(Task.FromResult(AuthenticateResult.Skip()));
            }
            try
            {
                var ticket = Options.TicketDataFormat.Unprotect(ticketData, GetTlsTokenBinding());
                return(Task.FromResult(AuthenticateResult.Success(ticket)));
            }
            catch (Exception ex)
            {
                return(Task.FromResult(AuthenticateResult.Fail(ex)));
            }
        }
        protected override Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            string cookieValue = Request.Cookies[Options.CookieName(Context)];

            if (cookieValue == null)
            {
                return(Task.FromResult(AuthenticateResult.Skip()));
            }
            try
            {
                var ticket = Options.TicketDataFormat.Unprotect(cookieValue, GetTlsTokenBinding());
                return(Task.FromResult(AuthenticateResult.Success(ticket)));
            }
            catch (Exception ex)
            {
                return(Task.FromResult(AuthenticateResult.Fail(ex)));
            }
        }
Beispiel #16
0
        private async Task <AuthenticateResult> ReadAuthorizationHeader()
        {
            string             token  = null;
            AuthenticateResult result = null;

            // Give application opportunity to find from a different location, adjust, or reject token
            var messageReceivedContext = new MessageReceivedContext(Context, Options);

            // event can set the token
            await Options.Events.MessageReceived(messageReceivedContext);

            if (messageReceivedContext.CheckEventResult(out result))
            {
                return(result);
            }

            // If application retrieved token from somewhere else, use that.
            token = messageReceivedContext.Token;

            if (string.IsNullOrEmpty(token))
            {
                string authorization = Request.Headers["Authorization"];

                // If no authorization header found, nothing to process further
                if (string.IsNullOrEmpty(authorization))
                {
                    return(AuthenticateResult.Skip());
                }

                if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
                {
                    token = authorization.Substring("Bearer ".Length).Trim();
                }

                // If no token found, no further work possible
                if (string.IsNullOrEmpty(token))
                {
                    return(AuthenticateResult.Skip());
                }
            }

            return(null);
        }
Beispiel #17
0
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            var authorization = Request.Headers["authorization"];

            if (string.IsNullOrEmpty(authorization))
            {
                return(AuthenticateResult.Skip());
            }
            var valid = Validate(Request);

            if (valid)
            {
                var principal = new ClaimsPrincipal(new ClaimsIdentity("HMAC"));
                var ticket    = new AuthenticationTicket(principal, new AuthenticationProperties(), Options.AuthenticationScheme);
                return(AuthenticateResult.Success(ticket));
            }

            return(AuthenticateResult.Fail("Authentication failed"));
        }
Beispiel #18
0
        protected override Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            var header = Request.Headers["Authorization"].ToString();

            if (string.IsNullOrEmpty(header) || !header.StartsWith("Bearer "))
            {
                return(Task.FromResult(AuthenticateResult.Skip()));
            }

            var user      = header.Substring(7);
            var principal = PrincipalFactory.Get(user);

            if (principal == null)
            {
                return(Task.FromResult(AuthenticateResult.Fail("No such user")));
            }

            var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Options.AuthenticationScheme);

            return(Task.FromResult(AuthenticateResult.Success(ticket)));
        }
Beispiel #19
0
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            string authorization = Request.Headers["Authorization"];

            if (string.IsNullOrEmpty(authorization))
            {
                return(AuthenticateResult.Skip());
            }

            string key = null;

            if (authorization.StartsWith("lousysecurity ", StringComparison.OrdinalIgnoreCase))
            {
                key = authorization.Substring("lousysecurity ".Length).Trim();
            }
            else
            {
                return(AuthenticateResult.Skip());
            }

            try
            {
                var keyGuid = new Guid(key);
                var player  = await Options.DbContext.Players.SingleOrDefaultAsync(x => x.LousySecurityKey == keyGuid);

                if (player != null)
                {
                    var principal = new ClaimsPrincipal(new ClaimsIdentity(CreatePlayerClaims(player), Options.AuthenticationScheme));
                    return(AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties(), Options.AuthenticationScheme)));
                }

                return(AuthenticateResult.Fail("No such user"));
            }
            catch (Exception ex)
            {
                return(AuthenticateResult.Fail(ex));
            }
        }
Beispiel #20
0
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            Logger.LogInformation("starting authentication handler for app service authentication");

            if (this.Context.User == null || this.Context.User.Identity == null || this.Context.User.Identity.IsAuthenticated == false)
            {
                Logger.LogInformation("identity not found, attempting to fetch from auth endpoint /.auth/me");

                var cookieContainer = new CookieContainer();

                HttpClientHandler handler = new HttpClientHandler()
                {
                    CookieContainer = cookieContainer
                };

                var uriString = $"{Context.Request.Scheme}://{Context.Request.Host}";

                Logger.LogDebug("host uri: {0}", uriString);

                foreach (var c in Context.Request.Cookies)
                {
                    cookieContainer.Add(new Uri(uriString), new Cookie(c.Key, c.Value));
                }

                Logger.LogDebug("found {0} cookies in request", cookieContainer.Count);

                foreach (var cookie in Context.Request.Cookies)
                {
                    Logger.LogDebug(cookie.Key);
                }

                //fetch value from endpoint
                var request = new HttpRequestMessage(HttpMethod.Get, $"{uriString}/.auth/me");

                foreach (var header in Context.Request.Headers)
                {
                    if (header.Key.StartsWith("X-ZUMO-"))
                    {
                        request.Headers.Add(header.Key, header.Value[0]);
                    }
                }

                JArray payload = null;

                using (HttpClient client = new HttpClient(handler))
                {
                    try
                    {
                        var response = await client.SendAsync(request);

                        if (!response.IsSuccessStatusCode)
                        {
                            Logger.LogDebug("auth endpoint was not sucessful. Status code: {0}, reason {1}", response.StatusCode, response.ReasonPhrase);
                            return(AuthenticateResult.Fail("Unable to fetch user information from auth endpoint."));
                        }

                        var content = await response.Content.ReadAsStringAsync();

                        payload = JArray.Parse(content);
                    }
                    catch (Exception ex)
                    {
                        Logger.LogError(ex.Message);
                    }
                };

                if (payload == null)
                {
                    return(AuthenticateResult.Fail("Could not retreive json from /me endpoint."));
                }

                //build up identity from json...
                var id           = payload[0]["user_id"].Value <string>();
                var idToken      = payload[0]["id_token"].Value <string>();
                var providerName = payload[0]["provider_name"].Value <string>();

                Logger.LogDebug("payload was fetched from endpoint. id: {0}", id);

                var identity = new GenericIdentity(id);

                Logger.LogInformation("building claims from payload...");

                List <Claim> claims = new List <Claim>();
                foreach (var claim in payload[0]["user_claims"])
                {
                    claims.Add(new Claim(claim["typ"].ToString(), claim["val"].ToString()));
                }

                Logger.LogInformation("Add claims to new identity");

                identity.AddClaims(claims);
                identity.AddClaim(new Claim("id_token", idToken));
                identity.AddClaim(new Claim("provider_name", providerName));

                ClaimsPrincipal p = new GenericPrincipal(identity, null); //todo add roles?

                var ticket = new AuthenticationTicket(p,
                                                      new Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties(),
                                                      Options.AuthenticationScheme);

                Logger.LogInformation("Set identity to user context object.");
                this.Context.User = p;

                Logger.LogInformation("identity build was a success, returning ticket");
                return(AuthenticateResult.Success(ticket));
            }

            Logger.LogInformation("identity already set, skipping middleware");
            return(AuthenticateResult.Skip());
        }
Beispiel #21
0
        protected override async Task <AuthenticateResult> HandleRemoteAuthenticateAsync()
        {
            // Always extract the "state" parameter from the query string.
            var state = Request.Query[OpenIdAuthenticationConstants.Parameters.State];

            if (string.IsNullOrEmpty(state))
            {
                return(AuthenticateResult.Fail("The authentication response was rejected " +
                                               "because the state parameter was missing."));
            }

            var properties = Options.StateDataFormat.Unprotect(state);

            if (properties == null)
            {
                return(AuthenticateResult.Fail("The authentication response was rejected " +
                                               "because the state parameter was invalid."));
            }

            // Validate the anti-forgery token.
            if (!ValidateCorrelationId(properties))
            {
                return(AuthenticateResult.Fail("The authentication response was rejected " +
                                               "because the anti-forgery token was invalid."));
            }

            OpenIdAuthenticationMessage message;

            // OpenID 2.0 responses MUST necessarily be made using either GET or POST.
            // See http://openid.net/specs/openid-authentication-2_0.html#anchor4
            if (!string.Equals(Request.Method, "GET", StringComparison.OrdinalIgnoreCase) &&
                !string.Equals(Request.Method, "POST", StringComparison.OrdinalIgnoreCase))
            {
                return(AuthenticateResult.Fail("The authentication response was rejected because it was made " +
                                               "using an invalid method: make sure to use either GET or POST."));
            }

            if (string.Equals(Request.Method, "GET", StringComparison.OrdinalIgnoreCase))
            {
                message = new OpenIdAuthenticationMessage(Request.Query);
            }

            else
            {
                // OpenID 2.0 responses MUST include a Content-Type header when using POST.
                // See http://openid.net/specs/openid-authentication-2_0.html#anchor4
                if (string.IsNullOrEmpty(Request.ContentType))
                {
                    return(AuthenticateResult.Fail("The authentication response was rejected because " +
                                                   "it was missing the mandatory 'Content-Type' header."));
                }

                // May have media/type; charset=utf-8, allow partial match.
                if (!Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase))
                {
                    return(AuthenticateResult.Fail("The authentication response was rejected because an invalid Content-Type header " +
                                                   "was received: make sure to use 'application/x-www-form-urlencoded'."));
                }

                message = new OpenIdAuthenticationMessage(await Request.ReadFormAsync(Context.RequestAborted));
            }

            // Ensure that the current request corresponds to an OpenID 2.0 assertion.
            if (!string.Equals(message.Namespace, OpenIdAuthenticationConstants.Namespaces.OpenId, StringComparison.Ordinal))
            {
                return(AuthenticateResult.Fail("The authentication response was rejected because it was missing the mandatory " +
                                               "'openid.ns' parameter or because an unsupported version of OpenID was used."));
            }

            // Stop processing the message if the authentication process was cancelled by the user.
            if (string.Equals(message.Mode, OpenIdAuthenticationConstants.Modes.Cancel, StringComparison.Ordinal))
            {
                return(AuthenticateResult.Fail("The authentication response was rejected because " +
                                               "the operation was cancelled by the user."));
            }

            // Stop processing the message if an error was returned by the provider.
            else if (string.Equals(message.Mode, OpenIdAuthenticationConstants.Modes.Error, StringComparison.Ordinal))
            {
                if (string.IsNullOrEmpty(message.Error))
                {
                    return(AuthenticateResult.Fail("The authentication response was rejected because an " +
                                                   "unspecified error was returned by the identity provider."));
                }

                return(AuthenticateResult.Fail("The authentication response was rejected because " +
                                               $"an error was returned by the identity provider: {message.Error}."));
            }

            // At this point, stop processing the message if the assertion was not positive.
            else if (!string.Equals(message.Mode, OpenIdAuthenticationConstants.Modes.IdRes, StringComparison.Ordinal))
            {
                return(AuthenticateResult.Fail("The authentication response was rejected because " +
                                               "the identity provider declared it as invalid."));
            }

            // Stop processing the message if the assertion
            // was not validated by the identity provider.
            if (!await VerifyAssertionAsync(message))
            {
                return(AuthenticateResult.Fail("The authentication response was rejected by the identity provider."));
            }

            var address = QueryHelpers.AddQueryString(uri: properties.Items[OpenIdAuthenticationConstants.Properties.ReturnTo],
                                                      name: OpenIdAuthenticationConstants.Parameters.State, value: state);

            // Validate the return_to parameter by comparing it to the address stored in the properties.
            // See http://openid.net/specs/openid-authentication-2_0.html#verify_return_to
            if (!string.Equals(message.ReturnTo, address, StringComparison.Ordinal))
            {
                return(AuthenticateResult.Fail("The authentication response was rejected because the return_to parameter was invalid."));
            }

            // Make sure the OpenID 2.0 assertion contains an identifier.
            if (string.IsNullOrEmpty(message.ClaimedIdentifier))
            {
                return(AuthenticateResult.Fail("The authentication response was rejected because it " +
                                               "was missing the mandatory 'claimed_id' parameter."));
            }

            var identity = new ClaimsIdentity(Options.AuthenticationScheme);

            // Add the claimed identifier to the identity.
            identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, message.ClaimedIdentifier, ClaimValueTypes.String, Options.ClaimsIssuer));

            // Add the most common attributes to the identity.
            var attributes = message.GetAttributes();

            foreach (var attribute in attributes)
            {
                // http://axschema.org/contact/email
                if (string.Equals(attribute.Key, OpenIdAuthenticationConstants.Attributes.Email, StringComparison.Ordinal))
                {
                    identity.AddClaim(new Claim(ClaimTypes.Email, attribute.Value, ClaimValueTypes.Email, Options.ClaimsIssuer));
                }

                // http://axschema.org/namePerson
                else if (string.Equals(attribute.Key, OpenIdAuthenticationConstants.Attributes.Name, StringComparison.Ordinal))
                {
                    identity.AddClaim(new Claim(ClaimTypes.Name, attribute.Value, ClaimValueTypes.String, Options.ClaimsIssuer));
                }

                // http://axschema.org/namePerson/first
                else if (string.Equals(attribute.Key, OpenIdAuthenticationConstants.Attributes.Firstname, StringComparison.Ordinal))
                {
                    identity.AddClaim(new Claim(ClaimTypes.GivenName, attribute.Value, ClaimValueTypes.String, Options.ClaimsIssuer));
                }

                // http://axschema.org/namePerson/last
                else if (string.Equals(attribute.Key, OpenIdAuthenticationConstants.Attributes.Lastname, StringComparison.Ordinal))
                {
                    identity.AddClaim(new Claim(ClaimTypes.Surname, attribute.Value, ClaimValueTypes.String, Options.ClaimsIssuer));
                }
            }

            // Create a ClaimTypes.Name claim using ClaimTypes.GivenName and ClaimTypes.Surname
            // if the http://axschema.org/namePerson attribute cannot be found in the assertion.
            if (!identity.HasClaim(claim => string.Equals(claim.Type, ClaimTypes.Name, StringComparison.OrdinalIgnoreCase)) &&
                identity.HasClaim(claim => string.Equals(claim.Type, ClaimTypes.GivenName, StringComparison.OrdinalIgnoreCase)) &&
                identity.HasClaim(claim => string.Equals(claim.Type, ClaimTypes.Surname, StringComparison.OrdinalIgnoreCase)))
            {
                identity.AddClaim(new Claim(ClaimTypes.Name, $"{identity.FindFirst(ClaimTypes.GivenName).Value} " +
                                            $"{identity.FindFirst(ClaimTypes.Surname).Value}",
                                            ClaimValueTypes.String, Options.ClaimsIssuer));
            }

            var ticket = await CreateTicketAsync(identity, properties, message.ClaimedIdentifier, attributes);

            if (ticket == null)
            {
                Logger.LogInformation("The authentication process was skipped because returned a null ticket was returned.");

                return(AuthenticateResult.Skip());
            }

            return(AuthenticateResult.Success(ticket));
        }
Beispiel #22
0
        /// <summary>
        /// Searches for the 'X-ZUMO-AUTH' header for a token.  If the tokne is found, it is validated using
        /// the options in the <see cref="AzureAppServiceAuthenticationOptions"/>.
        /// </summary>
        /// <returns></returns>
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            // Grab the X-ZUMO-AUTH token if it is available
            // If not, then try the Authorization Bearer token
            string token = Request.Headers["X-ZUMO-AUTH"];

            if (string.IsNullOrEmpty(token))
            {
                string authorization = Request.Headers["Authorization"];
                if (string.IsNullOrEmpty(authorization))
                {
                    return(AuthenticateResult.Skip());
                }
                if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
                {
                    token = authorization.Substring("Bearer ".Length).Trim();
                    if (string.IsNullOrEmpty(token))
                    {
                        return(AuthenticateResult.Skip());
                    }
                }
            }
            Logger.LogDebug($"Obtained Authorization Token = {token}");

            // Convert the signing key we have to something we can use
            var signingKeys = new List <SecurityKey>();

            // If the signingKey is the signature
            signingKeys.Add(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Options.SigningKey)));
            // If it's base-64 encoded
            try
            {
                signingKeys.Add(new SymmetricSecurityKey(Convert.FromBase64String(Options.SigningKey)));
            } catch (FormatException) { /* The key was not base 64 */ }
            // If it's hex encoded, then decode the hex and add it
            try
            {
                if (Options.SigningKey.Length % 2 == 0)
                {
                    signingKeys.Add(new SymmetricSecurityKey(
                                        Enumerable.Range(0, Options.SigningKey.Length)
                                        .Where(x => x % 2 == 0)
                                        .Select(x => Convert.ToByte(Options.SigningKey.Substring(x, 2), 16))
                                        .ToArray()
                                        ));
                }
            } catch (Exception) { /* The key was not hex-encoded */ }

            // validation parameters
            var websiteAuthEnabled        = Environment.GetEnvironmentVariable("WEBSITE_AUTH_ENABLED");
            var inAzureAppService         = (websiteAuthEnabled != null && websiteAuthEnabled.Equals("True", StringComparison.OrdinalIgnoreCase));
            var tokenValidationParameters = new TokenValidationParameters
            {
                // The signature must have been created by the signing key
                ValidateIssuerSigningKey = !inAzureAppService,
                IssuerSigningKeys        = signingKeys,

                // The Issuer (iss) claim must match
                ValidateIssuer = true,
                ValidIssuers   = Options.AllowedIssuers,

                // The Audience (aud) claim must match
                ValidateAudience = true,
                ValidAudiences   = Options.AllowedAudiences,

                // Validate the token expiry
                ValidateLifetime = true,

                // If you want to allow clock drift, set that here
                ClockSkew = TimeSpan.FromSeconds(60)
            };

            // validate the token we received
            var             tokenHandler = new JwtSecurityTokenHandler();
            SecurityToken   validatedToken;
            ClaimsPrincipal principal;

            try
            {
                principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out validatedToken);
            }
            catch (Exception ex)
            {
                Logger.LogError(101, ex, "Cannot validate JWT");
                return(AuthenticateResult.Fail(ex));
            }

            // Get the actual claims from the {issuer}/.auth/me
            try
            {
                client.BaseAddress = new Uri(validatedToken.Issuer);
                client.DefaultRequestHeaders.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                client.DefaultRequestHeaders.Add("X-ZUMO-AUTH", token);

                HttpResponseMessage response = await client.GetAsync("/.auth/me");

                if (response.IsSuccessStatusCode)
                {
                    var jsonContent = await response.Content.ReadAsStringAsync();

                    var userRecord = JsonConvert.DeserializeObject <List <AzureAppServiceClaims> >(jsonContent).First();

                    // Create a new ClaimsPrincipal based on the results of /.auth/me
                    List <Claim> claims = new List <Claim>();
                    foreach (var claim in userRecord.UserClaims)
                    {
                        claims.Add(new Claim(claim.Type, claim.Value));
                    }
                    claims.Add(new Claim("x-auth-provider-name", userRecord.ProviderName));
                    claims.Add(new Claim("x-auth-provider-token", userRecord.IdToken));
                    claims.Add(new Claim("x-user-id", userRecord.UserId));
                    var identity = new GenericIdentity(principal.Claims.Where(x => x.Type.Equals("stable_sid")).First().Value, Options.AuthenticationScheme);
                    identity.AddClaims(claims);
                    principal = new ClaimsPrincipal(identity);
                }
                else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                {
                    return(AuthenticateResult.Fail("/.auth/me says you are unauthorized"));
                }
                else
                {
                    Logger.LogWarning($"/.auth/me returned status = {response.StatusCode} - skipping user claims population");
                }
            }
            catch (Exception ex)
            {
                Logger.LogWarning($"Unable to get /.auth/me user claims - skipping (ex = {ex.GetType().FullName}, msg = {ex.Message})");
            }

            // Generate a new authentication ticket and return success
            var ticket = new AuthenticationTicket(
                principal, new AuthenticationProperties(),
                Options.AuthenticationScheme);

            return(AuthenticateResult.Success(ticket));
        }
Beispiel #23
0
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            string             token  = null;
            AuthenticateResult result = null;

            try
            {
                // Give application opportunity to find from a different location, adjust, or reject token
                var messageReceivedContext = new MessageReceivedContext(Context, Options);

                // event can set the token
                await Options.Events.MessageReceived(messageReceivedContext);

                if (messageReceivedContext.CheckEventResult(out result))
                {
                    return(result);
                }

                // If application retrieved token from somewhere else, use that.
                token = messageReceivedContext.Token;

                if (string.IsNullOrEmpty(token))
                {
                    string authorization = Request.Headers["Authorization"];

                    // If no authorization header found, nothing to process further
                    if (string.IsNullOrEmpty(authorization))
                    {
                        return(AuthenticateResult.Skip());
                    }

                    if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
                    {
                        token = authorization.Substring("Bearer ".Length).Trim();
                    }

                    // If no token found, no further work possible
                    if (string.IsNullOrEmpty(token))
                    {
                        return(AuthenticateResult.Skip());
                    }
                }

                var validationParameters = await Param();

                List <Exception> validationFailures = null;
                SecurityToken    validatedToken;
                foreach (var validator in Options.SecurityTokenValidators)
                {
                    if (validator.CanReadToken(token))
                    {
                        ClaimsPrincipal principal;
                        try
                        {
                            principal = validator.ValidateToken(token, validationParameters, out validatedToken);
                        }
                        catch (Exception ex)
                        {
                            // Refresh the configuration for exceptions that may be caused by key rollovers. The user can also request a refresh in the event.
                            if (Options.RefreshOnIssuerKeyNotFound && Options.ConfigurationManager != null &&
                                ex is SecurityTokenSignatureKeyNotFoundException)
                            {
                                Options.ConfigurationManager.RequestRefresh();
                            }

                            if (validationFailures == null)
                            {
                                validationFailures = new List <Exception>(1);
                            }
                            validationFailures.Add(ex);
                            continue;
                        }


                        var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Options.AuthenticationScheme);
                        var tokenValidatedContext = new TokenValidatedContext(Context, Options)
                        {
                            Ticket        = ticket,
                            SecurityToken = validatedToken,
                        };

                        await Options.Events.TokenValidated(tokenValidatedContext);

                        if (tokenValidatedContext.CheckEventResult(out result))
                        {
                            return(result);
                        }
                        ticket = tokenValidatedContext.Ticket;


                        string email = ticket.Principal.Identity.Name;
                        var    user  = UserExtensions.GetUser(ticket.Principal.Identity.Name);
                        if (user.User.Status != UserStatus.Active)
                        {
                            return(AuthenticateResult.Skip());
                        }

                        if (Options.SaveToken)
                        {
                            ticket.Properties.StoreTokens(new[]
                            {
                                new AuthenticationToken {
                                    Name = "access_token", Value = token
                                }
                            });
                        }

                        return(AuthenticateResult.Success(ticket));
                    }
                }
                if (validationFailures != null)
                {
                    var authenticationFailedContext = new AuthenticationFailedContext(Context, Options)
                    {
                        Exception = (validationFailures.Count == 1) ? validationFailures[0] : new AggregateException(validationFailures)
                    };

                    await Options.Events.AuthenticationFailed(authenticationFailedContext);

                    if (authenticationFailedContext.CheckEventResult(out result))
                    {
                        return(result);
                    }

                    return(AuthenticateResult.Fail(authenticationFailedContext.Exception));
                }

                return(AuthenticateResult.Fail("No SecurityTokenValidator available for token: " + token ?? "[null]"));
            }
            catch (Exception ex)
            {
                var authenticationFailedContext = new AuthenticationFailedContext(Context, Options)
                {
                    Exception = ex
                };

                await Options.Events.AuthenticationFailed(authenticationFailedContext);

                if (authenticationFailedContext.CheckEventResult(out result))
                {
                    return(result);
                }

                throw;
            }
        }
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            string token = Options.TokenRetriever(Context.Request);

            if (token.IsMissing())
            {
                return(AuthenticateResult.Skip());
            }

            if (token.Contains('.') && Options.SkipTokensWithDots)
            {
                _logger.LogTrace("Token contains a dot - skipped because SkipTokensWithDots is set.");
                return(AuthenticateResult.Skip());
            }

            // Resolve request generator
            _requestGenerator = Context.RequestServices.GetService <IIntrospectionRequestGenerator>() ?? new DefaultIntrospectionRequestGenerator();

            if (Options.EnableCaching)
            {
                var claims = await _cache.GetClaimsAsync(token).ConfigureAwait(false);

                if (claims != null && await _requestGenerator.UseCacheAsync(Context.Request, claims))
                {
                    var ticket = CreateTicket(claims);

                    _logger.LogTrace("Token found in cache.");

                    if (Options.SaveToken)
                    {
                        ticket.Properties.StoreTokens(new[]
                        {
                            new AuthenticationToken {
                                Name = "access_token", Value = token
                            }
                        });
                    }

                    return(AuthenticateResult.Success(ticket));
                }

                _logger.LogTrace("Token is not cached, or the introspection response generator rejected the currently cached claims.");
            }

            // Use a LazyAsync to ensure only one thread is requesting introspection for a token - the rest will wait for the result
            var lazyIntrospection = _lazyTokenIntrospections.GetOrAdd(token, CreateLazyIntrospection);

            try
            {
                var response = await lazyIntrospection.Value.ConfigureAwait(false);

                if (response.IsError)
                {
                    _logger.LogError("Error returned from introspection endpoint: " + response.Error);
                    return(AuthenticateResult.Fail("Error returned from introspection endpoint: " + response.Error));
                }

                if (response.IsActive)
                {
                    var ticket = CreateTicket(response.Claims);

                    if (Options.SaveToken)
                    {
                        ticket.Properties.StoreTokens(new[]
                        {
                            new AuthenticationToken {
                                Name = "access_token", Value = token
                            }
                        });
                    }

                    if (Options.EnableCaching)
                    {
                        await _cache.SetClaimsAsync(token, response.Claims, Options.CacheDuration, _logger).ConfigureAwait(false);
                    }

                    return(AuthenticateResult.Success(ticket));
                }
                else
                {
                    return(AuthenticateResult.Fail("Token is not active."));
                }
            }
            finally
            {
                // If caching is on and it succeeded, the claims are now in the cache.
                // If caching is off and it succeeded, the claims will be discarded.
                // Either way, we want to remove the temporary store of claims for this token because it is only intended for de-duping fetch requests
                AsyncLazy <IntrospectionResponse> removed;
                _lazyTokenIntrospections.TryRemove(token, out removed);
            }
        }
        // private OpenIdConnectConfiguration _configuration;

        /// <summary>
        /// Searches the 'Authorization' header for a 'Bearer' token. If the 'Bearer' token is found, it is validated using <see cref="TokenValidationParameters"/> set in the options.
        /// </summary>
        /// <returns></returns>
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            string url = Microsoft.AspNetCore.Http.Extensions.UriHelper.GetDisplayUrl(Context.Request);

            System.Console.WriteLine(url);


            string             token  = null;
            AuthenticateResult result = null;

            try
            {
                // Give application opportunity to find from a different location, adjust, or reject token
                var messageReceivedContext = new MessageReceivedContext(Context, Options);

                // event can set the token
                // await Options.Events.MessageReceived(messageReceivedContext);
                if (messageReceivedContext.CheckEventResult(out result))
                {
                    return(result);
                }

                // If application retrieved token from somewhere else, use that.
                token = messageReceivedContext.Token;

                if (string.IsNullOrEmpty(token))
                {
                    string authorization = Request.Headers["Authorization"];

                    // If no authorization header found, nothing to process further
                    if (string.IsNullOrEmpty(authorization))
                    {
                        return(AuthenticateResult.Skip());
                    }

                    if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
                    {
                        token = authorization.Substring("Bearer ".Length).Trim();
                    }

                    // If no token found, no further work possible
                    if (string.IsNullOrEmpty(token))
                    {
                        return(AuthenticateResult.Skip());
                    }
                }

                /*
                 * if (_configuration == null && Options.ConfigurationManager != null)
                 * {
                 *  _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted);
                 * }
                 *
                 * var validationParameters = Options.TokenValidationParameters.Clone();
                 * if (_configuration != null)
                 * {
                 *  if (validationParameters.ValidIssuer == null && !string.IsNullOrEmpty(_configuration.Issuer))
                 *  {
                 *      validationParameters.ValidIssuer = _configuration.Issuer;
                 *  }
                 *  else
                 *  {
                 *      var issuers = new[] { _configuration.Issuer };
                 *      validationParameters.ValidIssuers = (validationParameters.ValidIssuers == null ? issuers : validationParameters.ValidIssuers.Concat(issuers));
                 *  }
                 *
                 *  validationParameters.IssuerSigningKeys = (validationParameters.IssuerSigningKeys == null ? _configuration.SigningKeys : validationParameters.IssuerSigningKeys.Concat(_configuration.SigningKeys));
                 * }
                 */


                /*
                 * List<Exception> validationFailures = null;
                 * SecurityToken validatedToken;
                 * foreach (var validator in Options.SecurityTokenValidators)
                 * {
                 *  if (validator.CanReadToken(token))
                 *  {
                 *      ClaimsPrincipal principal;
                 *      try
                 *      {
                 *          principal = validator.ValidateToken(token, validationParameters, out validatedToken);
                 *      }
                 *      catch (Exception ex)
                 *      {
                 *          Logger.TokenValidationFailed(token, ex);
                 *
                 *          // Refresh the configuration for exceptions that may be caused by key rollovers. The user can also request a refresh in the event.
                 *          if (Options.RefreshOnIssuerKeyNotFound && Options.ConfigurationManager != null
                 *              && ex is SecurityTokenSignatureKeyNotFoundException)
                 *          {
                 *              Options.ConfigurationManager.RequestRefresh();
                 *          }
                 *
                 *          if (validationFailures == null)
                 *          {
                 *              validationFailures = new List<Exception>(1);
                 *          }
                 *          validationFailures.Add(ex);
                 *          continue;
                 *      }
                 *
                 *      Logger.TokenValidationSucceeded();
                 *
                 *      var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Options.AuthenticationScheme);
                 *      var tokenValidatedContext = new TokenValidatedContext(Context, Options)
                 *      {
                 *          Ticket = ticket,
                 *          SecurityToken = validatedToken,
                 *      };
                 *
                 *      await Options.Events.TokenValidated(tokenValidatedContext);
                 *      if (tokenValidatedContext.CheckEventResult(out result))
                 *      {
                 *          return result;
                 *      }
                 *      ticket = tokenValidatedContext.Ticket;
                 *
                 *      if (Options.SaveToken)
                 *      {
                 *          ticket.Properties.StoreTokens(new[]
                 *          {
                 *              new AuthenticationToken { Name = "access_token", Value = token }
                 *          });
                 *      }
                 *
                 *      return AuthenticateResult.Success(ticket);
                 *  }
                 * }
                 */

                /*
                 * if (validationFailures != null)
                 * {
                 *  var authenticationFailedContext = new AuthenticationFailedContext(Context, Options)
                 *  {
                 *      Exception = (validationFailures.Count == 1) ? validationFailures[0] : new AggregateException(validationFailures)
                 *  };
                 *
                 *  await Options.Events.AuthenticationFailed(authenticationFailedContext);
                 *  if (authenticationFailedContext.CheckEventResult(out result))
                 *  {
                 *      return result;
                 *  }
                 *
                 *  return AuthenticateResult.Fail(authenticationFailedContext.Exception);
                 * }
                 */
                return(AuthenticateResult.Fail("No SecurityTokenValidator available for token: " + token ?? "[null]"));
            }
            catch (Exception ex)
            {
                // Logger.ErrorProcessingMessage(ex);

                var authenticationFailedContext = new AuthenticationFailedContext(Context, Options)
                {
                    Exception = ex
                };

                // await Options.Events.AuthenticationFailed(authenticationFailedContext);
                if (authenticationFailedContext.CheckEventResult(out result))
                {
                    return(result);
                }

                throw;
            }
        }
Beispiel #26
0
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            var notification = new MatchEndpointContext(Context, Options);

            if (Options.AuthorizationEndpointPath.HasValue &&
                Options.AuthorizationEndpointPath == Request.Path)
            {
                notification.MatchesAuthorizationEndpoint();
            }

            else if (Options.LogoutEndpointPath.HasValue &&
                     Options.LogoutEndpointPath == Request.Path)
            {
                notification.MatchesLogoutEndpoint();
            }

            else if (Options.UserinfoEndpointPath.HasValue &&
                     Options.UserinfoEndpointPath == Request.Path)
            {
                notification.MatchesUserinfoEndpoint();
            }

            await Options.Provider.MatchEndpoint(notification);

            if (!notification.IsAuthorizationEndpoint &&
                !notification.IsLogoutEndpoint &&
                !notification.IsUserinfoEndpoint)
            {
                return(AuthenticateResult.Skip());
            }

            // Try to retrieve the current OpenID Connect request from the ASP.NET context.
            // If the request cannot be found, this means that this middleware was configured
            // to use the automatic authentication mode and that HandleAuthenticateAsync
            // was invoked before Invoke*EndpointAsync: in this case, the OpenID Connect
            // request is directly extracted from the query string or the request form.
            var request = Context.GetOpenIdConnectRequest();

            if (request == null)
            {
                if (string.Equals(Request.Method, "GET", StringComparison.OrdinalIgnoreCase))
                {
                    request = new OpenIdConnectMessage(Request.Query.ToDictionary());
                }

                else if (string.Equals(Request.Method, "POST", StringComparison.OrdinalIgnoreCase))
                {
                    if (string.IsNullOrEmpty(Request.ContentType))
                    {
                        return(AuthenticateResult.Skip());
                    }

                    else if (!Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase))
                    {
                        return(AuthenticateResult.Skip());
                    }

                    var form = await Request.ReadFormAsync(Context.RequestAborted);

                    request = new OpenIdConnectMessage(form.ToDictionary());
                }
            }

            // Missing or invalid requests are ignored in HandleAuthenticateAsync:
            // in this case, Skip is used to indicate authentication failed.
            if (request == null)
            {
                return(AuthenticateResult.Skip());
            }

            if (notification.IsAuthorizationEndpoint || notification.IsLogoutEndpoint)
            {
                if (string.IsNullOrEmpty(request.IdTokenHint))
                {
                    return(AuthenticateResult.Skip());
                }

                var ticket = await DeserializeIdentityTokenAsync(request.IdTokenHint, request);

                if (ticket == null)
                {
                    Logger.LogWarning("The identity token extracted from the id_token_hint " +
                                      "parameter was invalid and has been ignored.");

                    return(AuthenticateResult.Skip());
                }

                // Tickets are returned even if they
                // are considered invalid (e.g expired).
                return(AuthenticateResult.Success(ticket));
            }

            else if (notification.IsUserinfoEndpoint)
            {
                string token;
                if (!string.IsNullOrEmpty(request.AccessToken))
                {
                    token = request.AccessToken;
                }

                else
                {
                    string header = Request.Headers[HeaderNames.Authorization];
                    if (string.IsNullOrEmpty(header))
                    {
                        return(AuthenticateResult.Skip());
                    }

                    if (!header.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
                    {
                        return(AuthenticateResult.Skip());
                    }

                    token = header.Substring("Bearer ".Length);
                    if (string.IsNullOrWhiteSpace(token))
                    {
                        return(AuthenticateResult.Skip());
                    }
                }

                var ticket = await DeserializeAccessTokenAsync(token, request);

                if (ticket == null)
                {
                    Logger.LogWarning("The access token extracted from the userinfo " +
                                      "request was expired and has been ignored.");

                    return(AuthenticateResult.Skip());
                }

                if (!ticket.Properties.ExpiresUtc.HasValue ||
                    ticket.Properties.ExpiresUtc < Options.SystemClock.UtcNow)
                {
                    Logger.LogWarning("The access token extracted from the userinfo " +
                                      "request was expired and has been ignored.");

                    return(AuthenticateResult.Skip());
                }

                return(AuthenticateResult.Success(ticket));
            }

            return(AuthenticateResult.Skip());
        }
        /// <summary>
        /// Invoked to process incoming OpenIdConnect messages.
        /// </summary>
        /// <returns>An <see cref="AuthenticationTicket"/> if successful.</returns>
        protected override async Task <AuthenticateResult> HandleRemoteAuthenticateAsync()
        {
            Logger.EnteringOpenIdAuthenticationHandlerHandleRemoteAuthenticateAsync(GetType().FullName);

            OpenIdConnectMessage authorizationResponse = null;

            if (string.Equals(Request.Method, "GET", StringComparison.OrdinalIgnoreCase))
            {
                authorizationResponse = new OpenIdConnectMessage(Request.Query.Select(pair => new KeyValuePair <string, string[]>(pair.Key, pair.Value)));

                // response_mode=query (explicit or not) and a response_type containing id_token
                // or token are not considered as a safe combination and MUST be rejected.
                // See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Security
                if (!string.IsNullOrEmpty(authorizationResponse.IdToken) || !string.IsNullOrEmpty(authorizationResponse.AccessToken))
                {
                    if (Options.SkipUnrecognizedRequests)
                    {
                        // Not for us?
                        return(AuthenticateResult.Skip());
                    }
                    return(AuthenticateResult.Fail("An OpenID Connect response cannot contain an " +
                                                   "identity token or an access token when using response_mode=query"));
                }
            }
            // assumption: if the ContentType is "application/x-www-form-urlencoded" it should be safe to read as it is small.
            else if (string.Equals(Request.Method, "POST", StringComparison.OrdinalIgnoreCase) &&
                     !string.IsNullOrEmpty(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();

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

            if (authorizationResponse == null)
            {
                if (Options.SkipUnrecognizedRequests)
                {
                    // Not for us?
                    return(AuthenticateResult.Skip());
                }
                return(AuthenticateResult.Fail("No message."));
            }

            AuthenticateResult result;

            try
            {
                AuthenticationProperties properties = null;
                if (!string.IsNullOrEmpty(authorizationResponse.State))
                {
                    properties = Options.StateDataFormat.Unprotect(authorizationResponse.State);
                }

                var messageReceivedContext = await RunMessageReceivedEventAsync(authorizationResponse, properties);

                if (messageReceivedContext.CheckEventResult(out result))
                {
                    return(result);
                }
                authorizationResponse = messageReceivedContext.ProtocolMessage;
                properties            = messageReceivedContext.Properties;

                if (properties == null)
                {
                    // Fail if state is missing, it's required for the correlation id.
                    if (string.IsNullOrEmpty(authorizationResponse.State))
                    {
                        // This wasn't a valid OIDC message, it may not have been intended for us.
                        Logger.NullOrEmptyAuthorizationResponseState();
                        if (Options.SkipUnrecognizedRequests)
                        {
                            return(AuthenticateResult.Skip());
                        }
                        return(AuthenticateResult.Fail(Resources.MessageStateIsNullOrEmpty));
                    }

                    // if state exists and we failed to 'unprotect' this is not a message we should process.
                    properties = Options.StateDataFormat.Unprotect(authorizationResponse.State);
                }

                if (properties == null)
                {
                    Logger.UnableToReadAuthorizationResponseState();
                    if (Options.SkipUnrecognizedRequests)
                    {
                        // Not for us?
                        return(AuthenticateResult.Skip());
                    }
                    return(AuthenticateResult.Fail(Resources.MessageStateIsInvalid));
                }

                string userstate = null;
                properties.Items.TryGetValue(OpenIdConnectDefaults.UserstatePropertiesKey, out userstate);
                authorizationResponse.State = userstate;

                if (!ValidateCorrelationId(properties))
                {
                    return(AuthenticateResult.Fail("Correlation failed."));
                }

                // if any of the error fields are set, throw error null
                if (!string.IsNullOrEmpty(authorizationResponse.Error))
                {
                    Logger.AuthorizationResponseError(
                        authorizationResponse.Error,
                        authorizationResponse.ErrorDescription ?? "ErrorDecription null",
                        authorizationResponse.ErrorUri ?? "ErrorUri null");

                    return(AuthenticateResult.Fail(new OpenIdConnectProtocolException(
                                                       string.Format(CultureInfo.InvariantCulture, Resources.MessageContainsError, authorizationResponse.Error,
                                                                     authorizationResponse.ErrorDescription ?? "ErrorDecription null", authorizationResponse.ErrorUri ?? "ErrorUri null"))));
                }

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

                PopulateSessionProperties(authorizationResponse, properties);

                AuthenticationTicket ticket = null;
                JwtSecurityToken     jwt    = null;
                string nonce = null;
                var    validationParameters = Options.TokenValidationParameters.Clone();

                // Hybrid or Implicit flow
                if (!string.IsNullOrEmpty(authorizationResponse.IdToken))
                {
                    Logger.ReceivedIdToken();
                    ticket = ValidateToken(authorizationResponse.IdToken, properties, validationParameters, out jwt);

                    nonce = jwt?.Payload.Nonce;
                    if (!string.IsNullOrEmpty(nonce))
                    {
                        nonce = ReadNonceCookie(nonce);
                    }

                    var tokenValidatedContext = await RunTokenValidatedEventAsync(authorizationResponse, null, properties, ticket, jwt, nonce);

                    if (tokenValidatedContext.CheckEventResult(out result))
                    {
                        return(result);
                    }
                    authorizationResponse = tokenValidatedContext.ProtocolMessage;
                    properties            = tokenValidatedContext.Properties;
                    ticket = tokenValidatedContext.Ticket;
                    jwt    = tokenValidatedContext.SecurityToken;
                    nonce  = tokenValidatedContext.Nonce;
                }

                Options.ProtocolValidator.ValidateAuthenticationResponse(new OpenIdConnectProtocolValidationContext()
                {
                    ClientId         = Options.ClientId,
                    ProtocolMessage  = authorizationResponse,
                    ValidatedIdToken = jwt,
                    Nonce            = nonce
                });

                OpenIdConnectMessage tokenEndpointResponse = null;

                // Authorization Code or Hybrid flow
                if (!string.IsNullOrEmpty(authorizationResponse.Code))
                {
                    var authorizationCodeReceivedContext = await RunAuthorizationCodeReceivedEventAsync(authorizationResponse, properties, ticket, jwt);

                    if (authorizationCodeReceivedContext.CheckEventResult(out result))
                    {
                        return(result);
                    }
                    authorizationResponse = authorizationCodeReceivedContext.ProtocolMessage;
                    properties            = authorizationCodeReceivedContext.Properties;
                    var tokenEndpointRequest = authorizationCodeReceivedContext.TokenEndpointRequest;
                    // If the developer redeemed the code themselves...
                    tokenEndpointResponse = authorizationCodeReceivedContext.TokenEndpointResponse;
                    ticket = authorizationCodeReceivedContext.Ticket;
                    jwt    = authorizationCodeReceivedContext.JwtSecurityToken;

                    if (!authorizationCodeReceivedContext.HandledCodeRedemption)
                    {
                        tokenEndpointResponse = await RedeemAuthorizationCodeAsync(tokenEndpointRequest);
                    }

                    var tokenResponseReceivedContext = await RunTokenResponseReceivedEventAsync(authorizationResponse, tokenEndpointResponse, properties);

                    if (tokenResponseReceivedContext.CheckEventResult(out result))
                    {
                        return(result);
                    }
                    authorizationResponse = tokenResponseReceivedContext.ProtocolMessage;
                    tokenEndpointResponse = tokenResponseReceivedContext.TokenEndpointResponse;

                    // We only have to process the IdToken if we didn't already get one in the AuthorizationResponse
                    if (ticket == null)
                    {
                        // no need to validate signature when token is received using "code flow" as per spec
                        // [http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation].
                        validationParameters.RequireSignedTokens = false;

                        ticket = ValidateToken(tokenEndpointResponse.IdToken, properties, validationParameters, out jwt);

                        nonce = jwt?.Payload.Nonce;
                        if (!string.IsNullOrEmpty(nonce))
                        {
                            nonce = ReadNonceCookie(nonce);
                        }

                        var tokenValidatedContext = await RunTokenValidatedEventAsync(authorizationResponse, tokenEndpointResponse, properties, ticket, jwt, nonce);

                        if (tokenValidatedContext.CheckEventResult(out result))
                        {
                            return(result);
                        }
                        authorizationResponse = tokenValidatedContext.ProtocolMessage;
                        tokenEndpointResponse = tokenValidatedContext.TokenEndpointResponse;
                        properties            = tokenValidatedContext.Properties;
                        ticket = tokenValidatedContext.Ticket;
                        jwt    = tokenValidatedContext.SecurityToken;
                        nonce  = tokenValidatedContext.Nonce;
                    }

                    // Validate the token response if it wasn't provided manually
                    if (!authorizationCodeReceivedContext.HandledCodeRedemption)
                    {
                        Options.ProtocolValidator.ValidateTokenResponse(new OpenIdConnectProtocolValidationContext()
                        {
                            ClientId         = Options.ClientId,
                            ProtocolMessage  = tokenEndpointResponse,
                            ValidatedIdToken = jwt,
                            Nonce            = nonce
                        });
                    }
                }

                if (Options.SaveTokens)
                {
                    SaveTokens(ticket.Properties, tokenEndpointResponse ?? authorizationResponse);
                }

                if (Options.GetClaimsFromUserInfoEndpoint)
                {
                    return(await GetUserInformationAsync(tokenEndpointResponse ?? authorizationResponse, jwt, ticket));
                }

                return(AuthenticateResult.Success(ticket));
            }
            catch (Exception exception)
            {
                Logger.ExceptionProcessingMessage(exception);

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

                var authenticationFailedContext = await RunAuthenticationFailedEventAsync(authorizationResponse, exception);

                if (authenticationFailedContext.CheckEventResult(out result))
                {
                    return(result);
                }

                return(AuthenticateResult.Fail(exception));
            }
        }
Beispiel #28
0
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            var request = Context.GetOpenIdConnectRequest();

            if (request == null)
            {
                throw new InvalidOperationException("An identity cannot be extracted from this request.");
            }

            if (request.IsAuthorizationRequest() || request.IsLogoutRequest())
            {
                if (string.IsNullOrEmpty(request.IdTokenHint))
                {
                    return(AuthenticateResult.Skip());
                }

                var ticket = await DeserializeIdentityTokenAsync(request.IdTokenHint, request);

                if (ticket == null)
                {
                    Logger.LogWarning("The identity token extracted from the id_token_hint " +
                                      "parameter was invalid and has been ignored.");

                    return(AuthenticateResult.Skip());
                }

                // Tickets are returned even if they
                // are considered invalid (e.g expired).
                return(AuthenticateResult.Success(ticket));
            }

            else if (request.IsTokenRequest())
            {
                // Note: this method can be called from the ApplyTokenResponse event,
                // which may be invoked for a missing authorization code/refresh token.
                if (request.IsAuthorizationCodeGrantType())
                {
                    if (string.IsNullOrEmpty(request.Code))
                    {
                        return(AuthenticateResult.Skip());
                    }

                    var ticket = await DeserializeAuthorizationCodeAsync(request.Code, request);

                    if (ticket == null)
                    {
                        Logger.LogWarning("The authorization code extracted from the " +
                                          "token request was invalid and has been ignored.");

                        return(AuthenticateResult.Skip());
                    }

                    return(AuthenticateResult.Success(ticket));
                }

                else if (request.IsRefreshTokenGrantType())
                {
                    if (string.IsNullOrEmpty(request.RefreshToken))
                    {
                        return(AuthenticateResult.Skip());
                    }

                    var ticket = await DeserializeRefreshTokenAsync(request.RefreshToken, request);

                    if (ticket == null)
                    {
                        Logger.LogWarning("The refresh token extracted from the " +
                                          "token request was invalid and has been ignored.");

                        return(AuthenticateResult.Skip());
                    }

                    return(AuthenticateResult.Success(ticket));
                }

                return(AuthenticateResult.Skip());
            }

            throw new InvalidOperationException("An identity cannot be extracted from this request.");
        }
Beispiel #29
0
        /// <summary>
        ///     Authenticate the user identity with the identity provider.
        ///     The method process the request on the endpoint defined by CallbackPath.
        /// </summary>
        protected override async Task <AuthenticateResult> HandleRemoteAuthenticateAsync()
        {
            // Allow login to be constrained to a specific path.
            if (Options.CallbackPath.HasValue && !Options.CallbackPath.Equals(Request.PathBase + Request.Path, StringComparison.OrdinalIgnoreCase))
            {
                // Not for us.
                return(AuthenticateResult.Skip());
            }

            WsFederationMessage wsFederationMessage = null;

            // assumption: if the ContentType is "application/x-www-form-urlencoded" it should be safe to read as it is small.
            if (string.Equals(Request.Method, "POST", StringComparison.OrdinalIgnoreCase) &&
                !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)
            {
                if (!Request.Body.CanSeek)
                {
                    Logger.LogDebug("Buffering request body");
                    // Buffer in case this body was not meant for us.
                    var memoryStream = new MemoryStream();
                    await Request.Body.CopyToAsync(memoryStream);

                    memoryStream.Seek(0, SeekOrigin.Begin);
                    Request.Body = memoryStream;
                }
                var form = await Request.ReadFormAsync();

                Request.Body.Seek(0, SeekOrigin.Begin);

                // TODO: a delegate on WsFederationAuthenticationOptions would allow for users to hook their own custom message.
                wsFederationMessage = new WsFederationMessage(
                    form.Select(pair => new KeyValuePair <string, string[]>(pair.Key, pair.Value.ToArray())));
            }

            if (wsFederationMessage == null || !wsFederationMessage.IsSignInMessage)
            {
                if (Options.SkipUnrecognizedRequests)
                {
                    // Not for us?
                    return(AuthenticateResult.Skip());
                }
                return(AuthenticateResult.Fail("No message"));
            }

            try
            {
                var messageReceivedContext = await RunMessageReceivedEventAsync(wsFederationMessage);

                AuthenticateResult result;
                if (messageReceivedContext.CheckEventResult(out result))
                {
                    return(result);
                }

                if (wsFederationMessage.Wresult == null)
                {
                    return(AuthenticateResult.Fail("Received a sign-in message without a WResult."));
                }

                var token = wsFederationMessage.GetToken();
                if (string.IsNullOrWhiteSpace(token))
                {
                    return(AuthenticateResult.Fail("Received a sign-in message without a token."));
                }

                var securityTokenContext = await RunSecurityTokenReceivedEventAsync(wsFederationMessage);

                if (securityTokenContext.CheckEventResult(out result))
                {
                    return(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?.Concat(issuers) ?? issuers;
                tvp.IssuerSigningKeys = tvp.IssuerSigningKeys?.Concat(_configuration.SigningKeys) ??
                                        _configuration.SigningKeys;

                SecurityToken parsedToken;
                var           principal = Options.SecurityTokenHandlers.ValidateToken(token, tvp, out parsedToken);

                if (!string.IsNullOrEmpty(Options.BootStrapTokenClaimName) && parsedToken != null)
                {
                    ClaimsIdentity identity = principal.Identity as ClaimsIdentity;
                    if (identity != null)
                    {
                        StringBuilder sb     = new StringBuilder();
                        var           writer = XmlWriter.Create(new StringWriter(sb), new XmlWriterSettings
                        {
                            OmitXmlDeclaration = true
                        });
                        Options.SecurityTokenHandlers[parsedToken].WriteToken(writer, parsedToken);
                        writer.Flush();
                        identity.AddClaim(new Claim(Options.BootStrapTokenClaimName, Convert.ToBase64String(Encoding.UTF8.GetBytes(sb.ToString()))));
                    }
                }

                // Retrieve our cached redirect uri
                var state = wsFederationMessage.Wctx;
                // WsFed allows for uninitiated logins, state may be missing.
                var properties = GetPropertiesFromWctx(state);
                var ticket     = new AuthenticationTicket(principal, properties,
                                                          Options.AuthenticationScheme);

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

                var securityTokenValidatedNotification = await RunSecurityTokenValidatedEventAsync(wsFederationMessage,
                                                                                                   ticket);

                return(securityTokenValidatedNotification.CheckEventResult(out result)
                    ? result
                    : AuthenticateResult.Success(ticket));
            }
            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() == typeof(SecurityTokenSignatureKeyNotFoundException))
                {
                    Options.ConfigurationManager.RequestRefresh();
                }

                var authenticationFailedNotification = await RunAuthenticationFailedEventAsync(wsFederationMessage,
                                                                                               exception);

                return(authenticationFailedNotification.CheckEventResult(out AuthenticateResult result)
                    ? result
                    : AuthenticateResult.Fail(exception));
            }
        }