Browse Source

Catch exceptions thrown during the retrieval of the remote server configuration and generalize the use of OpenIddictHelpers.IsFatal()

pull/1755/head
Kévin Chalet 3 years ago
parent
commit
3bdfc20895
  1. 18
      shared/OpenIddict.Extensions/Helpers/OpenIddictHelpers.cs
  2. 6
      src/OpenIddict.Abstractions/OpenIddictResources.resx
  3. 3
      src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.cs
  4. 4
      src/OpenIddict.Client.DataProtection/OpenIddict.Client.DataProtection.csproj
  5. 3
      src/OpenIddict.Client.DataProtection/OpenIddictClientDataProtectionHandlers.Protection.cs
  6. 5
      src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.cs
  7. 3
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
  8. 2
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHttpListener.cs
  9. 4
      src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs
  10. 3
      src/OpenIddict.Client/OpenIddictClientDispatcher.cs
  11. 104
      src/OpenIddict.Client/OpenIddictClientHandlers.cs
  12. 2
      src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
  13. 2
      src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
  14. 6
      src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
  15. 3
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkApplicationStore.cs
  16. 6
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs
  17. 5
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs
  18. 3
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs
  19. 6
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs
  20. 5
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs
  21. 4
      src/OpenIddict.Quartz/OpenIddict.Quartz.csproj
  22. 29
      src/OpenIddict.Quartz/OpenIddictQuartzJob.cs
  23. 3
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
  24. 4
      src/OpenIddict.Server.DataProtection/OpenIddict.Server.DataProtection.csproj
  25. 3
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.Protection.cs
  26. 5
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
  27. 3
      src/OpenIddict.Server/OpenIddictServerDispatcher.cs
  28. 4
      src/OpenIddict.Validation.DataProtection/OpenIddict.Validation.DataProtection.csproj
  29. 3
      src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionHandlers.Protection.cs
  30. 4
      src/OpenIddict.Validation.Owin/OpenIddict.Validation.Owin.csproj
  31. 3
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs
  32. 4
      src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs
  33. 3
      src/OpenIddict.Validation/OpenIddictValidationDispatcher.cs
  34. 26
      src/OpenIddict.Validation/OpenIddictValidationHandlers.cs
  35. 57
      test/OpenIddict.Validation.IntegrationTests/OpenIddictValidationIntegrationTests.cs

18
shared/OpenIddict.Extensions/Helpers/OpenIddictHelpers.cs

@ -1,4 +1,5 @@
using System.Data;
using System.Collections.ObjectModel;
using System.Data;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
@ -144,11 +145,24 @@ internal static class OpenIddictHelpers
ThreadAbortException => true,
OutOfMemoryException and not InsufficientMemoryException => true,
AggregateException { InnerExceptions: var exceptions } => exceptions.Any(IsFatal),
AggregateException { InnerExceptions: var exceptions } => IsAnyFatal(exceptions),
Exception { InnerException: Exception inner } => IsFatal(inner),
_ => false
};
static bool IsAnyFatal(ReadOnlyCollection<Exception> exceptions)
{
for (var index = 0; index < exceptions.Count; index++)
{
if (IsFatal(exceptions[index]))
{
return true;
}
}
return false;
}
}
#if !SUPPORTS_TOHASHSET_LINQ_EXTENSION

6
src/OpenIddict.Abstractions/OpenIddictResources.resx

@ -2026,6 +2026,9 @@ To apply post-logout redirection responses, create a class implementing 'IOpenId
<data name="ID2169" xml:space="preserve">
<value>The '{0}' parameter returned in the device authorization response is not valid absolute URI.</value>
</data>
<data name="ID2170" xml:space="preserve">
<value>The remote authorization server is currently unavailable or returned an invalid configuration.</value>
</data>
<data name="ID4000" xml:space="preserve">
<value>The '{0}' parameter shouldn't be null or empty at this point.</value>
</data>
@ -2704,6 +2707,9 @@ This may indicate that the hashed entry is corrupted or malformed.</value>
<data name="ID6218" xml:space="preserve">
<value>The device authorization response returned by {Uri} was successfully extracted: {Response}.</value>
</data>
<data name="ID6219" xml:space="preserve">
<value>An error occurred while retrieving the configuration of the remote authorization server.</value>
</data>
<data name="ID8000" xml:space="preserve">
<value>https://documentation.openiddict.com/errors/{0}</value>
</data>

3
src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.cs

@ -18,6 +18,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Net.Http.Headers;
using OpenIddict.Extensions;
using Properties = OpenIddict.Client.AspNetCore.OpenIddictClientAspNetCoreConstants.Properties;
#if SUPPORTS_JSON_NODES
@ -469,7 +470,7 @@ public static partial class OpenIddictClientAspNetCoreHandlers
context.RequestForgeryProtection = Encoding.UTF8.GetString(payload, index: 5, length);
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
context.Reject(
error: Errors.InvalidRequest,

4
src/OpenIddict.Client.DataProtection/OpenIddict.Client.DataProtection.csproj

@ -32,6 +32,10 @@
<PackageReference Include="Microsoft.AspNetCore.DataProtection" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\shared\OpenIddict.Extensions\*\*.cs" />
</ItemGroup>
<ItemGroup>
<Using Include="OpenIddict.Abstractions" />
<Using Include="OpenIddict.Abstractions.OpenIddictConstants" Static="true" />

3
src/OpenIddict.Client.DataProtection/OpenIddictClientDataProtectionHandlers.Protection.cs

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Extensions;
using static OpenIddict.Client.DataProtection.OpenIddictClientDataProtectionConstants.Purposes;
using static OpenIddict.Client.OpenIddictClientHandlers.Protection;
using Schemes = OpenIddict.Client.DataProtection.OpenIddictClientDataProtectionConstants.Purposes.Schemes;
@ -124,7 +125,7 @@ public static partial class OpenIddictClientDataProtectionHandlers
return _options.CurrentValue.Formatter.ReadToken(reader)?.SetTokenType(type);
}
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
context.Logger.LogTrace(exception, SR.GetResourceString(SR.ID6153), context.Token);

5
src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.cs

@ -15,6 +15,7 @@ using System.Text.Json;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Extensions;
using Owin;
using static OpenIddict.Client.Owin.OpenIddictClientOwinConstants;
using Properties = OpenIddict.Client.Owin.OpenIddictClientOwinConstants.Properties;
@ -472,7 +473,7 @@ public static partial class OpenIddictClientOwinHandlers
context.RequestForgeryProtection = Encoding.UTF8.GetString(payload, index: 5, length);
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
context.Reject(
error: Errors.InvalidRequest,
@ -1237,7 +1238,7 @@ public static partial class OpenIddictClientOwinHandlers
context.Response.SuppressFormsAuthenticationRedirect = true;
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
}
}

3
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs

@ -11,6 +11,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Principal;
using OpenIddict.Extensions;
#if SUPPORTS_WINDOWS_RUNTIME
using Windows.ApplicationModel.Activation;
@ -163,7 +164,7 @@ public static class OpenIddictClientSystemIntegrationHelpers
ProtocolActivatedEventArgs args ? args.Uri : null;
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
return null;
}

2
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHttpListener.cs

@ -195,7 +195,7 @@ public sealed class OpenIddictClientSystemIntegrationHttpListener : BackgroundSe
exceptions.Push(new InvalidOperationException(SR.FormatID0384(port), exception));
}
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
listener.Close();

4
src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs

@ -448,7 +448,7 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
// If an exception is thrown at this stage, this likely means a persistent network error occurred.
// In this case, log the error details and return a generic error to stop processing the event.
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
context.Logger.LogError(exception, SR.GetResourceString(SR.ID6182));
@ -698,7 +698,7 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
// If an exception is thrown at this stage, this likely means the returned response was not a valid
// JSON response or was not correctly formatted as a JSON object. This typically happens when
// a server error occurs while the JSON response is being generated and returned to the client.
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
context.Logger.LogError(exception, SR.GetResourceString(SR.ID6183),
await response.Content.ReadAsStringAsync());

3
src/OpenIddict.Client/OpenIddictClientDispatcher.cs

@ -7,6 +7,7 @@
using System.ComponentModel;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenIddict.Extensions;
namespace OpenIddict.Client;
@ -48,7 +49,7 @@ public sealed class OpenIddictClientDispatcher : IOpenIddictClientDispatcher
await handler.HandleAsync(context);
}
catch (Exception exception) when (_logger.IsEnabled(LogLevel.Debug))
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) && _logger.IsEnabled(LogLevel.Debug))
{
_logger.LogDebug(exception, SR.GetResourceString(SR.ID6132), handler.GetType().FullName, typeof(TContext).FullName);

104
src/OpenIddict.Client/OpenIddictClientHandlers.cs

@ -386,11 +386,27 @@ public static partial class OpenIddictClientHandlers
// be used to authenticate users. In this case, throw an exception to abort the flow.
context.Registration ??= await _service.GetClientRegistrationAsync(context.Issuer, context.CancellationToken);
// Resolve and attach the server configuration to the context if none has been set already.
context.Configuration ??= await context.Registration.ConfigurationManager
.GetConfigurationAsync(context.CancellationToken)
.WaitAsync(context.CancellationToken) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
try
{
// Resolve and attach the server configuration to the context if none has been set already.
context.Configuration ??= await context.Registration.ConfigurationManager
.GetConfigurationAsync(context.CancellationToken)
.WaitAsync(context.CancellationToken) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) &&
exception is not OperationCanceledException)
{
context.Logger.LogError(exception, SR.GetResourceString(SR.ID6219));
context.Reject(
error: Errors.ServerError,
description: SR.GetResourceString(SR.ID2170),
uri: SR.FormatID8000(SR.ID2170));
return;
}
// Ensure the selected grant type, if explicitly set, is listed as supported in the configuration.
if (!string.IsNullOrEmpty(context.GrantType) &&
@ -982,11 +998,27 @@ public static partial class OpenIddictClientHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0349));
}
// Resolve and attach the server configuration to the context.
context.Configuration = await context.Registration.ConfigurationManager
.GetConfigurationAsync(context.CancellationToken)
.WaitAsync(context.CancellationToken) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
try
{
// Resolve and attach the server configuration to the context.
context.Configuration = await context.Registration.ConfigurationManager
.GetConfigurationAsync(context.CancellationToken)
.WaitAsync(context.CancellationToken) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) &&
exception is not OperationCanceledException)
{
context.Logger.LogError(exception, SR.GetResourceString(SR.ID6219));
context.Reject(
error: Errors.ServerError,
description: SR.GetResourceString(SR.ID2170),
uri: SR.FormatID8000(SR.ID2170));
return;
}
}
}
@ -3944,11 +3976,27 @@ public static partial class OpenIddictClientHandlers
// be used to authenticate users. In this case, throw an exception to abort the flow.
context.Registration ??= await _service.GetClientRegistrationAsync(context.Issuer, context.CancellationToken);
// Resolve and attach the server configuration to the context if none has been set already.
context.Configuration ??= await context.Registration.ConfigurationManager
.GetConfigurationAsync(context.CancellationToken)
.WaitAsync(context.CancellationToken) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
try
{
// Resolve and attach the server configuration to the context if none has been set already.
context.Configuration ??= await context.Registration.ConfigurationManager
.GetConfigurationAsync(context.CancellationToken)
.WaitAsync(context.CancellationToken) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) &&
exception is not OperationCanceledException)
{
context.Logger.LogError(exception, SR.GetResourceString(SR.ID6219));
context.Reject(
error: Errors.ServerError,
description: SR.GetResourceString(SR.ID2170),
uri: SR.FormatID8000(SR.ID2170));
return;
}
}
}
@ -5532,11 +5580,27 @@ public static partial class OpenIddictClientHandlers
// be used to authenticate users. In this case, throw an exception to abort the flow.
context.Registration ??= await _service.GetClientRegistrationAsync(context.Issuer, context.CancellationToken);
// Resolve and attach the server configuration to the context if none has been set already.
context.Configuration ??= await context.Registration.ConfigurationManager
.GetConfigurationAsync(context.CancellationToken)
.WaitAsync(context.CancellationToken) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
try
{
// Resolve and attach the server configuration to the context if none has been set already.
context.Configuration ??= await context.Registration.ConfigurationManager
.GetConfigurationAsync(context.CancellationToken)
.WaitAsync(context.CancellationToken) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) &&
exception is not OperationCanceledException)
{
context.Logger.LogError(exception, SR.GetResourceString(SR.ID6219));
context.Reject(
error: Errors.ServerError,
description: SR.GetResourceString(SR.ID2170),
uri: SR.FormatID8000(SR.ID2170));
return;
}
}
}

2
src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs

@ -1452,7 +1452,7 @@ public class OpenIddictApplicationManager<TApplication> : IOpenIddictApplication
return new(VerifyHashedSecret(comparand, secret));
}
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
Logger.LogWarning(exception, SR.GetResourceString(SR.ID6163));

2
src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs

@ -1063,7 +1063,7 @@ public class OpenIddictAuthorizationManager<TAuthorization> : IOpenIddictAuthori
return false;
}
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
Logger.LogWarning(exception, SR.GetResourceString(SR.ID6166), await Store.GetIdAsync(authorization, cancellationToken));

6
src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs

@ -1094,7 +1094,7 @@ public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TTok
return false;
}
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
Logger.LogWarning(exception, SR.GetResourceString(SR.ID6170), await Store.GetIdAsync(token, cancellationToken));
@ -1133,7 +1133,7 @@ public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TTok
return false;
}
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
Logger.LogWarning(exception, SR.GetResourceString(SR.ID6173), await Store.GetIdAsync(token, cancellationToken));
@ -1172,7 +1172,7 @@ public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TTok
return false;
}
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
Logger.LogWarning(exception, SR.GetResourceString(SR.ID6176), await Store.GetIdAsync(token, cancellationToken));

3
src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkApplicationStore.cs

@ -17,6 +17,7 @@ using System.Text.Json;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using OpenIddict.EntityFramework.Models;
using OpenIddict.Extensions;
using static OpenIddict.Abstractions.OpenIddictExceptions;
namespace OpenIddict.EntityFramework;
@ -138,7 +139,7 @@ public class OpenIddictEntityFrameworkApplicationStore<TApplication, TAuthorizat
return Context.Database.BeginTransaction(IsolationLevel.Serializable);
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
return null;
}

6
src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs

@ -137,7 +137,7 @@ public class OpenIddictEntityFrameworkAuthorizationStore<TAuthorization, TApplic
return Context.Database.BeginTransaction(IsolationLevel.Serializable);
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
return null;
}
@ -609,7 +609,7 @@ public class OpenIddictEntityFrameworkAuthorizationStore<TAuthorization, TApplic
return Context.Database.BeginTransaction(IsolationLevel.RepeatableRead);
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
return null;
}
@ -658,7 +658,7 @@ public class OpenIddictEntityFrameworkAuthorizationStore<TAuthorization, TApplic
transaction?.Commit();
}
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
exceptions ??= new List<Exception>(capacity: 1);
exceptions.Add(exception);

5
src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs

@ -14,6 +14,7 @@ using System.Text.Json;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using OpenIddict.EntityFramework.Models;
using OpenIddict.Extensions;
using static OpenIddict.Abstractions.OpenIddictExceptions;
namespace OpenIddict.EntityFramework;
@ -591,7 +592,7 @@ public class OpenIddictEntityFrameworkTokenStore<TToken, TApplication, TAuthoriz
return Context.Database.BeginTransaction(IsolationLevel.RepeatableRead);
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
return null;
}
@ -637,7 +638,7 @@ public class OpenIddictEntityFrameworkTokenStore<TToken, TApplication, TAuthoriz
transaction?.Commit();
}
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
exceptions ??= new List<Exception>(capacity: 1);
exceptions.Add(exception);

3
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs

@ -16,6 +16,7 @@ using System.Text.Json;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using OpenIddict.EntityFrameworkCore.Models;
using OpenIddict.Extensions;
using static OpenIddict.Abstractions.OpenIddictExceptions;
namespace OpenIddict.EntityFrameworkCore;
@ -165,7 +166,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore<TApplication, TAuthor
return await Context.Database.BeginTransactionAsync(IsolationLevel.Serializable, cancellationToken);
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
return null;
}

6
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs

@ -164,7 +164,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
return await Context.Database.BeginTransactionAsync(IsolationLevel.Serializable, cancellationToken);
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
return null;
}
@ -684,7 +684,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
return await Context.Database.BeginTransactionAsync(IsolationLevel.RepeatableRead, cancellationToken);
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
return null;
}
@ -736,7 +736,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
transaction?.Commit();
}
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
exceptions ??= new List<Exception>(capacity: 1);
exceptions.Add(exception);

5
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs

@ -13,6 +13,7 @@ using System.Text.Json;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using OpenIddict.EntityFrameworkCore.Models;
using OpenIddict.Extensions;
using static OpenIddict.Abstractions.OpenIddictExceptions;
namespace OpenIddict.EntityFrameworkCore;
@ -648,7 +649,7 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
return await Context.Database.BeginTransactionAsync(IsolationLevel.RepeatableRead, cancellationToken);
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
return null;
}
@ -697,7 +698,7 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
transaction?.Commit();
}
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
exceptions ??= new List<Exception>(capacity: 1);
exceptions.Add(exception);

4
src/OpenIddict.Quartz/OpenIddict.Quartz.csproj

@ -24,6 +24,10 @@
<PackageReference Include="Quartz.Extensions.DependencyInjection" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\shared\OpenIddict.Extensions\*\*.cs" />
</ItemGroup>
<ItemGroup>
<Using Include="OpenIddict.Abstractions" />
<Using Include="OpenIddict.Abstractions.OpenIddictConstants" Static="true" />

29
src/OpenIddict.Quartz/OpenIddictQuartzJob.cs

@ -7,6 +7,7 @@
using System.ComponentModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenIddict.Extensions;
namespace OpenIddict.Quartz;
@ -86,16 +87,10 @@ public sealed class OpenIddictQuartzJob : IJob
await manager.PruneAsync(threshold, context.CancellationToken);
}
// OutOfMemoryExceptions are treated as fatal errors and are always re-thrown as-is.
catch (OutOfMemoryException)
{
throw;
}
// OperationCanceledExceptions are typically thrown when the host is about to shut down.
// To allow the host to shut down as fast as possible, this exception type is special-cased
// to prevent further processing in this job and inform Quartz.NET it shouldn't be refired.
catch (OperationCanceledException exception) when (exception.CancellationToken == context.CancellationToken)
catch (OperationCanceledException exception) when (context.CancellationToken.IsCancellationRequested)
{
throw new JobExecutionException(exception)
{
@ -105,15 +100,15 @@ public sealed class OpenIddictQuartzJob : IJob
// AggregateExceptions are generally thrown by the manager itself when one or multiple exception(s)
// occurred while trying to prune the entities. In this case, add the inner exceptions to the collection.
catch (AggregateException exception)
catch (AggregateException exception) when (!OpenIddictHelpers.IsFatal(exception))
{
exceptions ??= new List<Exception>(capacity: exception.InnerExceptions.Count);
exceptions.AddRange(exception.InnerExceptions);
}
// Other exceptions are assumed to be transient and are added to the exceptions collection
// Other non-fatal exceptions are assumed to be transient and are added to the exceptions collection
// to be re-thrown later (typically, at the very end of this job, as an AggregateException).
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
exceptions ??= new List<Exception>(capacity: 1);
exceptions.Add(exception);
@ -143,16 +138,10 @@ public sealed class OpenIddictQuartzJob : IJob
await manager.PruneAsync(threshold, context.CancellationToken);
}
// OutOfMemoryExceptions are treated as fatal errors and are always re-thrown as-is.
catch (OutOfMemoryException)
{
throw;
}
// OperationCanceledExceptions are typically thrown when the host is about to shut down.
// To allow the host to shut down as fast as possible, this exception type is special-cased
// to prevent further processing in this job and inform Quartz.NET it shouldn't be refired.
catch (OperationCanceledException exception) when (exception.CancellationToken == context.CancellationToken)
catch (OperationCanceledException exception) when (context.CancellationToken.IsCancellationRequested)
{
throw new JobExecutionException(exception)
{
@ -162,15 +151,15 @@ public sealed class OpenIddictQuartzJob : IJob
// AggregateExceptions are generally thrown by the manager itself when one or multiple exception(s)
// occurred while trying to prune the entities. In this case, add the inner exceptions to the collection.
catch (AggregateException exception)
catch (AggregateException exception) when (!OpenIddictHelpers.IsFatal(exception))
{
exceptions ??= new List<Exception>(capacity: exception.InnerExceptions.Count);
exceptions.AddRange(exception.InnerExceptions);
}
// Other exceptions are assumed to be transient and are added to the exceptions collection
// Other non-fatal exceptions are assumed to be transient and are added to the exceptions collection
// to be re-thrown later (typically, at the very end of this job, as an AggregateException).
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
exceptions ??= new List<Exception>(capacity: 1);
exceptions.Add(exception);

3
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs

@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using OpenIddict.Extensions;
using Properties = OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreConstants.Properties;
#if SUPPORTS_JSON_NODES
@ -718,7 +719,7 @@ public static partial class OpenIddictServerAspNetCoreHandlers
return default;
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
context.Reject(
error: Errors.InvalidRequest,

4
src/OpenIddict.Server.DataProtection/OpenIddict.Server.DataProtection.csproj

@ -32,6 +32,10 @@
<PackageReference Include="Microsoft.AspNetCore.DataProtection" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\shared\OpenIddict.Extensions\*\*.cs" />
</ItemGroup>
<ItemGroup>
<Using Include="OpenIddict.Abstractions" />
<Using Include="OpenIddict.Abstractions.OpenIddictConstants" Static="true" />

3
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.Protection.cs

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Extensions;
using static OpenIddict.Server.DataProtection.OpenIddictServerDataProtectionConstants.Purposes;
using static OpenIddict.Server.OpenIddictServerHandlers.Protection;
using Schemes = OpenIddict.Server.DataProtection.OpenIddictServerDataProtectionConstants.Purposes.Schemes;
@ -229,7 +230,7 @@ public static partial class OpenIddictServerDataProtectionHandlers
return _options.CurrentValue.Formatter.ReadToken(reader)?.SetTokenType(type);
}
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
context.Logger.LogTrace(exception, SR.GetResourceString(SR.ID6153), context.Token);

5
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs

@ -13,6 +13,7 @@ using System.Text.Encodings.Web;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenIddict.Extensions;
using Owin;
using static OpenIddict.Server.Owin.OpenIddictServerOwinConstants;
using Properties = OpenIddict.Server.Owin.OpenIddictServerOwinConstants.Properties;
@ -771,7 +772,7 @@ public static partial class OpenIddictServerOwinHandlers
return default;
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
context.Reject(
error: Errors.InvalidRequest,
@ -1046,7 +1047,7 @@ public static partial class OpenIddictServerOwinHandlers
context.Response.SuppressFormsAuthenticationRedirect = true;
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
}
}

3
src/OpenIddict.Server/OpenIddictServerDispatcher.cs

@ -7,6 +7,7 @@
using System.ComponentModel;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenIddict.Extensions;
namespace OpenIddict.Server;
@ -48,7 +49,7 @@ public sealed class OpenIddictServerDispatcher : IOpenIddictServerDispatcher
await handler.HandleAsync(context);
}
catch (Exception exception) when (_logger.IsEnabled(LogLevel.Debug))
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) && _logger.IsEnabled(LogLevel.Debug))
{
_logger.LogDebug(exception, SR.GetResourceString(SR.ID6132), handler.GetType().FullName, typeof(TContext).FullName);

4
src/OpenIddict.Validation.DataProtection/OpenIddict.Validation.DataProtection.csproj

@ -32,6 +32,10 @@
<PackageReference Include="Microsoft.AspNetCore.DataProtection" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\shared\OpenIddict.Extensions\*\*.cs" />
</ItemGroup>
<ItemGroup>
<Using Include="OpenIddict.Abstractions" />
<Using Include="OpenIddict.Abstractions.OpenIddictConstants" Static="true" />

3
src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionHandlers.Protection.cs

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Extensions;
using static OpenIddict.Validation.DataProtection.OpenIddictValidationDataProtectionConstants.Purposes;
using static OpenIddict.Validation.OpenIddictValidationHandlers.Protection;
using Schemes = OpenIddict.Validation.DataProtection.OpenIddictValidationDataProtectionConstants.Purposes.Schemes;
@ -118,7 +119,7 @@ public static partial class OpenIddictValidationDataProtectionHandlers
return _options.CurrentValue.Formatter.ReadToken(reader)?.SetTokenType(type);
}
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
context.Logger.LogTrace(exception, SR.GetResourceString(SR.ID6153), context.Token);

4
src/OpenIddict.Validation.Owin/OpenIddict.Validation.Owin.csproj

@ -18,6 +18,10 @@
<PackageReference Include="Microsoft.Owin.Security" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\shared\OpenIddict.Extensions\*\*.cs" />
</ItemGroup>
<ItemGroup>
<Using Include="Microsoft.Owin" />
<Using Include="Microsoft.Owin.Infrastructure" />

3
src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs

@ -12,6 +12,7 @@ using System.Text;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenIddict.Extensions;
using Owin;
using static OpenIddict.Validation.Owin.OpenIddictValidationOwinConstants;
using Properties = OpenIddict.Validation.Owin.OpenIddictValidationOwinConstants.Properties;
@ -605,7 +606,7 @@ public static partial class OpenIddictValidationOwinHandlers
context.Response.SuppressFormsAuthenticationRedirect = true;
}
catch
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
}
}

4
src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs

@ -446,7 +446,7 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers
// If an exception is thrown at this stage, this likely means a persistent network error occurred.
// In this case, log the error details and return a generic error to stop processing the event.
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
context.Logger.LogError(exception, SR.GetResourceString(SR.ID6182));
@ -696,7 +696,7 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers
// If an exception is thrown at this stage, this likely means the returned response was not a valid
// JSON response or was not correctly formatted as a JSON object. This typically happens when
// a server error occurs while the JSON response is being generated and returned to the client.
catch (Exception exception)
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
context.Logger.LogError(exception, SR.GetResourceString(SR.ID6183),
await response.Content.ReadAsStringAsync());

3
src/OpenIddict.Validation/OpenIddictValidationDispatcher.cs

@ -7,6 +7,7 @@
using System.ComponentModel;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenIddict.Extensions;
namespace OpenIddict.Validation;
@ -48,7 +49,7 @@ public sealed class OpenIddictValidationDispatcher : IOpenIddictValidationDispat
await handler.HandleAsync(context);
}
catch (Exception exception) when (_logger.IsEnabled(LogLevel.Debug))
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) && _logger.IsEnabled(LogLevel.Debug))
{
_logger.LogDebug(exception, SR.GetResourceString(SR.ID6132), handler.GetType().FullName, typeof(TContext).FullName);

26
src/OpenIddict.Validation/OpenIddictValidationHandlers.cs

@ -6,6 +6,7 @@
using System.Collections.Immutable;
using System.ComponentModel;
using Microsoft.Extensions.Logging;
using OpenIddict.Extensions;
namespace OpenIddict.Validation;
@ -144,10 +145,27 @@ public static partial class OpenIddictValidationHandlers
throw new ArgumentNullException(nameof(context));
}
context.Configuration ??= await context.Options.ConfigurationManager
.GetConfigurationAsync(context.CancellationToken)
.WaitAsync(context.CancellationToken) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
try
{
// Resolve and attach the server configuration to the context if none has been set already.
context.Configuration ??= await context.Options.ConfigurationManager
.GetConfigurationAsync(context.CancellationToken)
.WaitAsync(context.CancellationToken) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) &&
exception is not OperationCanceledException)
{
context.Logger.LogError(exception, SR.GetResourceString(SR.ID6219));
context.Reject(
error: Errors.ServerError,
description: SR.GetResourceString(SR.ID2170),
uri: SR.FormatID8000(SR.ID2170));
return;
}
}
}

57
test/OpenIddict.Validation.IntegrationTests/OpenIddictValidationIntegrationTests.cs

@ -67,22 +67,25 @@ public abstract partial class OpenIddictValidationIntegrationTests
public async Task ProcessAuthentication_RejectsDemandWhenAccessTokenIsMissing()
{
// Arrange
await using var server = await CreateServerAsync(options =>
{
options.AddEventHandler<ProcessAuthenticationContext>(builder =>
{
builder.UseInlineHandler(context =>
{
// Assert
Assert.True(context.IsRejected);
Assert.Equal(Errors.MissingToken, context.Error);
Assert.Equal(SR.GetResourceString(SR.ID2000), context.ErrorDescription);
await using var server = await CreateServerAsync();
await using var client = await server.CreateClientAsync();
return default;
});
// Act
var response = await client.PostAsync("/authenticate", new OpenIddictRequest());
builder.SetOrder(ValidateRequiredTokens.Descriptor.Order + 1);
});
// Assert
Assert.Equal(0, response.Count);
}
[Fact]
public async Task ProcessAuthentication_RejectsDemandWithoutResolvingServerConfigurationWhenNoTokenWasResolved()
{
// Arrange
var manager = Mock.Of<IConfigurationManager<OpenIddictConfiguration>>();
await using var server = await CreateServerAsync(options =>
{
options.Configure(options => options.ConfigurationManager = manager);
});
await using var client = await server.CreateClientAsync();
@ -92,6 +95,32 @@ public abstract partial class OpenIddictValidationIntegrationTests
// Assert
Assert.Equal(0, response.Count);
Mock.Get(manager).Verify(manager => manager.GetConfigurationAsync(It.IsAny<CancellationToken>()), Times.Never());
}
[Fact]
public async Task ProcessAuthentication_RejectsDemandWhenConfigurationCannotBeResolved()
{
// Arrange
var manager = Mock.Of<IConfigurationManager<OpenIddictConfiguration>>(manager =>
manager.GetConfigurationAsync(It.IsAny<CancellationToken>()) == Task.FromException(new Exception()));
await using var server = await CreateServerAsync(options =>
{
options.Configure(options => options.ConfigurationManager = manager);
});
await using var client = await server.CreateClientAsync();
// Act
var response = await client.PostAsync("/authenticate", new OpenIddictRequest
{
AccessToken = "SlAV32hkKG"
});
// Assert
Assert.Equal(Errors.ServerError, response.Error);
Assert.Equal(SR.GetResourceString(SR.ID2170), response.ErrorDescription);
}
[Fact]

Loading…
Cancel
Save