public async Task HandleNotificationAsync( MessageReceivedNotification notification, CancellationToken cancellationToken) { using var statsScope = _dogStatsd.StartTimer("message_processing_ms"); var message = notification.Message; var channel = notification.Message.Channel; var guild = (channel as IGuildChannel)?.Guild; using var logScope = MessageLogMessages.BeginMessageNotificationScope(_logger, guild?.Id, message.Id, channel.Id); MessageLogMessages.MessageReceivedHandling(_logger); await TryTrackMessageAsync( guild, notification.Message, async (guildId) => { MessageLogMessages.MessageRecordCreating(_logger); await _messageRepository.CreateAsync(new MessageCreationData() { Id = message.Id, GuildId = guildId, ChannelId = channel.Id, AuthorId = message.Author.Id, Timestamp = message.Timestamp }); MessageLogMessages.MessageRecordCreated(_logger); }, cancellationToken); MessageLogMessages.MessageReceivedHandled(_logger); }
public void Constructor_Always_PropertiesAreGiven() { var mockMessage = new Mock <ISocketMessage>(); var uut = new MessageReceivedNotification(mockMessage.Object); uut.Message.ShouldBeSameAs(mockMessage.Object); }
private async Task OnMessageReceived(MessageReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification) { _log.Debug("OnMessageReceived: \r\nRequestType={0}\r\nAuthenticationType={1}\r\nRedirectUri={2}\r\nCode={3}", notification.ProtocolMessage.RequestType, notification.Options.AuthenticationType, notification.Options.RedirectUri, notification.ProtocolMessage.Code); await Task.FromResult(0); }
public async Task HandleNotificationAsync_MessageReceivedNotification_InviteLinkIsForMessageGuild_DoesNotDeleteMessage(string messageContent) { (var autoMocker, var uut) = BuildTestContext(); var notification = new MessageReceivedNotification( message: BuildTestMessage(autoMocker, messageContent)); await uut.HandleNotificationAsync(notification); autoMocker.MessageShouldNotHaveBeenDeleted(); }
private static Task HeaderReceived(MessageReceivedNotification<HttpContext, OAuthBearerAuthenticationOptions> notification) { List<Claim> claims = new List<Claim> { new Claim(ClaimTypes.Email, "*****@*****.**"), new Claim(ClaimsIdentity.DefaultNameClaimType, "bob"), }; notification.AuthenticationTicket = new AuthenticationTicket(new ClaimsPrincipal(new ClaimsIdentity(claims)), new Http.Authentication.AuthenticationProperties(), notification.Options.AuthenticationScheme); notification.HandleResponse(); return Task.FromResult<object>(null); }
private static Task HeaderReceived(MessageReceivedNotification <HttpContext, OAuthBearerAuthenticationOptions> notification) { List <Claim> claims = new List <Claim> { new Claim(ClaimTypes.Email, "*****@*****.**"), new Claim(ClaimsIdentity.DefaultNameClaimType, "bob"), }; notification.AuthenticationTicket = new AuthenticationTicket(new ClaimsIdentity(claims, notification.Options.AuthenticationType), new Http.Security.AuthenticationProperties()); notification.HandleResponse(); return(Task.FromResult <object>(null)); }
private async Task OnMessageReceived(MessageReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification) { var tokenResponse = TokenHelper.GetTokens(notification.ProtocolMessage.Code, notification.Options.RedirectUri); notification.ProtocolMessage.TokenType = tokenResponse.TokenType; notification.ProtocolMessage.ExpiresIn = tokenResponse.ExpiresIn.ToString(); notification.ProtocolMessage.IdToken = tokenResponse.IdentityToken; notification.ProtocolMessage.IdTokenHint = tokenResponse.IdentityToken; notification.ProtocolMessage.AccessToken = tokenResponse.AccessToken; notification.ProtocolMessage.RefreshToken = tokenResponse.RefreshToken; notification.ProtocolMessage.Code = null; // This is required so that the AuthorizationCodeReceived event does not trigger after SecurityTokenValidated event await Task.FromResult(0); }
public async Task HandleNotificationAsync_MessageReceivedNotification_MessageChannelIsNotGuildChannel_DoesNotDeleteMessage() { (var autoMocker, var uut) = BuildTestContext(); var notification = new MessageReceivedNotification( message: BuildTestMessage(autoMocker, DefaultInviteLink)); autoMocker.GetMock <ISocketMessage>() .Setup(x => x.Channel) .Returns(new Mock <IMessageChannel>().Object); await uut.HandleNotificationAsync(notification); autoMocker.MessageShouldNotHaveBeenDeleted(); }
public async Task HandleNotificationAsync_MessageReceivedNotification_MessageAuthorIsSelfUser_DoesNotDeleteMessage() { (var autoMocker, var uut) = BuildTestContext(); var notification = new MessageReceivedNotification( message: BuildTestMessage(autoMocker, DefaultInviteLink)); autoMocker.GetMock <ISocketSelfUser>() .Setup(x => x.Id) .Returns(autoMocker.Get <IGuildUser>().Id); await uut.HandleNotificationAsync(notification); autoMocker.MessageShouldNotHaveBeenDeleted(); }
public async Task HandleNotificationAsync_MessageReceivedNotification_Otherwise_DeletesMessage(string messageContent) { (var autoMocker, var uut) = BuildTestContext(); var notification = new MessageReceivedNotification( message: BuildTestMessage(autoMocker, messageContent)); await uut.HandleNotificationAsync(notification); autoMocker.GetMock <IModerationService>() .ShouldHaveReceived(x => x. DeleteMessageAsync( notification.Message, It.Is <string>(y => y.Contains("invite", StringComparison.OrdinalIgnoreCase)), autoMocker.Get <ISocketSelfUser>().Id)); }
public async Task HandleNotificationAsync_MessageReceivedNotification_MessageAuthorHasPostInviteLink_DoesNotDeleteMessage() { (var autoMocker, var uut) = BuildTestContext(); var notification = new MessageReceivedNotification( message: BuildTestMessage(autoMocker, DefaultInviteLink)); autoMocker.GetMock <IAuthorizationService>() .Setup(x => x.HasClaimsAsync( autoMocker.Get <IGuildUser>(), AuthorizationClaim.PostInviteLink)) .ReturnsAsync(true); await uut.HandleNotificationAsync(notification); autoMocker.MessageShouldNotHaveBeenDeleted(); }
public async Task HandleNotificationAsync_MessageReceivedNotification_Otherwise_SendsResponse() { (var autoMocker, var uut) = BuildTestContext(); var notification = new MessageReceivedNotification( message: BuildTestMessage(autoMocker, DefaultInviteLink)); await uut.HandleNotificationAsync(notification); autoMocker.GetMock <IMessageChannel>() .ShouldHaveReceived(x => x. SendMessageAsync( It.Is <string>(y => y.Contains("invite", StringComparison.OrdinalIgnoreCase)), It.IsAny <bool>(), It.IsAny <Embed>(), It.IsAny <RequestOptions>())); }
public async Task HandleNotificationAsync_MessageReceivedNotification_MessageChannelIsUnmoderated_DoesNotDeleteMessage() { (var autoMocker, var uut) = BuildTestContext(); var notification = new MessageReceivedNotification( message: BuildTestMessage(autoMocker, DefaultInviteLink)); autoMocker.GetMock <IDesignatedChannelService>() .Setup(x => x.ChannelHasDesignationAsync( autoMocker.Get <IGuild>(), autoMocker.Get <IMessageChannel>(), DesignatedChannelType.Unmoderated)) .ReturnsAsync(true); await uut.HandleNotificationAsync(notification); autoMocker.MessageShouldNotHaveBeenDeleted(); }
public async Task Handle(MessageReceivedNotification notification, CancellationToken cancellationToken) { if (!(notification.Message.Channel is SocketGuildChannel channel)) { return; } if (notification.Message.Channel.Id != (await _db.Guilds.FindAsync(channel.Guild.Id)).LolaBlessGame) { return; } var commands = new[] { "bless me, lola", "bless me!", "lola bless", "<:LolaBless:731455738152747108>" }; if (!commands.Any(c => notification.Message.Content.StartsWith(c))) { return; } var blessing = _wheel.SelectRandom(); if (blessing.Type == BlessingType.Kiss) { var embed = new EmbedBuilder() .WithUserAsAuthor(Context.User) .WithTitle("You have been kissed") .WithDescription(blessing.Text) .WithColor(0xFA877F) .WithCurrentTimestamp(); await notification.Message.Channel.SendMessageAsync( notification.Message.Author.Mention, embed : embed.Build()); } else { await notification.Message.Channel.SendMessageAsync( $"{notification.Message.Author.Mention} {blessing.Text}"); } await AwardUserAsync(blessing, channel.Guild, (SocketGuildUser)notification.Message.Author); }
private async Task <MessageReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> > RunMessageReceivedNotificationAsync(OpenIdConnectMessage message) { Logger.LogDebug(Resources.OIDCH_0001_MessageReceived, message.BuildRedirectUrl()); var messageReceivedNotification = new MessageReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { ProtocolMessage = message }; await Options.Notifications.MessageReceived(messageReceivedNotification); if (messageReceivedNotification.HandledResponse) { Logger.LogVerbose(Resources.OIDCH_0002_MessageReceivedNotificationHandledResponse); } else if (messageReceivedNotification.Skipped) { Logger.LogVerbose(Resources.OIDCH_0003_MessageReceivedNotificationSkipped); } return(messageReceivedNotification); }
/// <summary> /// Invoked to process incoming authentication messages. /// </summary> /// <returns></returns> protected override async Task <AuthenticationTicket> AuthenticateCoreAsync() { // Allow login to be constrained to a specific path. if (Options.CallbackPath.HasValue && Options.CallbackPath != (Request.PathBase + Request.Path)) { return(null); } 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.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 WsFederationAuthenticationOptions would allow for users to hook their own custom message. wsFederationMessage = new WsFederationMessage(form); } if (wsFederationMessage == null || !wsFederationMessage.IsSignInMessage) { return(null); } ExceptionDispatchInfo authFailedEx = null; try { var messageReceivedNotification = new MessageReceivedNotification <WsFederationMessage, WsFederationAuthenticationOptions>(Context, Options) { ProtocolMessage = wsFederationMessage }; await Options.Notifications.MessageReceived(messageReceivedNotification); if (messageReceivedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (messageReceivedNotification.Skipped) { return(null); } if (wsFederationMessage.Wresult == null) { _logger.WriteWarning("Received a sign-in message without a WResult."); return(null); } string token = wsFederationMessage.GetToken(); if (string.IsNullOrWhiteSpace(token)) { _logger.WriteWarning("Received a sign-in message without a token."); return(null); } var securityTokenReceivedNotification = new SecurityTokenReceivedNotification <WsFederationMessage, WsFederationAuthenticationOptions>(Context, Options) { ProtocolMessage = wsFederationMessage }; 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.IssuerSigningKeys = (tvp.IssuerSigningKeys == null ? _configuration.SigningKeys : tvp.IssuerSigningKeys.Concat(_configuration.SigningKeys)); SecurityToken parsedToken; ClaimsPrincipal principal = Options.SecurityTokenHandlers.ValidateToken(token, tvp, out parsedToken); ClaimsIdentity claimsIdentity = principal.Identity as ClaimsIdentity; // Retrieve our cached redirect uri string state = wsFederationMessage.Wctx; // WsFed allows for uninitiated logins, state may be missing. AuthenticationProperties properties = GetPropertiesFromWctx(state); AuthenticationTicket ticket = new AuthenticationTicket(claimsIdentity, properties); if (Options.UseTokenLifetime) { // Override any session persistence to match the token lifetime. DateTime issued = parsedToken.ValidFrom; if (issued != DateTime.MinValue) { ticket.Properties.IssuedUtc = issued.ToUniversalTime(); } DateTime expires = parsedToken.ValidTo; if (expires != DateTime.MinValue) { ticket.Properties.ExpiresUtc = expires.ToUniversalTime(); } ticket.Properties.AllowRefresh = false; } var securityTokenValidatedNotification = new SecurityTokenValidatedNotification <WsFederationMessage, WsFederationAuthenticationOptions>(Context, Options) { AuthenticationTicket = ticket, ProtocolMessage = wsFederationMessage, }; await Options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification); if (securityTokenValidatedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (securityTokenValidatedNotification.Skipped) { return(null); } // Flow possible changes ticket = securityTokenValidatedNotification.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.SourceException); // 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 <WsFederationMessage, WsFederationAuthenticationOptions>(Context, Options) { ProtocolMessage = wsFederationMessage, Exception = authFailedEx.SourceException }; await Options.Notifications.AuthenticationFailed(authenticationFailedNotification); if (authenticationFailedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (authenticationFailedNotification.Skipped) { return(null); } authFailedEx.Throw(); } return(null); }
internal static async Task MessageReceived(MessageReceivedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context) { Helpers.ThrowIfConditionFailed(() => context.ProtocolMessage != null, "ProtocolMessage is null."); notificationsFired.Add(nameof(MessageReceived)); await Task.FromResult(0); }
/// <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; } }
private async Task <AuthenticationTicket> CreateAuthenticationTicket(OpenIdConnectMessage openIdConnectMessage) { var messageReceivedNotification = new MessageReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { ProtocolMessage = openIdConnectMessage }; await Options.Notifications.MessageReceived(messageReceivedNotification).ConfigureAwait(false); 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, "Exception_OpenIdConnectMessageError", openIdConnectMessage.ErrorDescription ?? string.Empty, openIdConnectMessage.ErrorUri ?? string.Empty)); } // tokens.Item1 contains id token // tokens.Item2 contains access token Tuple <string, string> tokens = await GetTokens(openIdConnectMessage.Code, Options) .ConfigureAwait(false); if (string.IsNullOrWhiteSpace(openIdConnectMessage.IdToken)) { openIdConnectMessage.IdToken = tokens.Item1; } var securityTokenReceivedNotification = new SecurityTokenReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { ProtocolMessage = openIdConnectMessage, }; await Options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification).ConfigureAwait(false); if (securityTokenReceivedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (securityTokenReceivedNotification.Skipped) { return(null); } if (_configuration == null) { _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.Request.CallCancelled) .ConfigureAwait(false); } // 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?.Concat(issuers) ?? issuers; tvp.IssuerSigningTokens = tvp.IssuerSigningTokens?.Concat(_configuration.SigningTokens) ?? _configuration.SigningTokens; SecurityToken validatedToken; ClaimsPrincipal principal = Options.SecurityTokenHandlers.ValidateToken(openIdConnectMessage.IdToken, tvp, out validatedToken); ClaimsIdentity claimsIdentity = principal.Identity as ClaimsIdentity; var claims = await GetClaims(tokens.Item2).ConfigureAwait(false); AddClaim(claims, claimsIdentity, "sub", ClaimTypes.NameIdentifier, Options.AuthenticationType); AddClaim(claims, claimsIdentity, "given_name", ClaimTypes.GivenName); AddClaim(claims, claimsIdentity, "family_name", ClaimTypes.Surname); AddClaim(claims, claimsIdentity, "preferred_username", ClaimTypes.Name); AddClaim(claims, claimsIdentity, "email", ClaimTypes.Email); // 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); if (Options.ProtocolValidator.RequireNonce) { if (String.IsNullOrWhiteSpace(openIdConnectMessage.Nonce)) { openIdConnectMessage.Nonce = jwt.Payload.Nonce; } // deletes the nonce cookie 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).ConfigureAwait(false); if (securityTokenValidatedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (securityTokenValidatedNotification.Skipped) { return(null); } // Flow possible changes ticket = securityTokenValidatedNotification.AuthenticationTicket; // there is no hash of the code (c_hash) in the jwt obtained from the server // I don't know how to perform the validation using ProtocolValidator without the hash // that is why the code below is commented //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) .ConfigureAwait(false); if (authorizationCodeReceivedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (authorizationCodeReceivedNotification.Skipped) { return(null); } // Flow possible changes ticket = authorizationCodeReceivedNotification.AuthenticationTicket; } return(ticket); }
private static Task MessageReceived(MessageReceivedNotification<HttpContext, OAuthBearerAuthenticationOptions> notification) { notification.Token = "CustomToken"; return Task.FromResult<object>(null); }
/// <summary> /// Invokes the login procedure (2nd leg of SP-Initiated login). Analagous to Saml20SignonHandler from ASP.Net DLL /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task<AuthenticationTicket> Invoke(IOwinContext context) { Logger.Debug(TraceMessages.SignOnHandlerCalled); ExceptionDispatchInfo authFailedEx = null; try { var messageReceivedNotification = new MessageReceivedNotification<SamlMessage, SamlAuthenticationOptions>(context, options) { ProtocolMessage = new SamlMessage(context, configuration, null) }; await options.Notifications.MessageReceived(messageReceivedNotification); if (messageReceivedNotification.HandledResponse) { return null; // GetHandledResponseTicket() } if (messageReceivedNotification.Skipped) { return null; } var requestParams = await HandleResponse(context); var assertion = context.Get<Saml20Assertion>("Saml2:assertion"); var securityTokenReceivedNotification = new SecurityTokenReceivedNotification<SamlMessage, SamlAuthenticationOptions>(context, options) { ProtocolMessage = new SamlMessage(context, configuration, assertion) }; await options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification); if (securityTokenReceivedNotification.HandledResponse) { return null; // GetHandledResponseTicket(); } if (securityTokenReceivedNotification.Skipped) { return null; } var ticket = await GetAuthenticationTicket(context, requestParams); var securityTokenValidatedNotification = new SecurityTokenValidatedNotification<SamlMessage, SamlAuthenticationOptions>(context, options) { AuthenticationTicket = ticket, ProtocolMessage = new SamlMessage(context, configuration, assertion) }; await options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification); if (securityTokenValidatedNotification.HandledResponse) { return null; // GetHandledResponseTicket(); } if (securityTokenValidatedNotification.Skipped) { return null; // null; } // Flow possible changes ticket = securityTokenValidatedNotification.AuthenticationTicket; context.Authentication.AuthenticationResponseGrant = new AuthenticationResponseGrant(ticket.Identity, ticket.Properties); return ticket; } catch (Exception ex) { authFailedEx = ExceptionDispatchInfo.Capture(ex); } if (authFailedEx != null) { Logger.Error("Exception occurred while processing message: " + authFailedEx.SourceException); var message = new SamlMessage(context, configuration, context.Get<Saml20Assertion>("Saml2:assertion")); var authenticationFailedNotification = new AuthenticationFailedNotification<SamlMessage, SamlAuthenticationOptions>(context, options) { ProtocolMessage = message, Exception = authFailedEx.SourceException }; await options.Notifications.AuthenticationFailed(authenticationFailedNotification); if (authenticationFailedNotification.HandledResponse) { return null;//GetHandledResponseTicket(); } if (authenticationFailedNotification.Skipped) { return null; //null } authFailedEx.Throw(); } return null; }
protected override async Task <AuthenticationTicket> AuthenticateCoreAsync() { // Allow login to be constrained to a specific path. if (Options.CallbackPath.HasValue && Options.CallbackPath != Request.Path) { return(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) { // 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(); // Post preview release: a delegate on WsFederationAuthenticationOptions would allow for users to hook their own custom message. WsFederationMessage wsFederationMessage = new WsFederationMessage(form); if (!wsFederationMessage.IsSignInMessage) { Request.Body.Seek(0, SeekOrigin.Begin); return(null); } MessageReceivedNotification <WsFederationMessage> messageReceivedNotification = null; if (Options.Notifications != null && Options.Notifications.MessageReceived != null) { messageReceivedNotification = new MessageReceivedNotification <WsFederationMessage> { ProtocolMessage = wsFederationMessage }; await Options.Notifications.MessageReceived(messageReceivedNotification); } if (messageReceivedNotification != null && messageReceivedNotification.Cancel) { return(null); } if (wsFederationMessage.Wresult != null) { string token = wsFederationMessage.GetToken(); if (Options.Notifications != null && Options.Notifications.SecurityTokenReceived != null) { SecurityTokenReceivedNotification securityTokenReceivedNotification = new SecurityTokenReceivedNotification { SecurityToken = token }; await Options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification); if (securityTokenReceivedNotification.Cancel) { return(null); } } ExceptionDispatchInfo authFailedEx = null; try { ClaimsPrincipal principal = Options.SecurityTokenHandlers.ValidateToken(token, Options.TokenValidationParameters); ClaimsIdentity claimsIdentity = principal.Identity as ClaimsIdentity; // Retrieve our cached redirect uri string state = wsFederationMessage.Wctx; AuthenticationProperties properties = GetPropertiesFromWctx(state); AuthenticationTicket ticket = new AuthenticationTicket(claimsIdentity, properties); Request.Context.Authentication.SignIn(claimsIdentity); if (Options.Notifications != null && Options.Notifications.SecurityTokenValidated != null) { await Options.Notifications.SecurityTokenValidated(new SecurityTokenValidatedNotification { AuthenticationTicket = ticket }); } return(ticket); } catch (Exception exception) { // We can't await inside a catch block, capture and handle outside. authFailedEx = ExceptionDispatchInfo.Capture(exception); } if (authFailedEx != null) { if (Options.Notifications != null && Options.Notifications.AuthenticationFailed != null) { // Post preview release: user can update metadata, need consistent messaging. var authenticationFailedNotification = new AuthenticationFailedNotification <WsFederationMessage>() { ProtocolMessage = wsFederationMessage, Exception = authFailedEx.SourceException }; await Options.Notifications.AuthenticationFailed(authenticationFailedNotification); if (!authenticationFailedNotification.Cancel) { authFailedEx.Throw(); } } else { authFailedEx.Throw(); } } } } return(null); }
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); }
public async Task HandleNotificationAsync( MessageReceivedNotification notification, CancellationToken cancellationToken) { var message = notification.Message; var channel = message.Channel; var guild = (channel as IGuildChannel)?.Guild; var author = message.Author; using var logScope = UserMetricsLogMessages.BeginMessageScope(_logger, guild?.Id, channel.Id, author.Id, message.Id); UserMetricsLogMessages.MessageReceivedHandling(_logger); if (guild is null) { UserMetricsLogMessages.IgnoringNonGuildMessage(_logger); return; } if (author.IsBot || author.IsWebhook) { UserMetricsLogMessages.IgnoringNonHumanMessage(_logger); return; } var isOnTopic = true; try { UserMetricsLogMessages.ChannelParticipationFetching(_logger); isOnTopic = await _designatedChannelService.ChannelHasDesignationAsync( guild.Id, channel.Id, DesignatedChannelType.CountsTowardsParticipation, cancellationToken); UserMetricsLogMessages.ChannelParticipationFetched(_logger, isOnTopic); } catch (Exception ex) { UserMetricsLogMessages.ChannelParticipationFetchFailed(_logger, ex); } var isRanked = false; try { UserMetricsLogMessages.UserRankFetching(_logger); isRanked = await _designatedRoleService.RolesHaveDesignationAsync( guild.Id, ((IGuildUser)author).RoleIds, DesignatedRoleType.Rank, cancellationToken); UserMetricsLogMessages.UserRankFetched(_logger, isRanked); } catch (Exception ex) { UserMetricsLogMessages.UserRankFetchFailed(_logger, ex); } var tags = new[] { $"guild:{guild.Name}", $"channel:{channel.Name}", $"offtopic:{!isOnTopic}", $"has_role:{isRanked}" }; _dogStatsd.Increment(MessageReceivedCounterName, tags: tags); UserMetricsLogMessages.MessageReceivedHandled(_logger); }
/// <summary> /// Callback for LinphoneCoreListener /// </summary> public void MessageReceived(LinphoneChatMessage message) { if (BaseModel.UIDispatcher == null) { return; } BaseModel.UIDispatcher.BeginInvoke(() => { LinphoneAddress fromAddress = message.From; string sipAddress = String.Format("{0}@{1}", fromAddress.UserName, fromAddress.Domain); Logger.Msg("[LinphoneManager] Message received from " + sipAddress + ": " + message.Text + "\r\n"); //Vibrate ChatSettingsManager settings = new ChatSettingsManager(); settings.Load(); if ((bool)settings.VibrateOnIncomingMessage) { VibrationDevice vibrator = VibrationDevice.GetDefault(); vibrator.Vibrate(TimeSpan.FromSeconds(1)); } if (MessageListener != null && MessageListener.GetSipAddressAssociatedWithDisplayConversation() != null && MessageListener.GetSipAddressAssociatedWithDisplayConversation().Equals(sipAddress)) { MessageListener.MessageReceived(message); } else { DateTime date = new DateTime(message.Time * TimeSpan.TicksPerSecond, DateTimeKind.Utc).AddYears(1969).ToLocalTime(); DateTime now = DateTime.Now; string dateStr; if (now.Year == date.Year && now.Month == date.Month && now.Day == date.Day) { dateStr = String.Format("{0:HH:mm}", date); } else if (now.Year == date.Year) { dateStr = String.Format("{0:ddd d MMM, HH:mm}", date); } else { dateStr = String.Format("{0:ddd d MMM yyyy, HH:mm}", date); } //TODO: Temp hack to remove string url = message.ExternalBodyUrl; url = url.Replace("\"", ""); //Displays the message as a popup if (MessageReceivedNotification != null) { MessageReceivedNotification.Dismiss(); } MessageReceivedNotification = new CustomMessageBox() { Title = dateStr, Caption = url.Length > 0 ? AppResources.ImageMessageReceived : AppResources.MessageReceived, Message = url.Length > 0 ? "" : message.Text, LeftButtonContent = AppResources.Close, RightButtonContent = AppResources.Show }; MessageReceivedNotification.Dismissed += (s, e) => { switch (e.Result) { case CustomMessageBoxResult.RightButton: BaseModel.CurrentPage.NavigationService.Navigate(new Uri("/Views/Chat.xaml?sip=" + Utils.ReplacePlusInUri(message.PeerAddress.AsStringUriOnly()), UriKind.RelativeOrAbsolute)); break; } }; MessageReceivedNotification.Show(); } }); }
/// <summary> /// Invoked to process incoming authentication messages. /// </summary> /// <returns></returns> protected override async Task <AuthenticationTicket> AuthenticateCoreAsync() { // Allow login to be constrained to a specific path. //if (Options.CallbackPath.HasValue && Options.CallbackPath != (Request.PathBase + Request.Path)) //{ // return null; //} var SamlMessage = await SamlMessageFromRequest(); if (SamlMessage == null || !SamlMessage.IsSignInMessage()) { return(null); } ExceptionDispatchInfo authFailedEx = null; try { var messageReceivedNotification = new MessageReceivedNotification <SamlMessage, SamlAuthenticationOptions>(Context, Options) { ProtocolMessage = SamlMessage }; await Options.Notifications.MessageReceived(messageReceivedNotification); if (messageReceivedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (messageReceivedNotification.Skipped) { return(null); } //if (SamlMessage.Wresult == null) { // _logger.WriteWarning("Received a sign-in message without a WResult."); // return null; //} string token = SamlMessage.GetToken(); if (string.IsNullOrWhiteSpace(token)) { _logger.WriteWarning("Received a sign-in message without a token."); return(null); } var securityTokenReceivedNotification = new SecurityTokenReceivedNotification <SamlMessage, SamlAuthenticationOptions>(Context, Options) { ProtocolMessage = SamlMessage }; await Options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification); if (securityTokenReceivedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (securityTokenReceivedNotification.Skipped) { return(null); } // Copy and augment to avoid cross request race conditions for updated configurations. ClaimsPrincipal principal = null; ClaimsIdentity claimsIdentity = principal.Identity as ClaimsIdentity; // Retrieve our cached redirect uri // string state = SamlMessage.Wctx; // WsFed allows for uninitiated logins, state may be missing. AuthenticationProperties properties = null;// GetPropertiesFromWctx(state); AuthenticationTicket ticket = new AuthenticationTicket(claimsIdentity, properties); //if (Options.UseTokenLifetime) { // // Override any session persistence to match the token lifetime. // DateTime issued = parsedToken.ValidFrom; // if (issued != DateTime.MinValue) { // ticket.Properties.IssuedUtc = issued.ToUniversalTime(); // } // DateTime expires = parsedToken.ValidTo; // if (expires != DateTime.MinValue) { // ticket.Properties.ExpiresUtc = expires.ToUniversalTime(); // } // ticket.Properties.AllowRefresh = false; //} var securityTokenValidatedNotification = new SecurityTokenValidatedNotification <SamlMessage, SamlAuthenticationOptions>(Context, Options) { AuthenticationTicket = ticket, ProtocolMessage = SamlMessage, }; await Options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification); if (securityTokenValidatedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (securityTokenValidatedNotification.Skipped) { return(null); } // Flow possible changes ticket = securityTokenValidatedNotification.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.SourceException); // 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 <SamlMessage, SamlAuthenticationOptions>(Context, Options) { ProtocolMessage = SamlMessage, Exception = authFailedEx.SourceException }; await Options.Notifications.AuthenticationFailed(authenticationFailedNotification); if (authenticationFailedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (authenticationFailedNotification.Skipped) { return(null); } authFailedEx.Throw(); } return(null); }
/// <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; if (string.Equals(Request.Method, "GET", StringComparison.OrdinalIgnoreCase) && Request.Query.Any(q => q.Key == "code")) { _logger.WriteVerbose("Processing request query string"); openIdConnectMessage = new OpenIdConnectMessage(Request.Query); // 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(openIdConnectMessage.IdToken) || !string.IsNullOrEmpty(openIdConnectMessage.AccessToken)) { _logger.WriteWarning("An OpenID Connect response cannot contain an " + "identity token or an access token when using response_mode=query"); return(null); } } // 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.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 { // Run MessageReceived notification { 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, Resources.Exception_OpenIdConnectMessageError, openIdConnectMessage.Error, openIdConnectMessage.ErrorDescription ?? string.Empty, openIdConnectMessage.ErrorUri ?? string.Empty)); } if (_configuration == null) { _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.Request.CallCancelled); } JwtSecurityToken jwt = null; ClaimsPrincipal principal = null; AuthenticationTicket ticket = null; string nonce = null; OpenIdConnectMessage tokenEndpointResponse = null; JwtSecurityToken tokenEndpointJwt = null; // Copy and augment to avoid cross request race conditions for updated configurations. TokenValidationParameters tvp = Options.TokenValidationParameters.Clone(); // Hybrid or Implicit flow if (!string.IsNullOrWhiteSpace(openIdConnectMessage.IdToken)) { // Run SecurityTokenReceived notification { 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); } } principal = ValidateToken(openIdConnectMessage.IdToken, properties, tvp, out jwt); ticket = new AuthenticationTicket(principal.Identity as ClaimsIdentity, properties); 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)) { properties.Dictionary[OpenIdConnectSessionProperties.SessionState] = openIdConnectMessage.SessionState; } if (!string.IsNullOrWhiteSpace(_configuration.CheckSessionIframe)) { properties.Dictionary[OpenIdConnectSessionProperties.CheckSessionIFrame] = _configuration.CheckSessionIframe; } // Run SecurityTokenValidated notification { 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; } } Options.ProtocolValidator.ValidateAuthenticationResponse(new OpenIdConnectProtocolValidationContext() { ClientId = Options.ClientId, ProtocolMessage = openIdConnectMessage, ValidatedIdToken = jwt, Nonce = nonce }); // Authorization Code or Hybrid flow if (!string.IsNullOrWhiteSpace(openIdConnectMessage.Code)) { var tokenEndpointRequest = new OpenIdConnectMessage() { ClientId = Options.ClientId, ClientSecret = Options.ClientSecret, Code = openIdConnectMessage.Code, GrantType = OpenIdConnectGrantTypes.AuthorizationCode, RedirectUri = properties.Dictionary.ContainsKey(OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey) ? properties.Dictionary[OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey] : string.Empty }; // Run AuthorizationCodeReceived notification { var authorizationCodeReceivedNotification = new AuthorizationCodeReceivedNotification(Context, Options) { TokenEndpointRequest = tokenEndpointRequest, Code = openIdConnectMessage.Code, JwtSecurityToken = jwt, ProtocolMessage = openIdConnectMessage, RedirectUri = tokenEndpointRequest.RedirectUri, }; await Options.Notifications.AuthorizationCodeReceived(authorizationCodeReceivedNotification); if (authorizationCodeReceivedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (authorizationCodeReceivedNotification.Skipped) { return(null); } tokenEndpointRequest = authorizationCodeReceivedNotification.TokenEndpointRequest; openIdConnectMessage = authorizationCodeReceivedNotification.ProtocolMessage; } // Authorization Code flow - no Id Token was received if (ticket == null) { // Redeem token using the received authorization code tokenEndpointResponse = await RedeemAuthorizationCodeAsync(tokenEndpointRequest); // Run SecurityTokenReceived notification { var securityTokenReceivedNotification = new SecurityTokenReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { ProtocolMessage = tokenEndpointResponse, }; await Options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification); if (securityTokenReceivedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (securityTokenReceivedNotification.Skipped) { return(null); } } // Validate token // 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]. tvp.RequireSignedTokens = false; // At least a cursory validation is required on the new IdToken, even if we've already validated the one from the authorization response. // And we'll want to validate the new JWT in ValidateTokenResponse. principal = ValidateToken(tokenEndpointResponse.IdToken, properties, tvp, out tokenEndpointJwt); ticket = new AuthenticationTicket(principal.Identity as ClaimsIdentity, properties); nonce = tokenEndpointJwt.Payload.Nonce; if (String.IsNullOrWhiteSpace(nonce)) { nonce = ReadNonceCookie(nonce); } // Run SecurityTokenValidated notification { var securityTokenValidatedNotification = new SecurityTokenValidatedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { AuthenticationTicket = ticket, ProtocolMessage = tokenEndpointResponse, }; await Options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification); if (securityTokenValidatedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (securityTokenValidatedNotification.Skipped) { return(null); } // Flow possible changes ticket = securityTokenValidatedNotification.AuthenticationTicket; } } } if (Options.GetClaimsFromUserInfoEndpoint) { await GetUserInformationAsync( tokenEndpointResponse ?? openIdConnectMessage, tokenEndpointJwt ?? jwt, principal, properties); } 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.SourceException); // 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); }
private static Task MessageReceived(MessageReceivedNotification <HttpContext, OAuthBearerAuthenticationOptions> notification) { notification.Token = "CustomToken"; return(Task.FromResult <object>(null)); }
/// <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); }
/// <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 authorizationResponse = null; if (string.Equals(Request.Method, "GET", StringComparison.OrdinalIgnoreCase) && Request.Query.Any()) { 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)) { var invalidResponseEx = new OpenIdConnectProtocolException("An OpenID Connect response cannot contain an identity token or an access token when using response_mode=query"); _logger.WriteError("Exception occurred while processing message: ", invalidResponseEx); var authenticationFailedNotification = new AuthenticationFailedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { ProtocolMessage = authorizationResponse, Exception = invalidResponseEx }; await Options.Notifications.AuthenticationFailed(authenticationFailedNotification); if (authenticationFailedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (authenticationFailedNotification.Skipped) { return(null); } throw invalidResponseEx; } } // 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.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. authorizationResponse = new OpenIdConnectMessage(form); } if (authorizationResponse == null) { return(null); } ExceptionDispatchInfo authFailedEx = null; try { var messageReceivedNotification = new MessageReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { ProtocolMessage = authorizationResponse }; 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(authorizationResponse.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(authorizationResponse.Error)) { throw CreateOpenIdConnectProtocolException(authorizationResponse); } if (_configuration == null) { _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.Request.CallCancelled); } PopulateSessionProperties(authorizationResponse, properties); ClaimsPrincipal user = null; AuthenticationTicket ticket = null; JwtSecurityToken jwt = null; string nonce = null; // Copy and augment to avoid cross request race conditions for updated configurations. var validationParameters = Options.TokenValidationParameters.Clone(); // Hybrid or Implicit flow if (!string.IsNullOrEmpty(authorizationResponse.IdToken)) { var securityTokenReceivedNotification = new SecurityTokenReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { ProtocolMessage = authorizationResponse, }; await Options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification); if (securityTokenReceivedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (securityTokenReceivedNotification.Skipped) { return(null); } user = ValidateToken(authorizationResponse.IdToken, properties, validationParameters, out jwt); if (Options.ProtocolValidator.RequireNonce) { if (string.IsNullOrWhiteSpace(authorizationResponse.Nonce)) { authorizationResponse.Nonce = jwt.Payload.Nonce; } // deletes the nonce cookie nonce = RetrieveNonce(authorizationResponse); } ClaimsIdentity claimsIdentity = user.Identity as ClaimsIdentity; ticket = new AuthenticationTicket(claimsIdentity, properties); var securityTokenValidatedNotification = new SecurityTokenValidatedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { AuthenticationTicket = ticket, ProtocolMessage = authorizationResponse, }; await Options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification); if (securityTokenValidatedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (securityTokenValidatedNotification.Skipped) { return(null); } // Flow possible changes ticket = securityTokenValidatedNotification.AuthenticationTicket; } 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 tokenEndpointRequest = new OpenIdConnectMessage() { ClientId = Options.ClientId, ClientSecret = Options.ClientSecret, Code = authorizationResponse.Code, GrantType = OpenIdConnectGrantTypes.AuthorizationCode, RedirectUri = properties.Dictionary.ContainsKey(OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey) ? properties.Dictionary[OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey] : string.Empty, }; var authorizationCodeReceivedNotification = new AuthorizationCodeReceivedNotification(Context, Options) { AuthenticationTicket = ticket, Code = authorizationResponse.Code, JwtSecurityToken = jwt, ProtocolMessage = authorizationResponse, RedirectUri = tokenEndpointRequest.RedirectUri, TokenEndpointRequest = tokenEndpointRequest }; // PKCE https://tools.ietf.org/html/rfc7636#section-4.5 string codeVerifier; if (properties.Dictionary.TryGetValue(OAuthConstants.CodeVerifierKey, out codeVerifier)) { tokenEndpointRequest.Parameters.Add(OAuthConstants.CodeVerifierKey, codeVerifier); properties.Dictionary.Remove(OAuthConstants.CodeVerifierKey); } await Options.Notifications.AuthorizationCodeReceived(authorizationCodeReceivedNotification); if (authorizationCodeReceivedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (authorizationCodeReceivedNotification.Skipped) { return(null); } // Flow possible changes authorizationResponse = authorizationCodeReceivedNotification.ProtocolMessage; ticket = authorizationCodeReceivedNotification.AuthenticationTicket; tokenEndpointRequest = authorizationCodeReceivedNotification.TokenEndpointRequest; tokenEndpointResponse = authorizationCodeReceivedNotification.TokenEndpointResponse; jwt = authorizationCodeReceivedNotification.JwtSecurityToken; if (!authorizationCodeReceivedNotification.HandledCodeRedemption && Options.RedeemCode) { tokenEndpointResponse = await RedeemAuthorizationCodeAsync(tokenEndpointRequest); } if (tokenEndpointResponse != null) { var tokenResponseReceivedNotification = new TokenResponseReceivedNotification(Context, Options) { ProtocolMessage = authorizationResponse, TokenEndpointResponse = tokenEndpointResponse }; await Options.Notifications.TokenResponseReceived(tokenResponseReceivedNotification); if (tokenResponseReceivedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (tokenResponseReceivedNotification.Skipped) { return(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; // At least a cursory validation is required on the new IdToken, even if we've already validated the one from the authorization response. // And we'll want to validate the new JWT in ValidateTokenResponse. JwtSecurityToken tokenEndpointJwt = null; var tokenEndpointUser = ValidateToken(tokenEndpointResponse.IdToken, properties, validationParameters, out tokenEndpointJwt); // Avoid running the event, etc, if it was already done as part of the authorization response validation. if (user == null) { if (Options.ProtocolValidator.RequireNonce) { if (string.IsNullOrWhiteSpace(tokenEndpointResponse.Nonce)) { tokenEndpointResponse.Nonce = tokenEndpointJwt.Payload.Nonce; } // deletes the nonce cookie if (nonce == null) { nonce = RetrieveNonce(tokenEndpointResponse); } } ClaimsIdentity claimsIdentity = tokenEndpointUser.Identity as ClaimsIdentity; ticket = new AuthenticationTicket(claimsIdentity, properties); var securityTokenValidatedNotification = new SecurityTokenValidatedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { AuthenticationTicket = ticket, ProtocolMessage = tokenEndpointResponse, }; await Options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification); if (securityTokenValidatedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (securityTokenValidatedNotification.Skipped) { return(null); } // Flow possible changes ticket = securityTokenValidatedNotification.AuthenticationTicket; } else { if (!string.Equals(jwt.Subject, tokenEndpointJwt.Subject, StringComparison.Ordinal)) { throw new SecurityTokenException("The sub claim does not match in the id_token's from the authorization and token endpoints."); } } jwt = tokenEndpointJwt; } // Validate the token response if it wasn't provided manually if (!authorizationCodeReceivedNotification.HandledCodeRedemption && Options.RedeemCode) { Options.ProtocolValidator.ValidateTokenResponse(new OpenIdConnectProtocolValidationContext() { ClientId = Options.ClientId, ProtocolMessage = tokenEndpointResponse, ValidatedIdToken = jwt, Nonce = nonce }); } } if (Options.SaveTokens && ticket != null) { SaveTokens(ticket.Properties, tokenEndpointResponse ?? authorizationResponse); } 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.SourceException); // 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 = authorizationResponse, Exception = authFailedEx.SourceException }; await Options.Notifications.AuthenticationFailed(authenticationFailedNotification); if (authenticationFailedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (authenticationFailedNotification.Skipped) { return(null); } authFailedEx.Throw(); } return(null); }
/// <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 <AuthenticationTicket> HandleAuthenticateAsync() { string token = null; try { // Give application opportunity to find from a different location, adjust, or reject token var messageReceivedNotification = new MessageReceivedNotification <HttpContext, OAuthBearerAuthenticationOptions>(Context, Options) { ProtocolMessage = Context, }; // notification can set the token await Options.Notifications.MessageReceived(messageReceivedNotification); if (messageReceivedNotification.HandledResponse) { return(messageReceivedNotification.AuthenticationTicket); } if (messageReceivedNotification.Skipped) { return(null); } // If application retrieved token from somewhere else, use that. token = messageReceivedNotification.Token; if (string.IsNullOrEmpty(token)) { var authorization = Request.Headers.Get("Authorization"); // If no authorization header found, nothing to process further if (string.IsNullOrEmpty(authorization)) { return(null); } 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(null); } } // notify user token was received var securityTokenReceivedNotification = new SecurityTokenReceivedNotification <HttpContext, OAuthBearerAuthenticationOptions>(Context, Options) { ProtocolMessage = Context, SecurityToken = token, }; 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); } var validationParameters = Options.TokenValidationParameters.Clone(); if (_configuration != null) { if (validationParameters.ValidIssuer == null && !string.IsNullOrWhiteSpace(_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)); } SecurityToken validatedToken; foreach (var validator in Options.SecurityTokenValidators) { if (validator.CanReadToken(token)) { var principal = validator.ValidateToken(token, validationParameters, out validatedToken); var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Options.AuthenticationScheme); var securityTokenValidatedNotification = new SecurityTokenValidatedNotification <HttpContext, OAuthBearerAuthenticationOptions>(Context, Options) { ProtocolMessage = Context, AuthenticationTicket = ticket }; await Options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification); if (securityTokenValidatedNotification.HandledResponse) { return(securityTokenValidatedNotification.AuthenticationTicket); } if (securityTokenValidatedNotification.Skipped) { return(null); } return(ticket); } } throw new InvalidOperationException("No SecurityTokenValidator available for token: " + token ?? "null"); } catch (Exception ex) { Logger.LogError("Exception occurred while processing message", ex); // 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 && ex.GetType().Equals(typeof(SecurityTokenSignatureKeyNotFoundException))) { Options.ConfigurationManager.RequestRefresh(); } var authenticationFailedNotification = new AuthenticationFailedNotification <HttpContext, OAuthBearerAuthenticationOptions>(Context, Options) { ProtocolMessage = Context, Exception = ex }; await Options.Notifications.AuthenticationFailed(authenticationFailedNotification); if (authenticationFailedNotification.HandledResponse) { return(authenticationFailedNotification.AuthenticationTicket); } if (authenticationFailedNotification.Skipped) { return(null); } throw; } }
internal static async Task MessageReceived(MessageReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context) { Helpers.ThrowIfConditionFailed(() => context.ProtocolMessage != null, "ProtocolMessage is null."); notificationsFired.Add(nameof(MessageReceived)); await Task.FromResult(0); }
private Task OnMessageReceived(MessageReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> aArg) { return(Task.FromResult(0)); }
/// <summary> /// Invokes the login procedure (2nd leg of SP-Initiated login). Analagous to Saml20SignonHandler from ASP.Net DLL /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task <AuthenticationTicket> Invoke(IOwinContext context) { Logger.Debug(TraceMessages.SignOnHandlerCalled); ExceptionDispatchInfo authFailedEx = null; try { var messageReceivedNotification = new MessageReceivedNotification <SamlMessage, SamlAuthenticationOptions>(context, options) { ProtocolMessage = new SamlMessage(context, configuration, null) }; await options.Notifications.MessageReceived(messageReceivedNotification); if (messageReceivedNotification.HandledResponse) { return(null); // GetHandledResponseTicket() } if (messageReceivedNotification.Skipped) { return(null); } var requestParams = await HandleResponse(context); var assertion = context.Get <Saml20Assertion>("Saml2:assertion"); var securityTokenReceivedNotification = new SecurityTokenReceivedNotification <SamlMessage, SamlAuthenticationOptions>(context, options) { ProtocolMessage = new SamlMessage(context, configuration, assertion) }; await options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification); if (securityTokenReceivedNotification.HandledResponse) { return(null); // GetHandledResponseTicket(); } if (securityTokenReceivedNotification.Skipped) { return(null); } var ticket = await GetAuthenticationTicket(context, requestParams); var securityTokenValidatedNotification = new SecurityTokenValidatedNotification <SamlMessage, SamlAuthenticationOptions>(context, options) { AuthenticationTicket = ticket, ProtocolMessage = new SamlMessage(context, configuration, assertion) }; await options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification); if (securityTokenValidatedNotification.HandledResponse) { return(null); // GetHandledResponseTicket(); } if (securityTokenValidatedNotification.Skipped) { return(null); // null; } // Flow possible changes ticket = securityTokenValidatedNotification.AuthenticationTicket; context.Authentication.AuthenticationResponseGrant = new AuthenticationResponseGrant(ticket.Identity, ticket.Properties); return(ticket); } catch (Exception ex) { authFailedEx = ExceptionDispatchInfo.Capture(ex); } if (authFailedEx != null) { Logger.Error("Exception occurred while processing message: " + authFailedEx.SourceException); var message = new SamlMessage(context, configuration, context.Get <Saml20Assertion>("Saml2:assertion")); var authenticationFailedNotification = new AuthenticationFailedNotification <SamlMessage, SamlAuthenticationOptions>(context, options) { ProtocolMessage = message, Exception = authFailedEx.SourceException }; await options.Notifications.AuthenticationFailed(authenticationFailedNotification); if (authenticationFailedNotification.HandledResponse) { return(null);//GetHandledResponseTicket(); } if (authenticationFailedNotification.Skipped) { return(null); //null } authFailedEx.Throw(); } return(null); }
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; }