Ejemplo n.º 1
0
        public void GetSets()
        {
            OpenIdConnectProtocolValidationContext validationContext = new OpenIdConnectProtocolValidationContext();
            Type type = typeof(OpenIdConnectProtocolValidationContext);

            PropertyInfo[] properties = type.GetProperties();
            if (properties.Length != 6)
            {
                Assert.True(true, "Number of properties has changed from 6 to: " + properties.Length + ", adjust tests");
            }

            GetSetContext context =
                new GetSetContext
            {
                PropertyNamesAndSetGetValue = new List <KeyValuePair <string, List <object> > >
                {
                    new KeyValuePair <string, List <object> >("State", new List <object> {
                        (string)null, "AuthorizationCode", "AuthorizationCode_AuthorizationCode"
                    }),
                    new KeyValuePair <string, List <object> >("Nonce", new List <object> {
                        (string)null, "Nonce", "Nonce_Nonce"
                    }),
                },
                Object = validationContext,
            };

            TestUtilities.GetSet(context);
            TestUtilities.AssertFailIfErrors("OpenIdConnectProtocolValidationContext_GetSets", context.Errors);
        }
        private async Task ValidateOpenIdConnectProtocolAsync(JwtSecurityToken jwt, OpenIdConnectMessage message, bool ValidateCHash = true)
        {
            string nonce = jwt.Payload.Nonce;

            if (Options.CacheNonces)
            {
                if (await Options.NonceCache.GetAsync(nonce) != null)
                {
                    await Options.NonceCache.RemoveAsync(nonce);
                }
                else
                {
                    // If the nonce cannot be removed, it was
                    // already used and MUST be rejected.
                    nonce = null;
                }
            }
            else
            {
                nonce = ReadNonceCookie(nonce);
            }

            var protocolValidationContext = new OpenIdConnectProtocolValidationContext
            {
                Nonce = nonce
            };

            // If authorization code is null, protocol validator does not validate the chash
            if (ValidateCHash)
            {
                protocolValidationContext.AuthorizationCode = message.Code;
            }

            Options.ProtocolValidator.Validate(jwt, protocolValidationContext);
        }
        public override void ValidateUserInfoResponse(OpenIdConnectProtocolValidationContext validationContext)
        {
            if (validationContext.ValidatedIdToken.InnerToken != null)
            {
                validationContext.ValidatedIdToken = validationContext.ValidatedIdToken.InnerToken;
            }

            base.ValidateUserInfoResponse(validationContext);
        }
        protected override void ValidateIdToken(OpenIdConnectProtocolValidationContext validationContext)
        {
            if (validationContext.ValidatedIdToken.InnerToken != null)
            {
                validationContext.ValidatedIdToken = validationContext.ValidatedIdToken.InnerToken;
            }

            base.ValidateIdToken(validationContext);
        }
Ejemplo n.º 5
0
        private void ValidateCHash(JwtSecurityToken jwt, OpenIdConnectProtocolValidationContext validationContext, PublicOpenIdConnectProtocolValidator protocolValidator, ExpectedException ee)
        {
            try
            {
                protocolValidator.PublicValidateCHash(jwt, validationContext);
                ee.ProcessNoException();
            }
            catch (Exception ex)
            {
                ee.ProcessException(ex);
            }

            return;
        }
        /// <summary>
        ///     Validates the identity token.
        /// </summary>
        /// <param name="idToken">The identifier token.</param>
        /// <param name="oidcClientId">The oidc client identifier.</param>
        /// <param name="nonce">The nonce.</param>
        /// <param name="oidcConfig">The oidc configuration.</param>
        /// <returns>JwtSecurityToken.</returns>
        /// <exception cref="System.ArgumentNullException">
        /// </exception>
        private JwtSecurityToken ValidateIdentityToken(string idToken, string oidcClientId, string nonce, OpenIdConnectConfiguration oidcConfig)
        {
            if (string.IsNullOrWhiteSpace(idToken))
            {
                throw new ArgumentNullException(nameof(idToken));
            }

            if (string.IsNullOrWhiteSpace(oidcClientId))
            {
                throw new ArgumentNullException(nameof(oidcClientId));
            }

            if (string.IsNullOrWhiteSpace(nonce))
            {
                throw new ArgumentNullException(nameof(nonce));
            }

            if (oidcConfig == null)
            {
                throw new ArgumentNullException(nameof(oidcConfig));
            }

            var idTokenValidationParameters = new TokenValidationParameters
            {
                ValidAudience       = oidcClientId,
                ValidIssuer         = oidcConfig.Issuer,
                IssuerSigningTokens = oidcConfig.JsonWebKeySet.GetSigningTokens()
            };

            if (IsTokenValidationDisabled)
            {
                idTokenValidationParameters.LifetimeValidator = (before, expires, token, parameters) => true;
            }

            try
            {
                SecurityToken validatedToken;
                var           jwtTokenHandler = new JwtSecurityTokenHandler();
                jwtTokenHandler.ValidateToken(idToken, idTokenValidationParameters, out validatedToken);

                var validationContext = new OpenIdConnectProtocolValidationContext
                {
                    Nonce = IsTokenValidationDisabled ? null : nonce
                };

                var validatedJwtToken = validatedToken as JwtSecurityToken;

                var oidcProtocolValidator = new OpenIdConnectProtocolValidator();
                if (IsTokenValidationDisabled)
                {
                    oidcProtocolValidator.RequireNonce = false;
                }
                oidcProtocolValidator.Validate(validatedJwtToken, validationContext);

                return(validatedJwtToken);
            }
            catch (Exception ex)
            {
                throw new AuthenticationException("An error occurred validating the Id token.", ex);
            }
        }
Ejemplo n.º 7
0
 protected override void ValidateAtHash(OpenIdConnectProtocolValidationContext validationContext)
 {
 }
        /// <summary>
        /// Invoked to process incoming OpenIdConnect messages.
        /// </summary>
        /// <returns>An <see cref="AuthenticationTicket"/> if successful.</returns>
        protected override async Task <AuthenticationTicket> AuthenticateCoreAsync()
        {
            // Allow login to be constrained to a specific path. Need to make this runtime configurable.
            if (Options.CallbackPath.HasValue && Options.CallbackPath != (Request.PathBase + Request.Path))
            {
                return(null);
            }

            OpenIdConnectMessage openIdConnectMessage = 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)
            {
                IFormCollection form = await Request.ReadFormAsync();

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

                openIdConnectMessage = new OpenIdConnectMessage(form);
            }

            if (openIdConnectMessage == null)
            {
                return(null);
            }

            try
            {
                var messageReceivedNotification = new MessageReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
                {
                    ProtocolMessage = openIdConnectMessage
                };

                await Options.Notifications.MessageReceived(messageReceivedNotification);

                if (messageReceivedNotification.HandledResponse)
                {
                    return(messageReceivedNotification.AuthenticationTicket);
                }

                if (messageReceivedNotification.Skipped)
                {
                    return(null);
                }

                // runtime always adds state, if we don't find it OR we failed to 'unprotect' it this is not a message we
                // should process.
                AuthenticationProperties properties = GetPropertiesFromState(openIdConnectMessage.State);
                if (properties == null)
                {
                    _logger.LogWarning("The state field is missing or invalid.");
                    return(null);
                }

                // devs will need to hook AuthenticationFailedNotification to avoid having 'raw' runtime errors displayed to users.
                if (!string.IsNullOrWhiteSpace(openIdConnectMessage.Error))
                {
                    throw new OpenIdConnectProtocolException(
                              string.Format(CultureInfo.InvariantCulture,
                                            openIdConnectMessage.Error,
                                            Resources.Exception_OpenIdConnectMessageError, openIdConnectMessage.ErrorDescription ?? string.Empty, openIdConnectMessage.ErrorUri ?? string.Empty));
                }

                // code is only accepted with id_token, in this version, hence check for code is inside this if
                // OpenIdConnect protocol allows a Code to be received without the id_token
                if (string.IsNullOrWhiteSpace(openIdConnectMessage.IdToken))
                {
                    _logger.LogWarning("The id_token is missing.");
                    return(null);
                }

                var securityTokenReceivedNotification = new SecurityTokenReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
                {
                    ProtocolMessage = openIdConnectMessage
                };

                await Options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification);

                if (securityTokenReceivedNotification.HandledResponse)
                {
                    return(securityTokenReceivedNotification.AuthenticationTicket);
                }

                if (securityTokenReceivedNotification.Skipped)
                {
                    return(null);
                }

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

                // Copy and augment to avoid cross request race conditions for updated configurations.
                TokenValidationParameters validationParameters = Options.TokenValidationParameters.Clone();
                if (_configuration != null)
                {
                    if (string.IsNullOrWhiteSpace(validationParameters.ValidIssuer))
                    {
                        validationParameters.ValidIssuer = _configuration.Issuer;
                    }
                    else if (!string.IsNullOrWhiteSpace(_configuration.Issuer))
                    {
                        validationParameters.ValidIssuers = (validationParameters.ValidIssuers == null ? new[] { _configuration.Issuer } : validationParameters.ValidIssuers.Concat(new[] { _configuration.Issuer }));
                    }

                    validationParameters.IssuerSigningKeys = (validationParameters.IssuerSigningKeys == null ? _configuration.SigningKeys : validationParameters.IssuerSigningKeys.Concat(_configuration.SigningKeys));
                }

                AuthenticationTicket ticket;
                SecurityToken        validatedToken = null;
                ClaimsPrincipal      principal      = null;
                JwtSecurityToken     jwt            = null;

                foreach (var validator in Options.SecurityTokenValidators)
                {
                    if (validator.CanReadToken(openIdConnectMessage.IdToken))
                    {
                        principal = validator.ValidateToken(openIdConnectMessage.IdToken, validationParameters, out validatedToken);
                        jwt       = validatedToken as JwtSecurityToken;
                        if (jwt == null)
                        {
                            throw new InvalidOperationException("Validated Security Token must be a JwtSecurityToken was: " + (validatedToken == null ? "null" : validatedToken.GetType().ToString()));
                        }
                    }
                }

                if (validatedToken == null)
                {
                    throw new InvalidOperationException("No SecurityTokenValidator found for token: " + openIdConnectMessage.IdToken);
                }

                ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme);
                if (!string.IsNullOrWhiteSpace(openIdConnectMessage.SessionState))
                {
                    ticket.Properties.Dictionary[OpenIdConnectSessionProperties.SessionState] = openIdConnectMessage.SessionState;
                }

                if (_configuration != null && !string.IsNullOrWhiteSpace(_configuration.CheckSessionIframe))
                {
                    ticket.Properties.Dictionary[OpenIdConnectSessionProperties.CheckSessionIFrame] = _configuration.CheckSessionIframe;
                }

                if (Options.UseTokenLifetime)
                {
                    // Override any session persistence to match the token lifetime.
                    DateTime issued = validatedToken.ValidFrom;
                    if (issued != DateTime.MinValue)
                    {
                        ticket.Properties.IssuedUtc = issued;
                    }

                    DateTime expires = validatedToken.ValidTo;
                    if (expires != DateTime.MinValue)
                    {
                        ticket.Properties.ExpiresUtc = expires;
                    }

                    ticket.Properties.AllowRefresh = false;
                }

                var securityTokenValidatedNotification = new SecurityTokenValidatedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
                {
                    AuthenticationTicket = ticket,
                    ProtocolMessage      = openIdConnectMessage
                };

                await Options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification);

                if (securityTokenValidatedNotification.HandledResponse)
                {
                    return(securityTokenValidatedNotification.AuthenticationTicket);
                }

                if (securityTokenValidatedNotification.Skipped)
                {
                    return(null);
                }

                var protocolValidationContext = new OpenIdConnectProtocolValidationContext
                {
                    AuthorizationCode = openIdConnectMessage.Code,
                    Nonce             = RetrieveNonce(jwt.Payload.Nonce),
                };

                Options.ProtocolValidator.Validate(jwt, protocolValidationContext);
                if (openIdConnectMessage.Code != null)
                {
                    var authorizationCodeReceivedNotification = new AuthorizationCodeReceivedNotification(Context, Options)
                    {
                        AuthenticationTicket = ticket,
                        Code             = openIdConnectMessage.Code,
                        JwtSecurityToken = jwt,
                        ProtocolMessage  = openIdConnectMessage,
                        RedirectUri      = ticket.Properties.Dictionary.ContainsKey(OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey) ?
                                           ticket.Properties.Dictionary[OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey] : string.Empty,
                    };

                    await Options.Notifications.AuthorizationCodeReceived(authorizationCodeReceivedNotification);

                    if (authorizationCodeReceivedNotification.HandledResponse)
                    {
                        return(authorizationCodeReceivedNotification.AuthenticationTicket);
                    }

                    if (authorizationCodeReceivedNotification.Skipped)
                    {
                        return(null);
                    }
                }

                return(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().Equals(typeof(SecurityTokenSignatureKeyNotFoundException)))
                {
                    Options.ConfigurationManager.RequestRefresh();
                }

                var authenticationFailedNotification = new AuthenticationFailedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
                {
                    ProtocolMessage = openIdConnectMessage,
                    Exception       = exception
                };

                await Options.Notifications.AuthenticationFailed(authenticationFailedNotification);

                if (authenticationFailedNotification.HandledResponse)
                {
                    return(authenticationFailedNotification.AuthenticationTicket);
                }

                if (authenticationFailedNotification.Skipped)
                {
                    return(null);
                }

                throw;
            }
        }
        /// <summary>
        /// Invoked to process incoming authentication messages.
        /// </summary>
        /// <returns>An <see cref="AuthenticationTicket"/> if successful.</returns>
        protected override async Task <AuthenticationTicket> AuthenticateCoreAsync()
        {
            // Allow login to be constrained to a specific path. Need to make this runtime configurable.
            if (Options.CallbackPath.HasValue && Options.CallbackPath != (Request.PathBase + Request.Path))
            {
                return(null);
            }

            OpenIdConnectMessage openIdConnectMessage = 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.WriteVerbose("Buffering request body");
                    // Buffer in case this body was not meant for us.
                    MemoryStream memoryStream = new MemoryStream();
                    await Request.Body.CopyToAsync(memoryStream);

                    memoryStream.Seek(0, SeekOrigin.Begin);
                    Request.Body = memoryStream;
                }

                IFormCollection form = await Request.ReadFormAsync();

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

                // TODO: a delegate on OpenIdConnectAuthenticationOptions would allow for users to hook their own custom message.
                openIdConnectMessage = new OpenIdConnectMessage(form);
            }

            if (openIdConnectMessage == null)
            {
                return(null);
            }

            ExceptionDispatchInfo authFailedEx = null;

            try
            {
                var messageReceivedNotification = new MessageReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
                {
                    ProtocolMessage = openIdConnectMessage
                };
                await Options.Notifications.MessageReceived(messageReceivedNotification);

                if (messageReceivedNotification.HandledResponse)
                {
                    return(GetHandledResponseTicket());
                }
                if (messageReceivedNotification.Skipped)
                {
                    return(null);
                }

                // runtime always adds state, if we don't find it OR we failed to 'unprotect' it this is not a message we
                // should process.
                AuthenticationProperties properties = GetPropertiesFromState(openIdConnectMessage.State);
                if (properties == null)
                {
                    _logger.WriteWarning("The state field is missing or invalid.");
                    return(null);
                }

                // devs will need to hook AuthenticationFailedNotification to avoid having 'raw' runtime errors displayed to users.
                if (!string.IsNullOrWhiteSpace(openIdConnectMessage.Error))
                {
                    throw new OpenIdConnectProtocolException(
                              string.Format(CultureInfo.InvariantCulture,
                                            openIdConnectMessage.Error,
                                            Resources.Exception_OpenIdConnectMessageError, openIdConnectMessage.ErrorDescription ?? string.Empty, openIdConnectMessage.ErrorUri ?? string.Empty));
                }

                // code is only accepted with id_token, in this version, hence check for code is inside this if
                // OpenIdConnect protocol allows a Code to be received without the id_token
                if (string.IsNullOrWhiteSpace(openIdConnectMessage.IdToken))
                {
                    _logger.WriteWarning("The id_token is missing.");
                    return(null);
                }

                var securityTokenReceivedNotification = new SecurityTokenReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
                {
                    ProtocolMessage = openIdConnectMessage,
                };
                await Options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification);

                if (securityTokenReceivedNotification.HandledResponse)
                {
                    return(GetHandledResponseTicket());
                }
                if (securityTokenReceivedNotification.Skipped)
                {
                    return(null);
                }

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

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

                SecurityToken   validatedToken;
                ClaimsPrincipal principal      = Options.SecurityTokenHandlers.ValidateToken(openIdConnectMessage.IdToken, tvp, out validatedToken);
                ClaimsIdentity  claimsIdentity = principal.Identity as ClaimsIdentity;

                // claims principal could have changed claim values, use bits received on wire for validation.
                JwtSecurityToken     jwt    = validatedToken as JwtSecurityToken;
                AuthenticationTicket ticket = new AuthenticationTicket(claimsIdentity, properties);

                string nonce = null;
                if (Options.ProtocolValidator.RequireNonce)
                {
                    if (String.IsNullOrWhiteSpace(openIdConnectMessage.Nonce))
                    {
                        openIdConnectMessage.Nonce = jwt.Payload.Nonce;
                    }

                    // deletes the nonce cookie
                    nonce = RetrieveNonce(openIdConnectMessage);
                }

                // remember 'session_state' and 'check_session_iframe'
                if (!string.IsNullOrWhiteSpace(openIdConnectMessage.SessionState))
                {
                    ticket.Properties.Dictionary[OpenIdConnectSessionProperties.SessionState] = openIdConnectMessage.SessionState;
                }

                if (!string.IsNullOrWhiteSpace(_configuration.CheckSessionIframe))
                {
                    ticket.Properties.Dictionary[OpenIdConnectSessionProperties.CheckSessionIFrame] = _configuration.CheckSessionIframe;
                }

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

                var securityTokenValidatedNotification = new SecurityTokenValidatedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
                {
                    AuthenticationTicket = ticket,
                    ProtocolMessage      = openIdConnectMessage,
                };
                await Options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification);

                if (securityTokenValidatedNotification.HandledResponse)
                {
                    return(GetHandledResponseTicket());
                }
                if (securityTokenValidatedNotification.Skipped)
                {
                    return(null);
                }
                // Flow possible changes
                ticket = securityTokenValidatedNotification.AuthenticationTicket;

                var protocolValidationContext = new OpenIdConnectProtocolValidationContext
                {
                    AuthorizationCode = openIdConnectMessage.Code,
                    Nonce             = nonce,
                };

                Options.ProtocolValidator.Validate(jwt, protocolValidationContext);

                if (openIdConnectMessage.Code != null)
                {
                    var authorizationCodeReceivedNotification = new AuthorizationCodeReceivedNotification(Context, Options)
                    {
                        AuthenticationTicket = ticket,
                        Code             = openIdConnectMessage.Code,
                        JwtSecurityToken = jwt,
                        ProtocolMessage  = openIdConnectMessage,
                        RedirectUri      = ticket.Properties.Dictionary.ContainsKey(OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey) ?
                                           ticket.Properties.Dictionary[OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey] : string.Empty,
                    };
                    await Options.Notifications.AuthorizationCodeReceived(authorizationCodeReceivedNotification);

                    if (authorizationCodeReceivedNotification.HandledResponse)
                    {
                        return(GetHandledResponseTicket());
                    }
                    if (authorizationCodeReceivedNotification.Skipped)
                    {
                        return(null);
                    }
                    // Flow possible changes
                    ticket = authorizationCodeReceivedNotification.AuthenticationTicket;
                }

                return(ticket);
            }
            catch (Exception exception)
            {
                // We can't await inside a catch block, capture and handle outside.
                authFailedEx = ExceptionDispatchInfo.Capture(exception);
            }

            if (authFailedEx != null)
            {
                _logger.WriteError("Exception occurred while processing message: '" + authFailedEx.ToString());

                // 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 && authFailedEx.SourceException.GetType().Equals(typeof(SecurityTokenSignatureKeyNotFoundException)))
                {
                    Options.ConfigurationManager.RequestRefresh();
                }

                var authenticationFailedNotification = new AuthenticationFailedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
                {
                    ProtocolMessage = openIdConnectMessage,
                    Exception       = authFailedEx.SourceException
                };
                await Options.Notifications.AuthenticationFailed(authenticationFailedNotification);

                if (authenticationFailedNotification.HandledResponse)
                {
                    return(GetHandledResponseTicket());
                }
                if (authenticationFailedNotification.Skipped)
                {
                    return(null);
                }

                authFailedEx.Throw();
            }

            return(null);
        }
Ejemplo n.º 10
0
 public void PublicValidateNonce(JwtSecurityToken jwt, OpenIdConnectProtocolValidationContext context)
 {
     base.ValidateNonce(jwt, context);
 }
Ejemplo n.º 11
0
        public void OpenIdConnectProtocolValidator_ValidateNonce()
        {
            PublicOpenIdConnectProtocolValidator protocolValidatorRequiresTimeStamp = new PublicOpenIdConnectProtocolValidator();
            string nonceWithTimeStamp = protocolValidatorRequiresTimeStamp.GenerateNonce();

            PublicOpenIdConnectProtocolValidator protocolValidatorDoesNotRequireTimeStamp =
                new PublicOpenIdConnectProtocolValidator
            {
                RequireTimeStampInNonce = false,
            };

            PublicOpenIdConnectProtocolValidator protocolValidatorDoesNotRequireNonce =
                new PublicOpenIdConnectProtocolValidator
            {
                RequireNonce = false,
            };

            string nonceWithoutTimeStamp = protocolValidatorDoesNotRequireTimeStamp.GenerateNonce();
            string nonceBadTimeStamp     = "abc.abc";
            string nonceTicksTooLarge    = Int64.MaxValue.ToString() + "." + nonceWithoutTimeStamp;
            string nonceTicksTooSmall    = Int64.MinValue.ToString() + "." + nonceWithoutTimeStamp;
            string nonceTicksNegative    = ((Int64)(-1)).ToString() + "." + nonceWithoutTimeStamp;
            string nonceTicksZero        = ((Int64)(0)).ToString() + "." + nonceWithoutTimeStamp;

            JwtSecurityToken jwtWithNonceWithTimeStamp = new JwtSecurityToken(claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.Nonce, nonceWithTimeStamp)
            });
            JwtSecurityToken jwtWithNonceWithoutTimeStamp = new JwtSecurityToken(claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.Nonce, nonceWithoutTimeStamp)
            });
            JwtSecurityToken jwtWithNonceWithBadTimeStamp = new JwtSecurityToken(claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.Nonce, nonceBadTimeStamp)
            });
            JwtSecurityToken jwtWithNonceTicksTooLarge = new JwtSecurityToken(claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.Nonce, nonceTicksTooLarge)
            });
            JwtSecurityToken jwtWithNonceTicksTooSmall = new JwtSecurityToken(claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.Nonce, nonceTicksTooSmall)
            });
            JwtSecurityToken jwtWithNonceTicksNegative = new JwtSecurityToken(claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.Nonce, nonceTicksNegative)
            });
            JwtSecurityToken jwtWithNonceZero = new JwtSecurityToken(claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.Nonce, nonceTicksZero)
            });
            JwtSecurityToken jwtWithoutNonce = new JwtSecurityToken(claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.NameId, nonceWithTimeStamp)
            });
            JwtSecurityToken jwtWithNonceWhitespace = new JwtSecurityToken(claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.Nonce, "")
            });

            OpenIdConnectProtocolValidationContext validationContext = new OpenIdConnectProtocolValidationContext();

            validationContext.Nonce = null;
            ValidateNonce(jwt: null, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: validationContext, ee: ExpectedException.ArgumentNullException());
            ValidateNonce(jwt: jwtWithNonceWithTimeStamp, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: null, ee: ExpectedException.ArgumentNullException());

            // nonce is null, RequireNonce is true.
            ValidateNonce(jwt: jwtWithNonceWithTimeStamp, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: validationContext, ee:  new ExpectedException(typeof(OpenIdConnectProtocolInvalidNonceException), substringExpected: "IDX10311:"));

            validationContext.Nonce = nonceWithoutTimeStamp;
            ValidateNonce(jwt: jwtWithoutNonce, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: validationContext, ee: new ExpectedException(typeof(OpenIdConnectProtocolInvalidNonceException), substringExpected: "IDX10322:"));
            ValidateNonce(jwt: jwtWithNonceWhitespace, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: validationContext, ee: new ExpectedException(typeof(OpenIdConnectProtocolInvalidNonceException), substringExpected: "IDX10301:"));
            ValidateNonce(jwt: jwtWithNonceWithTimeStamp, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: validationContext, ee: new ExpectedException(typeof(OpenIdConnectProtocolInvalidNonceException), substringExpected: "IDX10301:"));

            validationContext.Nonce = nonceWithTimeStamp;
            ValidateNonce(jwt: jwtWithNonceWithTimeStamp, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: validationContext, ee: ExpectedException.NoExceptionExpected);

            // nonce expired
            validationContext.Nonce = nonceWithTimeStamp;
            protocolValidatorRequiresTimeStamp.NonceLifetime = TimeSpan.FromMilliseconds(10);
            Thread.Sleep(100);
            ValidateNonce(jwt: jwtWithNonceWithTimeStamp, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: validationContext, ee: new ExpectedException(typeof(OpenIdConnectProtocolInvalidNonceException)));

            // nonce missing timestamp, validator requires time stamp
            // 1. not well formed, no '.'
            validationContext.Nonce = nonceWithoutTimeStamp;
            protocolValidatorRequiresTimeStamp.NonceLifetime = TimeSpan.FromMinutes(10);
            ValidateNonce(jwt: jwtWithNonceWithoutTimeStamp, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: validationContext, ee: new ExpectedException(typeof(OpenIdConnectProtocolInvalidNonceException), substringExpected: "IDX10317:"));

            // 2. timestamp not well formed
            validationContext.Nonce = nonceBadTimeStamp;
            ValidateNonce(jwt: jwtWithNonceWithBadTimeStamp, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidNonceException), innerTypeExpected: typeof(FormatException), substringExpected: "IDX10318:"));

            // 3. timestamp not required
            validationContext.Nonce = nonceBadTimeStamp;
            ValidateNonce(jwt: jwtWithNonceWithBadTimeStamp, protocolValidator: protocolValidatorDoesNotRequireTimeStamp, validationContext: validationContext, ee: ExpectedException.NoExceptionExpected);

            // 4. ticks max value
            validationContext.Nonce = nonceTicksTooLarge;
            ValidateNonce(jwt: jwtWithNonceTicksTooLarge, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidNonceException), innerTypeExpected: typeof(ArgumentException), substringExpected: "IDX10320:"));

            // 5. ticks min value small
            validationContext.Nonce = nonceTicksTooSmall;
            ValidateNonce(jwt: jwtWithNonceTicksTooSmall, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidNonceException), substringExpected: "IDX10318:"));

            // 6. ticks negative
            validationContext.Nonce = nonceTicksNegative;
            ValidateNonce(jwt: jwtWithNonceTicksNegative, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidNonceException), substringExpected: "IDX10318:"));

            // 7. ticks zero
            validationContext.Nonce = nonceTicksZero;
            ValidateNonce(jwt: jwtWithNonceZero, protocolValidator: protocolValidatorRequiresTimeStamp, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidNonceException), substringExpected: "IDX10318:"));

            // require nonce false
            validationContext.Nonce = null;
            ValidateNonce(jwt: jwtWithNonceWithoutTimeStamp, protocolValidator: protocolValidatorDoesNotRequireNonce, validationContext: validationContext, ee: ExpectedException.NoExceptionExpected);

            // validationContext has nonce
            validationContext.Nonce = nonceWithTimeStamp;
            ValidateNonce(jwt: jwtWithoutNonce, protocolValidator: protocolValidatorDoesNotRequireNonce, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidNonceException), substringExpected: "IDX10323:"));
        }
Ejemplo n.º 12
0
        public void OpenIdConnectProtocolValidator_CHash()
        {
            PublicOpenIdConnectProtocolValidator protocolValidator = new PublicOpenIdConnectProtocolValidator();

            string authorizationCode1 = protocolValidator.GenerateNonce();
            string authorizationCode2 = protocolValidator.GenerateNonce();

            string chash1 = IdentityUtilities.CreateCHash(authorizationCode1, "SHA256");
            string chash2 = IdentityUtilities.CreateCHash(authorizationCode2, "SHA256");

            Dictionary <string, string> emptyDictionary  = new Dictionary <string, string>();
            Dictionary <string, string> mappedDictionary = new Dictionary <string, string>(protocolValidator.HashAlgorithmMap);

            JwtSecurityToken jwtWithCHash1 =
                new JwtSecurityToken
                (
                    audience: IdentityUtilities.DefaultAudience,
                    claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.CHash, chash1)
            },
                    issuer: IdentityUtilities.DefaultIssuer
                );

            JwtSecurityToken jwtWithEmptyCHash =
                new JwtSecurityToken
                (
                    audience: IdentityUtilities.DefaultAudience,
                    claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.CHash, string.Empty)
            },
                    issuer: IdentityUtilities.DefaultIssuer,
                    signingCredentials: IdentityUtilities.DefaultAsymmetricSigningCredentials
                );

            JwtSecurityToken jwtWithoutCHash =
                new JwtSecurityToken
                (
                    audience: IdentityUtilities.DefaultAudience,
                    claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.Nonce, chash2)
            },
                    issuer: IdentityUtilities.DefaultIssuer
                );

            JwtSecurityToken jwtWithSignatureChash1 =
                new JwtSecurityToken
                (
                    audience: IdentityUtilities.DefaultAudience,
                    claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.CHash, chash1)
            },
                    issuer: IdentityUtilities.DefaultIssuer,
                    signingCredentials: IdentityUtilities.DefaultAsymmetricSigningCredentials
                );

            JwtSecurityToken jwtWithSignatureMultipleChashes =
                new JwtSecurityToken
                (
                    audience: IdentityUtilities.DefaultAudience,
                    claims: new List <Claim> {
                new Claim(JwtRegisteredClaimNames.CHash, chash1), new Claim(JwtRegisteredClaimNames.CHash, chash2)
            },
                    issuer: IdentityUtilities.DefaultIssuer,
                    signingCredentials: IdentityUtilities.DefaultAsymmetricSigningCredentials
                );


            OpenIdConnectProtocolValidationContext validationContext = new OpenIdConnectProtocolValidationContext();

            validationContext.AuthorizationCode = authorizationCode2;
            // chash is not a string, but array
            ValidateCHash(jwt: jwtWithSignatureMultipleChashes, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidCHashException), substringExpected: "IDX10304:"));

            // chash doesn't match
            ValidateCHash(jwt: jwtWithSignatureChash1, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidCHashException), substringExpected: "IDX10304:"));

            // use algorithm map
            validationContext.AuthorizationCode = authorizationCode1;
            ValidateCHash(jwt: jwtWithSignatureChash1, protocolValidator: protocolValidator, validationContext: validationContext, ee: ExpectedException.NoExceptionExpected);

            // Creation of algorithm failed, need to map.
            protocolValidator.SetHashAlgorithmMap(emptyDictionary);
            ValidateCHash(jwt: jwtWithSignatureChash1, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidCHashException), substringExpected: "IDX10307:"));

            protocolValidator.SetHashAlgorithmMap(mappedDictionary);
            ValidateCHash(jwt: null, protocolValidator: protocolValidator, validationContext: validationContext, ee: ExpectedException.ArgumentNullException());
            ValidateCHash(jwt: jwtWithoutCHash, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidCHashException), substringExpected: "IDX10308:"));
            ValidateCHash(jwt: jwtWithEmptyCHash, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidCHashException), substringExpected: "IDX10304:"));
            ValidateCHash(jwt: jwtWithCHash1, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidCHashException), substringExpected: "IDX10307:"));
            ValidateCHash(jwt: jwtWithoutCHash, protocolValidator: protocolValidator, validationContext: null, ee: ExpectedException.ArgumentNullException());

            // make sure default alg works.
            validationContext.AuthorizationCode = authorizationCode1;
            jwtWithCHash1.Header.Remove("alg");
            ValidateCHash(jwt: jwtWithCHash1, protocolValidator: protocolValidator, validationContext: validationContext, ee: ExpectedException.NoExceptionExpected);
        }
Ejemplo n.º 13
0
 public void Validate(JwtSecurityToken jwt, OpenIdConnectProtocolValidator protocolValidator, OpenIdConnectProtocolValidationContext validationContext, ExpectedException ee)
 {
     try
     {
         protocolValidator.Validate(jwt, validationContext);
         ee.ProcessNoException();
     }
     catch (Exception ex)
     {
         ee.ProcessException(ex);
     }
 }
Ejemplo n.º 14
0
        public void OpenIdConnectProtocolValidator_Validate()
        {
            JwtSecurityToken jwt = new JwtSecurityToken();
            OpenIdConnectProtocolValidationContext validationContext = new OpenIdConnectProtocolValidationContext();
            OpenIdConnectProtocolValidator         protocolValidator = new OpenIdConnectProtocolValidator();

            // jwt null
            Validate(jwt: null, protocolValidator: protocolValidator, validationContext: null, ee: ExpectedException.ArgumentNullException());

            // validationContext null
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: null, ee: ExpectedException.ArgumentNullException());

            // aud missing
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10309:"));

            // exp missing
            jwt.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Aud, IdentityUtilities.DefaultAudience));
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10309:"));

            // iat missing
            jwt.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Exp, EpochTime.GetIntDate(DateTime.UtcNow).ToString()));
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10309:"));

            // iss missing
            jwt.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Iat, EpochTime.GetIntDate(DateTime.UtcNow).ToString()));
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10309:"));

            // add iis, nonce is not retuired.
            protocolValidator.RequireNonce = false;
            jwt.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Iss, IdentityUtilities.DefaultIssuer));
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: ExpectedException.NoExceptionExpected);

            // nonce invalid
            string validNonce = protocolValidator.GenerateNonce();

            // add the valid 'nonce' but set validationContext.Nonce to a different 'nonce'.
            protocolValidator.RequireNonce = true;
            jwt.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Nonce, validNonce));
            validationContext.Nonce = protocolValidator.GenerateNonce();
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidNonceException), substringExpected: "IDX10301:"));

            // sub missing, default not required
            validationContext.Nonce = validNonce;
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: ExpectedException.NoExceptionExpected);

            protocolValidator.RequireSub = true;
            Validate(jwt: jwt, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10309:"));

            // authorizationCode invalid
            string validAuthorizationCode = protocolValidator.GenerateNonce();
            string validChash             = IdentityUtilities.CreateCHash(validAuthorizationCode, "SHA256");

            JwtSecurityToken jwtWithSignatureChash =
                new JwtSecurityToken
                (
                    audience: IdentityUtilities.DefaultAudience,
                    claims: new List <Claim>
            {
                new Claim(JwtRegisteredClaimNames.CHash, validChash),
                new Claim(JwtRegisteredClaimNames.Iat, EpochTime.GetIntDate(DateTime.UtcNow).ToString()),
                new Claim(JwtRegisteredClaimNames.Nonce, validNonce),
                new Claim(JwtRegisteredClaimNames.Sub, "sub"),
            },
                    expires: DateTime.UtcNow + TimeSpan.FromHours(1),
                    issuer: IdentityUtilities.DefaultIssuer,
                    signingCredentials: IdentityUtilities.DefaultAsymmetricSigningCredentials
                );

            Dictionary <string, string> algmap = new Dictionary <string, string>(protocolValidator.HashAlgorithmMap);

            protocolValidator.HashAlgorithmMap.Clear();
            protocolValidator.HashAlgorithmMap.Add(JwtAlgorithms.RSA_SHA256, "SHA256");

            validationContext.Nonce             = validNonce;
            validationContext.AuthorizationCode = validNonce;
            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolInvalidCHashException), substringExpected: "IDX10304:"));

            // nonce and authorizationCode valid
            validationContext.AuthorizationCode = validAuthorizationCode;
            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: ExpectedException.NoExceptionExpected);

            // validate optional claims
            protocolValidator.RequireAcr = true;
            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10312:"));
            jwtWithSignatureChash.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Acr, "acr"));

            protocolValidator.RequireAmr = true;
            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10313:"));
            jwtWithSignatureChash.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Amr, "amr"));

            protocolValidator.RequireAuthTime = true;
            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10314:"));
            jwtWithSignatureChash.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.AuthTime, "authTime"));

            protocolValidator.RequireAzp = true;
            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: new ExpectedException(typeExpected: typeof(OpenIdConnectProtocolException), substringExpected: "IDX10315:"));
            jwtWithSignatureChash.Payload.AddClaim(new Claim(JwtRegisteredClaimNames.Azp, "azp"));

            Validate(jwt: jwtWithSignatureChash, protocolValidator: protocolValidator, validationContext: validationContext, ee: ExpectedException.NoExceptionExpected);
        }
        protected override async Task <AuthenticationTicket> AuthenticateCoreAsync()
        {
            if (Options.CallbackPath.HasValue && Options.CallbackPath != (Request.PathBase + Request.Path))
            {
                return(null);
            }

            OpenIdConnectMessage openIdConnectMessage = null;

            if (string.Equals(Request.Method, "POST", StringComparison.OrdinalIgnoreCase) &&
                !string.IsNullOrWhiteSpace(Request.ContentType) &&
                Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase) &&
                Request.Body.CanRead)
            {
                if (!Request.Body.CanSeek)
                {
                    _logger.WriteVerbose("Buffering request body");
                    MemoryStream memoryStream = new MemoryStream();
                    await Request.Body.CopyToAsync(memoryStream);

                    memoryStream.Seek(0, SeekOrigin.Begin);
                    Request.Body = memoryStream;
                }

                IFormCollection form = await Request.ReadFormAsync();

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

                openIdConnectMessage = new OpenIdConnectMessage(form);
            }

            if (openIdConnectMessage == null)
            {
                return(null);
            }

            ExceptionDispatchInfo authFailedEx = null;
            string policy = string.Empty;

            try
            {
                var messageReceivedNotification = new MessageReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
                {
                    ProtocolMessage = openIdConnectMessage
                };
                await Options.Notifications.MessageReceived(messageReceivedNotification);

                if (messageReceivedNotification.HandledResponse)
                {
                    return(GetHandledResponseTicket());
                }
                if (messageReceivedNotification.Skipped)
                {
                    return(null);
                }

                AuthenticationProperties properties = GetPropertiesFromState(openIdConnectMessage.State);
                if (properties == null)
                {
                    _logger.WriteWarning("The state field is missing or invalid.");
                    return(null);
                }

                string nonce = null;
                if (Options.ProtocolValidator.RequireNonce)
                {
                    nonce = RetrieveNonce(openIdConnectMessage);
                }

                if (!string.IsNullOrWhiteSpace(openIdConnectMessage.Error))
                {
                    throw new OpenIdConnectProtocolException(
                              string.Format(CultureInfo.InvariantCulture,
                                            openIdConnectMessage.Error,
                                            "", openIdConnectMessage.ErrorDescription ?? string.Empty, openIdConnectMessage.ErrorUri ?? string.Empty));
                }

                if (string.IsNullOrWhiteSpace(openIdConnectMessage.IdToken))
                {
                    _logger.WriteWarning("The id_token is missing.");
                    return(null);
                }

                var securityTokenReceivedNotification = new SecurityTokenReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
                {
                    ProtocolMessage = openIdConnectMessage,
                };
                await Options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification);

                if (securityTokenReceivedNotification.HandledResponse)
                {
                    return(GetHandledResponseTicket());
                }
                if (securityTokenReceivedNotification.Skipped)
                {
                    return(null);
                }

                // Enable Per-Policy Metadata Retreival
                if (properties.Dictionary.TryGetValue(PolicyParameter, out policy))
                {
                    B2CConfigurationManager mgr = Options.ConfigurationManager as B2CConfigurationManager;
                    _configuration = await mgr.GetConfigurationAsync(Context.Request.CallCancelled, policy);
                }
                else
                {
                    _logger.WriteWarning("No policy identifier was found in the Authentication Properties of the request.");
                    return(null);
                }

                TokenValidationParameters tvp     = Options.TokenValidationParameters.Clone();
                IEnumerable <string>      issuers = new[] { _configuration.Issuer };
                tvp.ValidIssuers        = (tvp.ValidIssuers == null ? issuers : tvp.ValidIssuers.Concat(issuers));
                tvp.IssuerSigningTokens = (tvp.IssuerSigningTokens == null ? _configuration.SigningTokens : tvp.IssuerSigningTokens.Concat(_configuration.SigningTokens));

                SecurityToken   validatedToken;
                ClaimsPrincipal principal      = Options.SecurityTokenHandlers.ValidateToken(openIdConnectMessage.IdToken, tvp, out validatedToken);
                ClaimsIdentity  claimsIdentity = principal.Identity as ClaimsIdentity;

                JwtSecurityToken     jwt    = validatedToken as JwtSecurityToken;
                AuthenticationTicket ticket = new AuthenticationTicket(claimsIdentity, properties);

                if (!string.IsNullOrWhiteSpace(openIdConnectMessage.SessionState))
                {
                    ticket.Properties.Dictionary[OpenIdConnectSessionProperties.SessionState] = openIdConnectMessage.SessionState;
                }

                if (!string.IsNullOrWhiteSpace(_configuration.CheckSessionIframe))
                {
                    ticket.Properties.Dictionary[OpenIdConnectSessionProperties.CheckSessionIFrame] = _configuration.CheckSessionIframe;
                }

                if (Options.UseTokenLifetime)
                {
                    DateTime issued = jwt.ValidFrom;
                    if (issued != DateTime.MinValue)
                    {
                        ticket.Properties.IssuedUtc = issued.ToUniversalTime();
                    }
                    DateTime expires = jwt.ValidTo;
                    if (expires != DateTime.MinValue)
                    {
                        ticket.Properties.ExpiresUtc = expires.ToUniversalTime();
                    }
                    ticket.Properties.AllowRefresh = false;
                }

                var securityTokenValidatedNotification = new SecurityTokenValidatedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
                {
                    AuthenticationTicket = ticket,
                    ProtocolMessage      = openIdConnectMessage,
                };
                await Options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification);

                if (securityTokenValidatedNotification.HandledResponse)
                {
                    return(GetHandledResponseTicket());
                }
                if (securityTokenValidatedNotification.Skipped)
                {
                    return(null);
                }
                ticket = securityTokenValidatedNotification.AuthenticationTicket;

                var protocolValidationContext = new OpenIdConnectProtocolValidationContext
                {
                    AuthorizationCode = openIdConnectMessage.Code,
                    Nonce             = nonce,
                };

                Options.ProtocolValidator.Validate(jwt, protocolValidationContext);
                if (openIdConnectMessage.Code != null)
                {
                    var authorizationCodeReceivedNotification = new AuthorizationCodeReceivedNotification(Context, Options)
                    {
                        AuthenticationTicket = ticket,
                        Code             = openIdConnectMessage.Code,
                        JwtSecurityToken = jwt,
                        ProtocolMessage  = openIdConnectMessage,
                        RedirectUri      = ticket.Properties.Dictionary.ContainsKey(OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey) ?
                                           ticket.Properties.Dictionary[OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey] : string.Empty,
                    };
                    await Options.Notifications.AuthorizationCodeReceived(authorizationCodeReceivedNotification);

                    if (authorizationCodeReceivedNotification.HandledResponse)
                    {
                        return(GetHandledResponseTicket());
                    }
                    if (authorizationCodeReceivedNotification.Skipped)
                    {
                        return(null);
                    }
                    ticket = authorizationCodeReceivedNotification.AuthenticationTicket;
                }

                return(ticket);
            }
            catch (Exception exception)
            {
                authFailedEx = ExceptionDispatchInfo.Capture(exception);
            }

            if (authFailedEx != null)
            {
                _logger.WriteError("Exception occurred while processing message: '" + authFailedEx.ToString());

                if (Options.RefreshOnIssuerKeyNotFound && authFailedEx.SourceException.GetType().Equals(typeof(SecurityTokenSignatureKeyNotFoundException)))
                {
                    B2CConfigurationManager mgr = Options.ConfigurationManager as B2CConfigurationManager;
                    mgr.RequestRefresh(policy);
                }

                var authenticationFailedNotification = new AuthenticationFailedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options)
                {
                    ProtocolMessage = openIdConnectMessage,
                    Exception       = authFailedEx.SourceException
                };
                await Options.Notifications.AuthenticationFailed(authenticationFailedNotification);

                if (authenticationFailedNotification.HandledResponse)
                {
                    return(GetHandledResponseTicket());
                }
                if (authenticationFailedNotification.Skipped)
                {
                    return(null);
                }

                authFailedEx.Throw();
            }

            return(null);
        }