private void CurrentPluginFailed(ExceptionDispatchInfo e) { var plugin = _currentMainWindow.Plugin.GetType(); _currentMainWindow.BeginHide(); TrayIconManager.GetInstance().ShowNotification("", $"Failed to preview {Path.GetFileName(_path)}", true); Debug.WriteLine(e.ToString()); Debug.WriteLine(e.SourceException.StackTrace); if (plugin != PluginManager.GetInstance().DefaultPlugin.GetType()) { BeginShowNewWindow(PluginManager.GetInstance().DefaultPlugin); } else { e.Throw(); } }
/// <summary> /// Invoked to process incoming authentication messages. /// </summary> /// <returns>An <see cref="AuthenticationTicket"/> if successful.</returns> protected override async Task <AuthenticationTicket> AuthenticateCoreAsync() { // Allow login to be constrained to a specific path. Need to make this runtime configurable. if (Options.CallbackPath.HasValue && Options.CallbackPath != (Request.PathBase + Request.Path)) { return(null); } OpenIdConnectMessage openIdConnectMessage = null; // assumption: if the ContentType is "application/x-www-form-urlencoded" it should be safe to read as it is small. if (string.Equals(Request.Method, "POST", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(Request.ContentType) // May have media/type; charset=utf-8, allow partial match. && Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase) && Request.Body.CanRead) { if (!Request.Body.CanSeek) { _logger.WriteVerbose("Buffering request body"); // Buffer in case this body was not meant for us. MemoryStream memoryStream = new MemoryStream(); await Request.Body.CopyToAsync(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); Request.Body = memoryStream; } IFormCollection form = await Request.ReadFormAsync(); Request.Body.Seek(0, SeekOrigin.Begin); // TODO: a delegate on OpenIdConnectAuthenticationOptions would allow for users to hook their own custom message. openIdConnectMessage = new OpenIdConnectMessage(form); } if (openIdConnectMessage == null) { return(null); } ExceptionDispatchInfo authFailedEx = null; try { var messageReceivedNotification = new MessageReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { ProtocolMessage = openIdConnectMessage }; await Options.Notifications.MessageReceived(messageReceivedNotification); if (messageReceivedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (messageReceivedNotification.Skipped) { return(null); } // runtime always adds state, if we don't find it OR we failed to 'unprotect' it this is not a message we // should process. AuthenticationProperties properties = GetPropertiesFromState(openIdConnectMessage.State); if (properties == null) { _logger.WriteWarning("The state field is missing or invalid."); return(null); } // devs will need to hook AuthenticationFailedNotification to avoid having 'raw' runtime errors displayed to users. if (!string.IsNullOrWhiteSpace(openIdConnectMessage.Error)) { throw new OpenIdConnectProtocolException( string.Format(CultureInfo.InvariantCulture, openIdConnectMessage.Error, Resources.Exception_OpenIdConnectMessageError, openIdConnectMessage.ErrorDescription ?? string.Empty, openIdConnectMessage.ErrorUri ?? string.Empty)); } // code is only accepted with id_token, in this version, hence check for code is inside this if // OpenIdConnect protocol allows a Code to be received without the id_token if (string.IsNullOrWhiteSpace(openIdConnectMessage.IdToken)) { _logger.WriteWarning("The id_token is missing."); return(null); } var securityTokenReceivedNotification = new SecurityTokenReceivedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { ProtocolMessage = openIdConnectMessage, }; await Options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification); if (securityTokenReceivedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (securityTokenReceivedNotification.Skipped) { return(null); } if (_configuration == null) { _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.Request.CallCancelled); } // Copy and augment to avoid cross request race conditions for updated configurations. TokenValidationParameters tvp = Options.TokenValidationParameters.Clone(); IEnumerable <string> issuers = new[] { _configuration.Issuer }; tvp.ValidIssuers = (tvp.ValidIssuers == null ? issuers : tvp.ValidIssuers.Concat(issuers)); tvp.IssuerSigningTokens = (tvp.IssuerSigningTokens == null ? _configuration.SigningTokens : tvp.IssuerSigningTokens.Concat(_configuration.SigningTokens)); SecurityToken validatedToken; ClaimsPrincipal principal = Options.SecurityTokenHandlers.ValidateToken(openIdConnectMessage.IdToken, tvp, out validatedToken); ClaimsIdentity claimsIdentity = principal.Identity as ClaimsIdentity; // claims principal could have changed claim values, use bits received on wire for validation. JwtSecurityToken jwt = validatedToken as JwtSecurityToken; AuthenticationTicket ticket = new AuthenticationTicket(claimsIdentity, properties); string nonce = null; if (Options.ProtocolValidator.RequireNonce) { if (String.IsNullOrWhiteSpace(openIdConnectMessage.Nonce)) { openIdConnectMessage.Nonce = jwt.Payload.Nonce; } // deletes the nonce cookie nonce = RetrieveNonce(openIdConnectMessage); } // remember 'session_state' and 'check_session_iframe' if (!string.IsNullOrWhiteSpace(openIdConnectMessage.SessionState)) { ticket.Properties.Dictionary[OpenIdConnectSessionProperties.SessionState] = openIdConnectMessage.SessionState; } if (!string.IsNullOrWhiteSpace(_configuration.CheckSessionIframe)) { ticket.Properties.Dictionary[OpenIdConnectSessionProperties.CheckSessionIFrame] = _configuration.CheckSessionIframe; } if (Options.UseTokenLifetime) { // Override any session persistence to match the token lifetime. DateTime issued = jwt.ValidFrom; if (issued != DateTime.MinValue) { ticket.Properties.IssuedUtc = issued.ToUniversalTime(); } DateTime expires = jwt.ValidTo; if (expires != DateTime.MinValue) { ticket.Properties.ExpiresUtc = expires.ToUniversalTime(); } ticket.Properties.AllowRefresh = false; } var securityTokenValidatedNotification = new SecurityTokenValidatedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { AuthenticationTicket = ticket, ProtocolMessage = openIdConnectMessage, }; await Options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification); if (securityTokenValidatedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (securityTokenValidatedNotification.Skipped) { return(null); } // Flow possible changes ticket = securityTokenValidatedNotification.AuthenticationTicket; var protocolValidationContext = new OpenIdConnectProtocolValidationContext { AuthorizationCode = openIdConnectMessage.Code, Nonce = nonce, }; Options.ProtocolValidator.Validate(jwt, protocolValidationContext); if (openIdConnectMessage.Code != null) { var authorizationCodeReceivedNotification = new AuthorizationCodeReceivedNotification(Context, Options) { AuthenticationTicket = ticket, Code = openIdConnectMessage.Code, JwtSecurityToken = jwt, ProtocolMessage = openIdConnectMessage, RedirectUri = ticket.Properties.Dictionary.ContainsKey(OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey) ? ticket.Properties.Dictionary[OpenIdConnectAuthenticationDefaults.RedirectUriUsedForCodeKey] : string.Empty, }; await Options.Notifications.AuthorizationCodeReceived(authorizationCodeReceivedNotification); if (authorizationCodeReceivedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (authorizationCodeReceivedNotification.Skipped) { return(null); } // Flow possible changes ticket = authorizationCodeReceivedNotification.AuthenticationTicket; } return(ticket); } catch (Exception exception) { // We can't await inside a catch block, capture and handle outside. authFailedEx = ExceptionDispatchInfo.Capture(exception); } if (authFailedEx != null) { _logger.WriteError("Exception occurred while processing message: '" + authFailedEx.ToString()); // Refresh the configuration for exceptions that may be caused by key rollovers. The user can also request a refresh in the notification. if (Options.RefreshOnIssuerKeyNotFound && authFailedEx.SourceException.GetType().Equals(typeof(SecurityTokenSignatureKeyNotFoundException))) { Options.ConfigurationManager.RequestRefresh(); } var authenticationFailedNotification = new AuthenticationFailedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>(Context, Options) { ProtocolMessage = openIdConnectMessage, Exception = authFailedEx.SourceException }; await Options.Notifications.AuthenticationFailed(authenticationFailedNotification); if (authenticationFailedNotification.HandledResponse) { return(GetHandledResponseTicket()); } if (authenticationFailedNotification.Skipped) { return(null); } authFailedEx.Throw(); } return(null); }
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); }