Browse Source

Update the entire codebase to use IStringLocalizer/ResourceManager

pull/1030/head
Kévin Chalet 6 years ago
parent
commit
8feeb8698d
  1. 1
      Directory.Build.props
  2. 16
      Directory.Build.targets
  3. 2
      Directory.Packages.props
  4. 2
      samples/Mvc.Server/ViewModels/Authorization/VerifyViewModel.cs
  5. 3
      shared/OpenIddict.Extensions/Helpers/OpenIddictHelpers.cs
  6. 4
      shared/OpenIddict.Extensions/OpenIddict.Extensions.csproj
  7. 1
      src/OpenIddict.Abstractions/Caches/IOpenIddictApplicationCache.cs
  8. 1
      src/OpenIddict.Abstractions/Caches/IOpenIddictTokenCache.cs
  9. 5
      src/OpenIddict.Abstractions/OpenIddict.Abstractions.csproj
  10. 3
      src/OpenIddict.Abstractions/Primitives/OpenIddictConverter.cs
  11. 57
      src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs
  12. 17
      src/OpenIddict.Abstractions/Primitives/OpenIddictMessage.cs
  13. 11
      src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs
  14. 1432
      src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx
  15. 4
      src/OpenIddict.Abstractions/Stores/IOpenIddictApplicationStore.cs
  16. 2
      src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs
  17. 4
      src/OpenIddict.Abstractions/Stores/IOpenIddictScopeStore.cs
  18. 2
      src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs
  19. 17
      src/OpenIddict.Core/Caches/OpenIddictApplicationCache.cs
  20. 41
      src/OpenIddict.Core/Caches/OpenIddictAuthorizationCache.cs
  21. 17
      src/OpenIddict.Core/Caches/OpenIddictScopeCache.cs
  22. 37
      src/OpenIddict.Core/Caches/OpenIddictTokenCache.cs
  23. 83
      src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
  24. 74
      src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
  25. 36
      src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs
  26. 69
      src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
  27. 1
      src/OpenIddict.Core/OpenIddict.Core.csproj
  28. 51
      src/OpenIddict.Core/OpenIddictCoreBuilder.cs
  29. 19
      src/OpenIddict.Core/OpenIddictCoreExtensions.cs
  30. 19
      src/OpenIddict.Core/Resolvers/OpenIddictApplicationStoreResolver.cs
  31. 19
      src/OpenIddict.Core/Resolvers/OpenIddictAuthorizationStoreResolver.cs
  32. 19
      src/OpenIddict.Core/Resolvers/OpenIddictScopeStoreResolver.cs
  33. 19
      src/OpenIddict.Core/Resolvers/OpenIddictTokenStoreResolver.cs
  34. 3
      src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkBuilder.cs
  35. 15
      src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkApplicationStoreResolver.cs
  36. 15
      src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkAuthorizationStoreResolver.cs
  37. 15
      src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkScopeStoreResolver.cs
  38. 15
      src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkTokenStoreResolver.cs
  39. 25
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkApplicationStore.cs
  40. 54
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs
  41. 25
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkScopeStore.cs
  42. 52
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs
  43. 3
      src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreBuilder.cs
  44. 15
      src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreApplicationStoreResolver.cs
  45. 15
      src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreAuthorizationStoreResolver.cs
  46. 15
      src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreScopeStoreResolver.cs
  47. 15
      src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreTokenStoreResolver.cs
  48. 25
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs
  49. 54
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs
  50. 25
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreScopeStore.cs
  51. 52
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs
  52. 9
      src/OpenIddict.MongoDb/OpenIddictMongoDbBuilder.cs
  53. 9
      src/OpenIddict.MongoDb/OpenIddictMongoDbContext.cs
  54. 1
      src/OpenIddict.MongoDb/OpenIddictMongoDbOptions.cs
  55. 9
      src/OpenIddict.MongoDb/Resolvers/OpenIddictMongoDbApplicationStoreResolver.cs
  56. 9
      src/OpenIddict.MongoDb/Resolvers/OpenIddictMongoDbAuthorizationStoreResolver.cs
  57. 9
      src/OpenIddict.MongoDb/Resolvers/OpenIddictMongoDbScopeStoreResolver.cs
  58. 9
      src/OpenIddict.MongoDb/Resolvers/OpenIddictMongoDbTokenStoreResolver.cs
  59. 26
      src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbApplicationStore.cs
  60. 50
      src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbAuthorizationStore.cs
  61. 26
      src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbScopeStore.cs
  62. 46
      src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbTokenStore.cs
  63. 3
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreBuilder.cs
  64. 18
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreConfiguration.cs
  65. 36
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandler.cs
  66. 36
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Authentication.cs
  67. 33
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Session.cs
  68. 66
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
  69. 7
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.cs
  70. 3
      src/OpenIddict.Server.Owin/OpenIddictServerOwinBuilder.cs
  71. 7
      src/OpenIddict.Server.Owin/OpenIddictServerOwinConfiguration.cs
  72. 38
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandler.cs
  73. 36
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Authentication.cs
  74. 2
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Device.cs
  75. 33
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Session.cs
  76. 61
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
  77. 17
      src/OpenIddict.Server.Owin/OpenIddictServerOwinMiddlewareFactory.cs
  78. 1
      src/OpenIddict.Server/OpenIddict.Server.csproj
  79. 102
      src/OpenIddict.Server/OpenIddictServerBuilder.cs
  80. 109
      src/OpenIddict.Server/OpenIddictServerConfiguration.cs
  81. 13
      src/OpenIddict.Server/OpenIddictServerDispatcher.cs
  82. 7
      src/OpenIddict.Server/OpenIddictServerEvents.Authentication.cs
  83. 7
      src/OpenIddict.Server/OpenIddictServerEvents.Session.cs
  84. 2
      src/OpenIddict.Server/OpenIddictServerEvents.Userinfo.cs
  85. 7
      src/OpenIddict.Server/OpenIddictServerEvents.cs
  86. 19
      src/OpenIddict.Server/OpenIddictServerExtensions.cs
  87. 8
      src/OpenIddict.Server/OpenIddictServerFactory.cs
  88. 7
      src/OpenIddict.Server/OpenIddictServerHandlerDescriptor.cs
  89. 169
      src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs
  90. 109
      src/OpenIddict.Server/OpenIddictServerHandlers.Device.cs
  91. 23
      src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs
  92. 182
      src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs
  93. 90
      src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs
  94. 94
      src/OpenIddict.Server/OpenIddictServerHandlers.Revocation.cs
  95. 37
      src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs
  96. 18
      src/OpenIddict.Server/OpenIddictServerHandlers.Userinfo.cs
  97. 466
      src/OpenIddict.Server/OpenIddictServerHandlers.cs
  98. 5
      src/OpenIddict.Server/OpenIddictServerHelpers.cs
  99. 7
      src/OpenIddict.Server/OpenIddictServerOptions.cs
  100. 6
      src/OpenIddict.Server/OpenIddictServerTransaction.cs

1
Directory.Build.props

@ -9,6 +9,7 @@
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<CodeAnalysisRuleset>$(MSBuildThisFileDirectory)eng\CodeAnalysis.ruleset</CodeAnalysisRuleset> <CodeAnalysisRuleset>$(MSBuildThisFileDirectory)eng\CodeAnalysis.ruleset</CodeAnalysisRuleset>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<EnableXlfLocalization>false</EnableXlfLocalization>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>

16
Directory.Build.targets

@ -73,5 +73,21 @@
</ReferencePath> </ReferencePath>
</ItemGroup> </ItemGroup>
</Target> </Target>
<!--
Note: Arcade always generates .resx backing files with internal static methods/constants.
To ensure the OpenIddict resources are public, the default visibility is manually overriden.
-->
<Target Name="OverrideResourcesVisibility" Condition=" @(EmbeddedResourceSGResx) != '' " AfterTargets="_GenerateResxSource">
<WriteLinesToFile
File=" %(EmbeddedResourceSGResx.SourceOutputPath) "
Lines=" $([System.IO.File]::ReadAllText(%(EmbeddedResourceSGResx.SourceOutputPath))
.Replace('internal const', 'public const')
.Replace('internal static', 'public static')
.Replace('static partial class', 'partial class')) "
Overwrite="true"
Encoding="Unicode" />
</Target>
</Project> </Project>

2
Directory.Packages.props

@ -42,6 +42,7 @@
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="2.1.2" /> <PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="2.1.2" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="2.1.2" /> <PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="2.1.2" />
<PackageVersion Include="Microsoft.Extensions.Http.Polly" Version="2.1.1" /> <PackageVersion Include="Microsoft.Extensions.Http.Polly" Version="2.1.1" />
<PackageVersion Include="Microsoft.Extensions.Localization" Version="2.1.1" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="2.1.1" /> <PackageVersion Include="Microsoft.Extensions.Logging" Version="2.1.1" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="2.1.1" /> <PackageVersion Include="Microsoft.Extensions.Options" Version="2.1.1" />
<PackageVersion Include="Microsoft.Extensions.Primitives" Version="2.1.6" /> <PackageVersion Include="Microsoft.Extensions.Primitives" Version="2.1.6" />
@ -63,6 +64,7 @@
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.6" /> <PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.6" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="3.1.6" /> <PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="3.1.6" />
<PackageVersion Include="Microsoft.Extensions.Http.Polly" Version="3.1.6" /> <PackageVersion Include="Microsoft.Extensions.Http.Polly" Version="3.1.6" />
<PackageVersion Include="Microsoft.Extensions.Localization" Version="3.1.6" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="3.1.6" /> <PackageVersion Include="Microsoft.Extensions.Logging" Version="3.1.6" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="3.1.6" /> <PackageVersion Include="Microsoft.Extensions.Options" Version="3.1.6" />
<PackageVersion Include="Microsoft.Extensions.Primitives" Version="3.1.6" /> <PackageVersion Include="Microsoft.Extensions.Primitives" Version="3.1.6" />

2
samples/Mvc.Server/ViewModels/Authorization/VerifyViewModel.cs

@ -12,7 +12,7 @@ namespace Mvc.Server.ViewModels.Authorization
[BindNever, Display(Name = "Error")] [BindNever, Display(Name = "Error")]
public string Error { get; set; } public string Error { get; set; }
[BindNever, Display(Name = "Error description")] [BindNever, Display(Name = "Error description")]
public string ErrorDescription { get; set; } public string ErrorDescription { get; set; }

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

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Extensions namespace OpenIddict.Extensions
{ {
@ -38,7 +39,7 @@ namespace OpenIddict.Extensions
if (!definition.IsGenericTypeDefinition) if (!definition.IsGenericTypeDefinition)
{ {
throw new ArgumentException("The second parameter must be a generic type definition.", nameof(definition)); throw new ArgumentException(SR.GetResourceString(SR.ID1262), nameof(definition));
} }
if (definition.IsInterface) if (definition.IsInterface)

4
shared/OpenIddict.Extensions/OpenIddict.Extensions.csproj

@ -5,4 +5,8 @@
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\OpenIddict.Abstractions\OpenIddict.Abstractions.csproj" />
</ItemGroup>
</Project> </Project>

1
src/OpenIddict.Abstractions/Caches/IOpenIddictApplicationCache.cs

@ -5,7 +5,6 @@
*/ */
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;

1
src/OpenIddict.Abstractions/Caches/IOpenIddictTokenCache.cs

@ -5,7 +5,6 @@
*/ */
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;

5
src/OpenIddict.Abstractions/OpenIddict.Abstractions.csproj

@ -2,6 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net461;netstandard2.0;netstandard2.1</TargetFrameworks> <TargetFrameworks>net461;netstandard2.0;netstandard2.1</TargetFrameworks>
<GenerateResxSourceEmitFormatMethods>true</GenerateResxSourceEmitFormatMethods>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
@ -29,4 +30,8 @@
<PackageReference Include="System.ComponentModel.Annotations" /> <PackageReference Include="System.ComponentModel.Annotations" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<EmbeddedResource Update="**\*Resources.resx" GenerateSource="true" GenerateResourcesCodeAsConstants="true" />
</ItemGroup>
</Project> </Project>

3
src/OpenIddict.Abstractions/Primitives/OpenIddictConverter.cs

@ -8,6 +8,7 @@ using System;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using JetBrains.Annotations; using JetBrains.Annotations;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Abstractions namespace OpenIddict.Abstractions
{ {
@ -52,7 +53,7 @@ namespace OpenIddict.Abstractions
return typeToConvert == typeof(OpenIddictMessage) ? new OpenIddictMessage(document.RootElement.Clone()) : return typeToConvert == typeof(OpenIddictMessage) ? new OpenIddictMessage(document.RootElement.Clone()) :
typeToConvert == typeof(OpenIddictRequest) ? new OpenIddictRequest(document.RootElement.Clone()) : typeToConvert == typeof(OpenIddictRequest) ? new OpenIddictRequest(document.RootElement.Clone()) :
typeToConvert == typeof(OpenIddictResponse) ? (OpenIddictMessage) new OpenIddictResponse(document.RootElement.Clone()) : typeToConvert == typeof(OpenIddictResponse) ? (OpenIddictMessage) new OpenIddictResponse(document.RootElement.Clone()) :
throw new ArgumentException("The specified type is not supported.", nameof(typeToConvert)); throw new ArgumentException(SR.GetResourceString(SR.ID1175), nameof(typeToConvert));
} }
/// <summary> /// <summary>

57
src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs

@ -16,6 +16,7 @@ using System.Text.Json;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Abstractions namespace OpenIddict.Abstractions
{ {
@ -115,7 +116,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(value)) if (string.IsNullOrEmpty(value))
{ {
throw new ArgumentException("The value cannot be null or empty.", nameof(value)); throw new ArgumentException(SR.GetResourceString(SR.ID1176), nameof(value));
} }
return HasValue(request.AcrValues, value, Separators.Space); return HasValue(request.AcrValues, value, Separators.Space);
@ -135,7 +136,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(prompt)) if (string.IsNullOrEmpty(prompt))
{ {
throw new ArgumentException("The prompt cannot be null or empty.", nameof(prompt)); throw new ArgumentException(SR.GetResourceString(SR.ID1177), nameof(prompt));
} }
return HasValue(request.Prompt, prompt, Separators.Space); return HasValue(request.Prompt, prompt, Separators.Space);
@ -155,7 +156,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The response type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1178), nameof(type));
} }
return HasValue(request.ResponseType, type, Separators.Space); return HasValue(request.ResponseType, type, Separators.Space);
@ -175,7 +176,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(scope)) if (string.IsNullOrEmpty(scope))
{ {
throw new ArgumentException("The scope cannot be null or empty.", nameof(scope)); throw new ArgumentException(SR.GetResourceString(SR.ID1179), nameof(scope));
} }
return HasValue(request.Scope, scope, Separators.Space); return HasValue(request.Scope, scope, Separators.Space);
@ -556,7 +557,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(destination)) if (string.IsNullOrEmpty(destination))
{ {
throw new ArgumentException("The destination cannot be null or empty.", nameof(destination)); throw new ArgumentException(SR.GetResourceString(SR.ID1180), nameof(destination));
} }
claim.Properties.TryGetValue(Properties.Destinations, out string destinations); claim.Properties.TryGetValue(Properties.Destinations, out string destinations);
@ -591,7 +592,7 @@ namespace OpenIddict.Abstractions
if (destinations.Any(destination => string.IsNullOrEmpty(destination))) if (destinations.Any(destination => string.IsNullOrEmpty(destination)))
{ {
throw new ArgumentException("Destinations cannot be null or empty.", nameof(destinations)); throw new ArgumentException(SR.GetResourceString(SR.ID1181), nameof(destinations));
} }
claim.Properties[Properties.Destinations] = claim.Properties[Properties.Destinations] =
@ -646,7 +647,7 @@ namespace OpenIddict.Abstractions
{ {
if (!destinations.SetEquals(claims[index].GetDestinations())) if (!destinations.SetEquals(claims[index].GetDestinations()))
{ {
throw new InvalidOperationException($"Conflicting destinations for the claim '{group.Key}' were specified."); throw new InvalidOperationException(SR.FormatID1182(group.Key));
} }
} }
@ -779,12 +780,12 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
if (string.IsNullOrEmpty(value)) if (string.IsNullOrEmpty(value))
{ {
throw new ArgumentException("The claim value cannot be null or empty.", nameof(value)); throw new ArgumentException(SR.GetResourceString(SR.ID1184), nameof(value));
} }
identity.AddClaim(new Claim(type, value)); identity.AddClaim(new Claim(type, value));
@ -810,12 +811,12 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
if (string.IsNullOrEmpty(value)) if (string.IsNullOrEmpty(value))
{ {
throw new ArgumentException("The claim value cannot be null or empty.", nameof(value)); throw new ArgumentException(SR.GetResourceString(SR.ID1184), nameof(value));
} }
if (destinations == null) if (destinations == null)
@ -855,7 +856,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
return identity.FindFirst(type)?.Value; return identity.FindFirst(type)?.Value;
@ -876,7 +877,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
return principal.FindFirst(type)?.Value; return principal.FindFirst(type)?.Value;
@ -897,7 +898,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
return identity.FindAll(type).Select(claim => claim.Value).Distinct(StringComparer.Ordinal).ToImmutableArray(); return identity.FindAll(type).Select(claim => claim.Value).Distinct(StringComparer.Ordinal).ToImmutableArray();
@ -918,7 +919,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
return identity.FindAll(type).Any(); return identity.FindAll(type).Any();
@ -939,7 +940,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
return principal.FindAll(type).Select(claim => claim.Value).Distinct(StringComparer.Ordinal).ToImmutableArray(); return principal.FindAll(type).Select(claim => claim.Value).Distinct(StringComparer.Ordinal).ToImmutableArray();
@ -960,7 +961,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
return principal.FindAll(type).Any(); return principal.FindAll(type).Any();
@ -981,7 +982,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
foreach (var claim in identity.FindAll(type).ToList()) foreach (var claim in identity.FindAll(type).ToList())
@ -1007,7 +1008,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
foreach (var identity in principal.Identities) foreach (var identity in principal.Identities)
@ -1039,7 +1040,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
identity.RemoveClaims(type); identity.RemoveClaims(type);
@ -1070,7 +1071,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
principal.RemoveClaims(type); principal.RemoveClaims(type);
@ -1100,7 +1101,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
identity.RemoveClaims(type); identity.RemoveClaims(type);
@ -1130,7 +1131,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The claim type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1183), nameof(type));
} }
principal.RemoveClaims(type); principal.RemoveClaims(type);
@ -1322,7 +1323,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(audience)) if (string.IsNullOrEmpty(audience))
{ {
throw new ArgumentException("The audience cannot be null or empty.", nameof(audience)); throw new ArgumentException(SR.GetResourceString(SR.ID1185), nameof(audience));
} }
return principal.HasClaim(Claims.Private.Audience, audience); return principal.HasClaim(Claims.Private.Audience, audience);
@ -1351,7 +1352,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(presenter)) if (string.IsNullOrEmpty(presenter))
{ {
throw new ArgumentException("The presenter cannot be null or empty.", nameof(presenter)); throw new ArgumentException(SR.GetResourceString(SR.ID1186), nameof(presenter));
} }
return principal.HasClaim(Claims.Private.Presenter, presenter); return principal.HasClaim(Claims.Private.Presenter, presenter);
@ -1380,7 +1381,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(resource)) if (string.IsNullOrEmpty(resource))
{ {
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource)); throw new ArgumentException(SR.GetResourceString(SR.ID1061), nameof(resource));
} }
return principal.HasClaim(Claims.Private.Resource, resource); return principal.HasClaim(Claims.Private.Resource, resource);
@ -1409,7 +1410,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(scope)) if (string.IsNullOrEmpty(scope))
{ {
throw new ArgumentException("The scope cannot be null or empty.", nameof(scope)); throw new ArgumentException(SR.GetResourceString(SR.ID1179), nameof(scope));
} }
return principal.HasClaim(Claims.Private.Scope, scope); return principal.HasClaim(Claims.Private.Scope, scope);
@ -1430,7 +1431,7 @@ namespace OpenIddict.Abstractions
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The token type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1187), nameof(type));
} }
return string.Equals(principal.GetTokenType(), type, StringComparison.OrdinalIgnoreCase); return string.Equals(principal.GetTokenType(), type, StringComparison.OrdinalIgnoreCase);

17
src/OpenIddict.Abstractions/Primitives/OpenIddictMessage.cs

@ -16,6 +16,7 @@ using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Abstractions namespace OpenIddict.Abstractions
{ {
@ -46,7 +47,7 @@ namespace OpenIddict.Abstractions
{ {
if (parameters.ValueKind != JsonValueKind.Object) if (parameters.ValueKind != JsonValueKind.Object)
{ {
throw new ArgumentException("The specified JSON element is not an object.", nameof(parameters)); throw new ArgumentException(SR.GetResourceString(SR.ID1188), nameof(parameters));
} }
foreach (var parameter in parameters.EnumerateObject()) foreach (var parameter in parameters.EnumerateObject())
@ -192,12 +193,12 @@ namespace OpenIddict.Abstractions
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The parameter name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1189), nameof(name));
} }
if (Parameters.ContainsKey(name)) if (Parameters.ContainsKey(name))
{ {
throw new ArgumentException("A parameter with the same name already exists.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1190), nameof(name));
} }
Parameters.Add(name, value); Parameters.Add(name, value);
@ -214,7 +215,7 @@ namespace OpenIddict.Abstractions
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The parameter name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1189), nameof(name));
} }
if (Parameters.TryGetValue(name, out OpenIddictParameter value)) if (Parameters.TryGetValue(name, out OpenIddictParameter value))
@ -241,7 +242,7 @@ namespace OpenIddict.Abstractions
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The parameter name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1189), nameof(name));
} }
return Parameters.ContainsKey(name); return Parameters.ContainsKey(name);
@ -256,7 +257,7 @@ namespace OpenIddict.Abstractions
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The parameter name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1189), nameof(name));
} }
Parameters.Remove(name); Parameters.Remove(name);
@ -275,7 +276,7 @@ namespace OpenIddict.Abstractions
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The parameter name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1189), nameof(name));
} }
// If the parameter value is null or empty, remove the corresponding entry from the collection. // If the parameter value is null or empty, remove the corresponding entry from the collection.
@ -302,7 +303,7 @@ namespace OpenIddict.Abstractions
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The parameter name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1189), nameof(name));
} }
return Parameters.TryGetValue(name, out value); return Parameters.TryGetValue(name, out value);

11
src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs

@ -13,6 +13,7 @@ using System.Linq;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using JetBrains.Annotations; using JetBrains.Annotations;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Abstractions namespace OpenIddict.Abstractions
{ {
@ -199,7 +200,7 @@ namespace OpenIddict.Abstractions
{ {
return false; return false;
} }
if (!Equals(property.Value, element)) if (!Equals(property.Value, element))
{ {
return false; return false;
@ -298,7 +299,7 @@ namespace OpenIddict.Abstractions
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The item name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1191), nameof(name));
} }
if (Value is JsonElement element && element.ValueKind == JsonValueKind.Object) if (Value is JsonElement element && element.ValueKind == JsonValueKind.Object)
@ -324,7 +325,7 @@ namespace OpenIddict.Abstractions
{ {
if (index < 0) if (index < 0)
{ {
throw new ArgumentOutOfRangeException(nameof(index), "The item index cannot be negative."); throw new ArgumentOutOfRangeException(nameof(index), SR.GetResourceString(SR.ID1192));
} }
if (Value is string[] array) if (Value is string[] array)
@ -437,7 +438,7 @@ namespace OpenIddict.Abstractions
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The parameter name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1189), nameof(name));
} }
if (Value is JsonElement element && element.ValueKind == JsonValueKind.Object && if (Value is JsonElement element && element.ValueKind == JsonValueKind.Object &&
@ -499,7 +500,7 @@ namespace OpenIddict.Abstractions
value.WriteTo(writer); value.WriteTo(writer);
break; break;
default: throw new InvalidOperationException("The type of the parameter value is not supported."); default: throw new InvalidOperationException(SR.GetResourceString(SR.ID1193));
} }
} }

1432
src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx

File diff suppressed because it is too large

4
src/OpenIddict.Abstractions/Stores/IOpenIddictApplicationStore.cs

@ -7,12 +7,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using System.Text.Json;
using System.Globalization;
namespace OpenIddict.Abstractions namespace OpenIddict.Abstractions
{ {

2
src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs

@ -8,10 +8,10 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using System.Text.Json;
namespace OpenIddict.Abstractions namespace OpenIddict.Abstractions
{ {

4
src/OpenIddict.Abstractions/Stores/IOpenIddictScopeStore.cs

@ -7,12 +7,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using System.Text.Json;
using System.Globalization;
namespace OpenIddict.Abstractions namespace OpenIddict.Abstractions
{ {

2
src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs

@ -8,10 +8,10 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using System.Text.Json;
namespace OpenIddict.Abstractions namespace OpenIddict.Abstractions
{ {

17
src/OpenIddict.Core/Caches/OpenIddictApplicationCache.cs

@ -16,6 +16,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Core namespace OpenIddict.Core
{ {
@ -124,7 +125,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var parameters = new var parameters = new
@ -166,7 +167,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var parameters = new var parameters = new
@ -206,7 +207,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("The address cannot be null or empty.", nameof(address)); throw new ArgumentException(SR.GetResourceString(SR.ID1142), nameof(address));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -253,7 +254,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("The address cannot be null or empty.", nameof(address)); throw new ArgumentException(SR.GetResourceString(SR.ID1142), nameof(address));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -305,7 +306,7 @@ namespace OpenIddict.Core
var identifier = await _store.GetIdAsync(application, cancellationToken); var identifier = await _store.GetIdAsync(application, cancellationToken);
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new InvalidOperationException("The application identifier cannot be extracted."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1195));
} }
if (_signals.TryRemove(identifier, out CancellationTokenSource signal)) if (_signals.TryRemove(identifier, out CancellationTokenSource signal))
@ -337,7 +338,7 @@ namespace OpenIddict.Core
var signal = await CreateExpirationSignalAsync(application, cancellationToken); var signal = await CreateExpirationSignalAsync(application, cancellationToken);
if (signal == null) if (signal == null)
{ {
throw new InvalidOperationException("An error occurred while creating an expiration signal."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1196));
} }
entry.AddExpirationToken(signal); entry.AddExpirationToken(signal);
@ -369,7 +370,7 @@ namespace OpenIddict.Core
var signal = await CreateExpirationSignalAsync(application, cancellationToken); var signal = await CreateExpirationSignalAsync(application, cancellationToken);
if (signal == null) if (signal == null)
{ {
throw new InvalidOperationException("An error occurred while creating an expiration signal."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1196));
} }
entry.AddExpirationToken(signal); entry.AddExpirationToken(signal);
@ -400,7 +401,7 @@ namespace OpenIddict.Core
var identifier = await _store.GetIdAsync(application, cancellationToken); var identifier = await _store.GetIdAsync(application, cancellationToken);
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new InvalidOperationException("The application identifier cannot be extracted."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1195));
} }
var signal = _signals.GetOrAdd(identifier, _ => new CancellationTokenSource()); var signal = _signals.GetOrAdd(identifier, _ => new CancellationTokenSource());

41
src/OpenIddict.Core/Caches/OpenIddictAuthorizationCache.cs

@ -16,6 +16,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Core namespace OpenIddict.Core
{ {
@ -132,12 +133,12 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -188,17 +189,17 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -251,22 +252,22 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -322,22 +323,22 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
// Note: this method is only partially cached. // Note: this method is only partially cached.
@ -366,7 +367,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -415,7 +416,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var parameters = new var parameters = new
@ -455,7 +456,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -507,7 +508,7 @@ namespace OpenIddict.Core
var identifier = await _store.GetIdAsync(authorization, cancellationToken); var identifier = await _store.GetIdAsync(authorization, cancellationToken);
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new InvalidOperationException("The application identifier cannot be extracted."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1195));
} }
if (_signals.TryRemove(identifier, out CancellationTokenSource signal)) if (_signals.TryRemove(identifier, out CancellationTokenSource signal))
@ -539,7 +540,7 @@ namespace OpenIddict.Core
var signal = await CreateExpirationSignalAsync(authorization, cancellationToken); var signal = await CreateExpirationSignalAsync(authorization, cancellationToken);
if (signal == null) if (signal == null)
{ {
throw new InvalidOperationException("An error occurred while creating an expiration signal."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1196));
} }
entry.AddExpirationToken(signal); entry.AddExpirationToken(signal);
@ -571,7 +572,7 @@ namespace OpenIddict.Core
var signal = await CreateExpirationSignalAsync(authorization, cancellationToken); var signal = await CreateExpirationSignalAsync(authorization, cancellationToken);
if (signal == null) if (signal == null)
{ {
throw new InvalidOperationException("An error occurred while creating an expiration signal."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1196));
} }
entry.AddExpirationToken(signal); entry.AddExpirationToken(signal);
@ -602,7 +603,7 @@ namespace OpenIddict.Core
var identifier = await _store.GetIdAsync(authorization, cancellationToken); var identifier = await _store.GetIdAsync(authorization, cancellationToken);
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new InvalidOperationException("The authorization identifier cannot be extracted."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1200));
} }
var signal = _signals.GetOrAdd(identifier, _ => new CancellationTokenSource()); var signal = _signals.GetOrAdd(identifier, _ => new CancellationTokenSource());

17
src/OpenIddict.Core/Caches/OpenIddictScopeCache.cs

@ -17,6 +17,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Core namespace OpenIddict.Core
{ {
@ -116,7 +117,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var parameters = new var parameters = new
@ -158,7 +159,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The scope name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1201), nameof(name));
} }
var parameters = new var parameters = new
@ -197,7 +198,7 @@ namespace OpenIddict.Core
{ {
if (names.Any(name => string.IsNullOrEmpty(name))) if (names.Any(name => string.IsNullOrEmpty(name)))
{ {
throw new ArgumentException("Scope names cannot be null or empty.", nameof(names)); throw new ArgumentException(SR.GetResourceString(SR.ID1202), nameof(names));
} }
// Note: this method is only partially cached. // Note: this method is only partially cached.
@ -225,7 +226,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(resource)) if (string.IsNullOrEmpty(resource))
{ {
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource)); throw new ArgumentException(SR.GetResourceString(SR.ID1061), nameof(resource));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -277,7 +278,7 @@ namespace OpenIddict.Core
var identifier = await _store.GetIdAsync(scope, cancellationToken); var identifier = await _store.GetIdAsync(scope, cancellationToken);
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new InvalidOperationException("The application identifier cannot be extracted."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1195));
} }
if (_signals.TryRemove(identifier, out CancellationTokenSource signal)) if (_signals.TryRemove(identifier, out CancellationTokenSource signal))
@ -309,7 +310,7 @@ namespace OpenIddict.Core
var signal = await CreateExpirationSignalAsync(scope, cancellationToken); var signal = await CreateExpirationSignalAsync(scope, cancellationToken);
if (signal == null) if (signal == null)
{ {
throw new InvalidOperationException("An error occurred while creating an expiration signal."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1196));
} }
entry.AddExpirationToken(signal); entry.AddExpirationToken(signal);
@ -341,7 +342,7 @@ namespace OpenIddict.Core
var signal = await CreateExpirationSignalAsync(scope, cancellationToken); var signal = await CreateExpirationSignalAsync(scope, cancellationToken);
if (signal == null) if (signal == null)
{ {
throw new InvalidOperationException("An error occurred while creating an expiration signal."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1196));
} }
entry.AddExpirationToken(signal); entry.AddExpirationToken(signal);
@ -371,7 +372,7 @@ namespace OpenIddict.Core
var identifier = await _store.GetIdAsync(scope, cancellationToken); var identifier = await _store.GetIdAsync(scope, cancellationToken);
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new InvalidOperationException("The scope identifier cannot be extracted."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1203));
} }
var signal = _signals.GetOrAdd(identifier, _ => new CancellationTokenSource()); var signal = _signals.GetOrAdd(identifier, _ => new CancellationTokenSource());

37
src/OpenIddict.Core/Caches/OpenIddictTokenCache.cs

@ -16,6 +16,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Core namespace OpenIddict.Core
{ {
@ -148,12 +149,12 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -204,17 +205,17 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -267,22 +268,22 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -332,7 +333,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -379,7 +380,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -428,7 +429,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var parameters = new var parameters = new
@ -471,7 +472,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var parameters = new var parameters = new
@ -510,7 +511,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -562,7 +563,7 @@ namespace OpenIddict.Core
var identifier = await _store.GetIdAsync(token, cancellationToken); var identifier = await _store.GetIdAsync(token, cancellationToken);
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new InvalidOperationException("The application identifier cannot be extracted."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1204));
} }
if (_signals.TryRemove(identifier, out CancellationTokenSource signal)) if (_signals.TryRemove(identifier, out CancellationTokenSource signal))
@ -594,7 +595,7 @@ namespace OpenIddict.Core
var signal = await CreateExpirationSignalAsync(token, cancellationToken); var signal = await CreateExpirationSignalAsync(token, cancellationToken);
if (signal == null) if (signal == null)
{ {
throw new InvalidOperationException("An error occurred while creating an expiration signal."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1196));
} }
entry.AddExpirationToken(signal); entry.AddExpirationToken(signal);
@ -626,7 +627,7 @@ namespace OpenIddict.Core
var signal = await CreateExpirationSignalAsync(token, cancellationToken); var signal = await CreateExpirationSignalAsync(token, cancellationToken);
if (signal == null) if (signal == null)
{ {
throw new InvalidOperationException("An error occurred while creating an expiration signal."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1196));
} }
entry.AddExpirationToken(signal); entry.AddExpirationToken(signal);
@ -656,7 +657,7 @@ namespace OpenIddict.Core
var identifier = await _store.GetIdAsync(token, cancellationToken); var identifier = await _store.GetIdAsync(token, cancellationToken);
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new InvalidOperationException("The token identifier cannot be extracted."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1204));
} }
var signal = _signals.GetOrAdd(identifier, _ => new CancellationTokenSource()); var signal = _signals.GetOrAdd(identifier, _ => new CancellationTokenSource());

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

@ -17,10 +17,13 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.Abstractions.Resources;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute; using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
#if !SUPPORTS_KEY_DERIVATION_WITH_SPECIFIED_HASH_ALGORITHM #if !SUPPORTS_KEY_DERIVATION_WITH_SPECIFIED_HASH_ALGORITHM
@ -49,14 +52,16 @@ namespace OpenIddict.Core
{ {
public OpenIddictApplicationManager( public OpenIddictApplicationManager(
[NotNull] IOpenIddictApplicationCache<TApplication> cache, [NotNull] IOpenIddictApplicationCache<TApplication> cache,
[NotNull] IOpenIddictApplicationStoreResolver resolver, [NotNull] IStringLocalizer<OpenIddictResources> localizer,
[NotNull] ILogger<OpenIddictApplicationManager<TApplication>> logger, [NotNull] ILogger<OpenIddictApplicationManager<TApplication>> logger,
[NotNull] IOptionsMonitor<OpenIddictCoreOptions> options) [NotNull] IOptionsMonitor<OpenIddictCoreOptions> options,
[NotNull] IOpenIddictApplicationStoreResolver resolver)
{ {
Cache = cache; Cache = cache;
Store = resolver.Get<TApplication>(); Localizer = localizer;
Logger = logger; Logger = logger;
Options = options; Options = options;
Store = resolver.Get<TApplication>();
} }
/// <summary> /// <summary>
@ -64,6 +69,11 @@ namespace OpenIddict.Core
/// </summary> /// </summary>
protected IOpenIddictApplicationCache<TApplication> Cache { get; } protected IOpenIddictApplicationCache<TApplication> Cache { get; }
/// <summary>
/// Gets the string localizer associated with the current manager.
/// </summary>
protected IStringLocalizer Localizer { get; }
/// <summary> /// <summary>
/// Gets the logger associated with the current manager. /// Gets the logger associated with the current manager.
/// </summary> /// </summary>
@ -144,7 +154,7 @@ namespace OpenIddict.Core
if (!string.IsNullOrEmpty(await Store.GetClientSecretAsync(application, cancellationToken))) if (!string.IsNullOrEmpty(await Store.GetClientSecretAsync(application, cancellationToken)))
{ {
throw new ArgumentException("The client secret hash cannot be set on the application entity.", nameof(application)); throw new ArgumentException(SR.GetResourceString(SR.ID1205), nameof(application));
} }
// If no client type was specified, assume it's a public application if no secret was provided. // If no client type was specified, assume it's a public application if no secret was provided.
@ -166,7 +176,7 @@ namespace OpenIddict.Core
if (results.Any(result => result != ValidationResult.Success)) if (results.Any(result => result != ValidationResult.Success))
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine("One or more validation error(s) occurred while trying to create a new application:"); builder.AppendLine(SR.GetResourceString(SR.ID1206));
builder.AppendLine(); builder.AppendLine();
foreach (var result in results) foreach (var result in results)
@ -220,7 +230,7 @@ namespace OpenIddict.Core
var application = await Store.InstantiateAsync(cancellationToken); var application = await Store.InstantiateAsync(cancellationToken);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("An error occurred while trying to create a new application."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1207));
} }
await PopulateAsync(application, descriptor, cancellationToken); await PopulateAsync(application, descriptor, cancellationToken);
@ -276,7 +286,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var application = Options.CurrentValue.DisableEntityCaching ? var application = Options.CurrentValue.DisableEntityCaching ?
@ -313,7 +323,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var application = Options.CurrentValue.DisableEntityCaching ? var application = Options.CurrentValue.DisableEntityCaching ?
@ -348,7 +358,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("The address cannot be null or empty.", nameof(address)); throw new ArgumentException(SR.GetResourceString(SR.ID1142), nameof(address));
} }
var applications = Options.CurrentValue.DisableEntityCaching ? var applications = Options.CurrentValue.DisableEntityCaching ?
@ -390,7 +400,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("The address cannot be null or empty.", nameof(address)); throw new ArgumentException(SR.GetResourceString(SR.ID1142), nameof(address));
} }
var applications = Options.CurrentValue.DisableEntityCaching ? var applications = Options.CurrentValue.DisableEntityCaching ?
@ -755,7 +765,7 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The client type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1208), nameof(type));
} }
return string.Equals(await GetClientTypeAsync(application, cancellationToken), type, StringComparison.OrdinalIgnoreCase); return string.Equals(await GetClientTypeAsync(application, cancellationToken), type, StringComparison.OrdinalIgnoreCase);
@ -778,7 +788,7 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The consent type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1209), nameof(type));
} }
return string.Equals(await GetConsentTypeAsync(application, cancellationToken), type, StringComparison.OrdinalIgnoreCase); return string.Equals(await GetConsentTypeAsync(application, cancellationToken), type, StringComparison.OrdinalIgnoreCase);
@ -801,7 +811,7 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(permission)) if (string.IsNullOrEmpty(permission))
{ {
throw new ArgumentException("The permission name cannot be null or empty.", nameof(permission)); throw new ArgumentException(SR.GetResourceString(SR.ID1210), nameof(permission));
} }
return (await GetPermissionsAsync(application, cancellationToken)).Contains(permission, StringComparer.Ordinal); return (await GetPermissionsAsync(application, cancellationToken)).Contains(permission, StringComparer.Ordinal);
@ -824,7 +834,7 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(requirement)) if (string.IsNullOrEmpty(requirement))
{ {
throw new ArgumentException("The requirement name cannot be null or empty.", nameof(requirement)); throw new ArgumentException(SR.GetResourceString(SR.ID1211), nameof(requirement));
} }
return (await GetRequirementsAsync(application, cancellationToken)).Contains(requirement, StringComparer.Ordinal); return (await GetRequirementsAsync(application, cancellationToken)).Contains(requirement, StringComparer.Ordinal);
@ -961,13 +971,13 @@ namespace OpenIddict.Core
// Ensure the address is not null or empty. // Ensure the address is not null or empty.
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("Callback URLs cannot be null or empty."); throw new ArgumentException(SR.GetResourceString(SR.ID1212));
} }
// Ensure the address is a valid absolute URL. // Ensure the address is a valid absolute URL.
if (!Uri.TryCreate(address, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString()) if (!Uri.TryCreate(address, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString())
{ {
throw new ArgumentException("Callback URLs must be valid absolute URLs."); throw new ArgumentException(SR.GetResourceString(SR.ID1213));
} }
descriptor.PostLogoutRedirectUris.Add(uri); descriptor.PostLogoutRedirectUris.Add(uri);
@ -979,13 +989,13 @@ namespace OpenIddict.Core
// Ensure the address is not null or empty. // Ensure the address is not null or empty.
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("Callback URLs cannot be null or empty."); throw new ArgumentException(SR.GetResourceString(SR.ID1212));
} }
// Ensure the address is a valid absolute URL. // Ensure the address is a valid absolute URL.
if (!Uri.TryCreate(address, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString()) if (!Uri.TryCreate(address, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString())
{ {
throw new ArgumentException("Callback URLs must be valid absolute URLs."); throw new ArgumentException(SR.GetResourceString(SR.ID1213));
} }
descriptor.RedirectUris.Add(uri); descriptor.RedirectUris.Add(uri);
@ -1011,7 +1021,7 @@ namespace OpenIddict.Core
if (results.Any(result => result != ValidationResult.Success)) if (results.Any(result => result != ValidationResult.Success))
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine("One or more validation error(s) occurred while trying to update an existing application:"); builder.AppendLine(SR.GetResourceString(SR.ID1214));
builder.AppendLine(); builder.AppendLine();
foreach (var result in results) foreach (var result in results)
@ -1133,7 +1143,7 @@ namespace OpenIddict.Core
var identifier = await Store.GetClientIdAsync(application, cancellationToken); var identifier = await Store.GetClientIdAsync(application, cancellationToken);
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
yield return new ValidationResult("The client identifier cannot be null or empty."); yield return new ValidationResult(Localizer[SR.ID3036]);
} }
else else
@ -1147,14 +1157,14 @@ namespace OpenIddict.Core
await Store.GetIdAsync(other, cancellationToken), await Store.GetIdAsync(other, cancellationToken),
await Store.GetIdAsync(application, cancellationToken), StringComparison.Ordinal)) await Store.GetIdAsync(application, cancellationToken), StringComparison.Ordinal))
{ {
yield return new ValidationResult("An application with the same client identifier already exists."); yield return new ValidationResult(Localizer[SR.ID3111]);
} }
} }
var type = await Store.GetClientTypeAsync(application, cancellationToken); var type = await Store.GetClientTypeAsync(application, cancellationToken);
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
yield return new ValidationResult("The client type cannot be null or empty."); yield return new ValidationResult(Localizer[SR.ID3118]);
} }
else else
@ -1164,21 +1174,20 @@ namespace OpenIddict.Core
!string.Equals(type, ClientTypes.Hybrid, StringComparison.OrdinalIgnoreCase) && !string.Equals(type, ClientTypes.Hybrid, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(type, ClientTypes.Public, StringComparison.OrdinalIgnoreCase)) !string.Equals(type, ClientTypes.Public, StringComparison.OrdinalIgnoreCase))
{ {
yield return new ValidationResult("Only 'confidential', 'hybrid' or 'public' applications are " + yield return new ValidationResult(Localizer[SR.ID3112]);
"supported by the default application manager.");
} }
// Ensure a client secret was specified if the client is a confidential application. // Ensure a client secret was specified if the client is a confidential application.
var secret = await Store.GetClientSecretAsync(application, cancellationToken); var secret = await Store.GetClientSecretAsync(application, cancellationToken);
if (string.IsNullOrEmpty(secret) && string.Equals(type, ClientTypes.Confidential, StringComparison.OrdinalIgnoreCase)) if (string.IsNullOrEmpty(secret) && string.Equals(type, ClientTypes.Confidential, StringComparison.OrdinalIgnoreCase))
{ {
yield return new ValidationResult("The client secret cannot be null or empty for a confidential application."); yield return new ValidationResult(Localizer[SR.ID3113]);
} }
// Ensure no client secret was specified if the client is a public application. // Ensure no client secret was specified if the client is a public application.
else if (!string.IsNullOrEmpty(secret) && string.Equals(type, ClientTypes.Public, StringComparison.OrdinalIgnoreCase)) else if (!string.IsNullOrEmpty(secret) && string.Equals(type, ClientTypes.Public, StringComparison.OrdinalIgnoreCase))
{ {
yield return new ValidationResult("A client secret cannot be associated with a public application."); yield return new ValidationResult(Localizer[SR.ID3114]);
} }
} }
@ -1191,7 +1200,7 @@ namespace OpenIddict.Core
// Ensure the address is not null or empty. // Ensure the address is not null or empty.
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
yield return new ValidationResult("Callback URLs cannot be null or empty."); yield return new ValidationResult(Localizer[SR.ID3119]);
break; break;
} }
@ -1199,7 +1208,7 @@ namespace OpenIddict.Core
// Ensure the address is a valid absolute URL. // Ensure the address is a valid absolute URL.
if (!Uri.TryCreate(address, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString()) if (!Uri.TryCreate(address, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString())
{ {
yield return new ValidationResult("Callback URLs must be valid absolute URLs."); yield return new ValidationResult(Localizer[SR.ID3120]);
break; break;
} }
@ -1207,7 +1216,7 @@ namespace OpenIddict.Core
// Ensure the address doesn't contain a fragment. // Ensure the address doesn't contain a fragment.
if (!string.IsNullOrEmpty(uri.Fragment)) if (!string.IsNullOrEmpty(uri.Fragment))
{ {
yield return new ValidationResult("Callback URLs cannot contain a fragment."); yield return new ValidationResult(Localizer[SR.ID3115]);
break; break;
} }
@ -1234,7 +1243,7 @@ namespace OpenIddict.Core
} }
if (string.IsNullOrEmpty(secret)) if (string.IsNullOrEmpty(secret))
{ {
throw new ArgumentException("The secret cannot be null or empty.", nameof(secret)); throw new ArgumentException(SR.GetResourceString(SR.ID1215), nameof(secret));
} }
if (await HasClientTypeAsync(application, ClientTypes.Public, cancellationToken)) if (await HasClientTypeAsync(application, ClientTypes.Public, cancellationToken))
@ -1285,7 +1294,7 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("The address cannot be null or empty.", nameof(address)); throw new ArgumentException(SR.GetResourceString(SR.ID1142), nameof(address));
} }
foreach (var uri in await Store.GetRedirectUrisAsync(application, cancellationToken)) foreach (var uri in await Store.GetRedirectUrisAsync(application, cancellationToken))
@ -1317,7 +1326,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(secret)) if (string.IsNullOrEmpty(secret))
{ {
throw new ArgumentException("The secret cannot be null or empty.", nameof(secret)); throw new ArgumentException(SR.GetResourceString(SR.ID1215), nameof(secret));
} }
// Note: the PRF, iteration count, salt length and key length currently all match the default values // Note: the PRF, iteration count, salt length and key length currently all match the default values
@ -1362,7 +1371,7 @@ namespace OpenIddict.Core
var name when name == HashAlgorithmName.SHA256 => 1, var name when name == HashAlgorithmName.SHA256 => 1,
var name when name == HashAlgorithmName.SHA512 => 2, var name when name == HashAlgorithmName.SHA512 => 2,
_ => throw new InvalidOperationException("The specified HMAC algorithm is not valid.") _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID1216))
}); });
// Write the iteration count of the algorithm. // Write the iteration count of the algorithm.
@ -1397,12 +1406,12 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(secret)) if (string.IsNullOrEmpty(secret))
{ {
throw new ArgumentException("The secret cannot be null or empty.", nameof(secret)); throw new ArgumentException(SR.GetResourceString(SR.ID1215), nameof(secret));
} }
if (string.IsNullOrEmpty(comparand)) if (string.IsNullOrEmpty(comparand))
{ {
throw new ArgumentException("The comparand cannot be null or empty.", nameof(comparand)); throw new ArgumentException(SR.GetResourceString(SR.ID1217), nameof(comparand));
} }
try try
@ -1443,7 +1452,7 @@ namespace OpenIddict.Core
1 => HashAlgorithmName.SHA256, 1 => HashAlgorithmName.SHA256,
2 => HashAlgorithmName.SHA512, 2 => HashAlgorithmName.SHA512,
_ => throw new InvalidOperationException("The specified hash algorithm is not valid.") _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID1216))
}; };
// Read the iteration count of the algorithm. // Read the iteration count of the algorithm.
@ -1493,7 +1502,7 @@ namespace OpenIddict.Core
var name when name == HashAlgorithmName.SHA256 => new Sha256Digest(), var name when name == HashAlgorithmName.SHA256 => new Sha256Digest(),
var name when name == HashAlgorithmName.SHA512 => new Sha512Digest(), var name when name == HashAlgorithmName.SHA512 => new Sha512Digest(),
_ => throw new InvalidOperationException("The specified hash algorithm is not valid.") _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID1216))
}); });
generator.Init(PbeParametersGenerator.Pkcs5PasswordToBytes(secret.ToCharArray()), salt.ToArray(), iterations); generator.Init(PbeParametersGenerator.Pkcs5PasswordToBytes(secret.ToCharArray()), salt.ToArray(), iterations);

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

@ -15,11 +15,14 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.Abstractions.Resources;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Abstractions.OpenIddictExceptions; using static OpenIddict.Abstractions.OpenIddictExceptions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Core namespace OpenIddict.Core
{ {
@ -36,14 +39,16 @@ namespace OpenIddict.Core
{ {
public OpenIddictAuthorizationManager( public OpenIddictAuthorizationManager(
[NotNull] IOpenIddictAuthorizationCache<TAuthorization> cache, [NotNull] IOpenIddictAuthorizationCache<TAuthorization> cache,
[NotNull] IOpenIddictAuthorizationStoreResolver resolver, [NotNull] IStringLocalizer<OpenIddictResources> localizer,
[NotNull] ILogger<OpenIddictAuthorizationManager<TAuthorization>> logger, [NotNull] ILogger<OpenIddictAuthorizationManager<TAuthorization>> logger,
[NotNull] IOptionsMonitor<OpenIddictCoreOptions> options) [NotNull] IOptionsMonitor<OpenIddictCoreOptions> options,
[NotNull] IOpenIddictAuthorizationStoreResolver resolver)
{ {
Cache = cache; Cache = cache;
Store = resolver.Get<TAuthorization>(); Localizer = localizer;
Logger = logger; Logger = logger;
Options = options; Options = options;
Store = resolver.Get<TAuthorization>();
} }
/// <summary> /// <summary>
@ -51,6 +56,11 @@ namespace OpenIddict.Core
/// </summary> /// </summary>
protected IOpenIddictAuthorizationCache<TAuthorization> Cache { get; } protected IOpenIddictAuthorizationCache<TAuthorization> Cache { get; }
/// <summary>
/// Gets the string localizer associated with the current manager.
/// </summary>
protected IStringLocalizer Localizer { get; }
/// <summary> /// <summary>
/// Gets the logger associated with the current manager. /// Gets the logger associated with the current manager.
/// </summary> /// </summary>
@ -123,7 +133,7 @@ namespace OpenIddict.Core
if (results.Any(result => result != ValidationResult.Success)) if (results.Any(result => result != ValidationResult.Success))
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine("One or more validation error(s) occurred while trying to create a new authorization:"); builder.AppendLine(SR.GetResourceString(SR.ID1218));
builder.AppendLine(); builder.AppendLine();
foreach (var result in results) foreach (var result in results)
@ -174,7 +184,7 @@ namespace OpenIddict.Core
var authorization = await Store.InstantiateAsync(cancellationToken); var authorization = await Store.InstantiateAsync(cancellationToken);
if (authorization == null) if (authorization == null)
{ {
throw new InvalidOperationException("An error occurred while trying to create a new authorization."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1219));
} }
await PopulateAsync(authorization, descriptor, cancellationToken); await PopulateAsync(authorization, descriptor, cancellationToken);
@ -206,17 +216,17 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
var descriptor = new OpenIddictAuthorizationDescriptor var descriptor = new OpenIddictAuthorizationDescriptor
@ -269,12 +279,12 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
var authorizations = Options.CurrentValue.DisableEntityCaching ? var authorizations = Options.CurrentValue.DisableEntityCaching ?
@ -322,17 +332,17 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
var authorizations = Options.CurrentValue.DisableEntityCaching ? var authorizations = Options.CurrentValue.DisableEntityCaching ?
@ -377,22 +387,22 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
var authorizations = Options.CurrentValue.DisableEntityCaching ? var authorizations = Options.CurrentValue.DisableEntityCaching ?
@ -439,22 +449,22 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
var authorizations = Options.CurrentValue.DisableEntityCaching ? var authorizations = Options.CurrentValue.DisableEntityCaching ?
@ -502,7 +512,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var authorizations = Options.CurrentValue.DisableEntityCaching ? var authorizations = Options.CurrentValue.DisableEntityCaching ?
@ -545,7 +555,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var authorization = Options.CurrentValue.DisableEntityCaching ? var authorization = Options.CurrentValue.DisableEntityCaching ?
@ -580,7 +590,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
var authorizations = Options.CurrentValue.DisableEntityCaching ? var authorizations = Options.CurrentValue.DisableEntityCaching ?
@ -810,7 +820,7 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
return string.Equals(await Store.GetStatusAsync(authorization, cancellationToken), status, StringComparison.OrdinalIgnoreCase); return string.Equals(await Store.GetStatusAsync(authorization, cancellationToken), status, StringComparison.OrdinalIgnoreCase);
@ -833,7 +843,7 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
return string.Equals(await Store.GetTypeAsync(authorization, cancellationToken), type, StringComparison.OrdinalIgnoreCase); return string.Equals(await Store.GetTypeAsync(authorization, cancellationToken), type, StringComparison.OrdinalIgnoreCase);
@ -1047,7 +1057,7 @@ namespace OpenIddict.Core
if (results.Any(result => result != ValidationResult.Success)) if (results.Any(result => result != ValidationResult.Success))
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine("One or more validation error(s) occurred while trying to update an existing authorization:"); builder.AppendLine(SR.GetResourceString(SR.ID1220));
builder.AppendLine(); builder.AppendLine();
foreach (var result in results) foreach (var result in results)
@ -1123,18 +1133,18 @@ namespace OpenIddict.Core
var type = await Store.GetTypeAsync(authorization, cancellationToken); var type = await Store.GetTypeAsync(authorization, cancellationToken);
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
yield return new ValidationResult("The authorization type cannot be null or empty."); yield return new ValidationResult(Localizer[SR.ID3116]);
} }
else if (!string.Equals(type, AuthorizationTypes.AdHoc, StringComparison.OrdinalIgnoreCase) && else if (!string.Equals(type, AuthorizationTypes.AdHoc, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(type, AuthorizationTypes.Permanent, StringComparison.OrdinalIgnoreCase)) !string.Equals(type, AuthorizationTypes.Permanent, StringComparison.OrdinalIgnoreCase))
{ {
yield return new ValidationResult("The specified authorization type is not supported by the default token manager."); yield return new ValidationResult(Localizer[SR.ID3117]);
} }
if (string.IsNullOrEmpty(await Store.GetStatusAsync(authorization, cancellationToken))) if (string.IsNullOrEmpty(await Store.GetStatusAsync(authorization, cancellationToken)))
{ {
yield return new ValidationResult("The status cannot be null or empty."); yield return new ValidationResult(Localizer[SR.ID3038]);
} }
// Ensure that the scopes are not null or empty and do not contain spaces. // Ensure that the scopes are not null or empty and do not contain spaces.
@ -1142,14 +1152,14 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(scope)) if (string.IsNullOrEmpty(scope))
{ {
yield return new ValidationResult("Scopes cannot be null or empty."); yield return new ValidationResult(Localizer[SR.ID3039]);
break; break;
} }
if (scope.Contains(Separators.Space[0])) if (scope.Contains(Separators.Space[0]))
{ {
yield return new ValidationResult("Scopes cannot contain spaces."); yield return new ValidationResult(Localizer[SR.ID3042]);
break; break;
} }

36
src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs

@ -15,10 +15,13 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.Abstractions.Resources;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Core namespace OpenIddict.Core
{ {
@ -35,14 +38,16 @@ namespace OpenIddict.Core
{ {
public OpenIddictScopeManager( public OpenIddictScopeManager(
[NotNull] IOpenIddictScopeCache<TScope> cache, [NotNull] IOpenIddictScopeCache<TScope> cache,
[NotNull] IOpenIddictScopeStoreResolver resolver, [NotNull] IStringLocalizer<OpenIddictResources> localizer,
[NotNull] ILogger<OpenIddictScopeManager<TScope>> logger, [NotNull] ILogger<OpenIddictScopeManager<TScope>> logger,
[NotNull] IOptionsMonitor<OpenIddictCoreOptions> options) [NotNull] IOptionsMonitor<OpenIddictCoreOptions> options,
[NotNull] IOpenIddictScopeStoreResolver resolver)
{ {
Cache = cache; Cache = cache;
Store = resolver.Get<TScope>(); Localizer = localizer;
Logger = logger; Logger = logger;
Options = options; Options = options;
Store = resolver.Get<TScope>();
} }
/// <summary> /// <summary>
@ -50,6 +55,11 @@ namespace OpenIddict.Core
/// </summary> /// </summary>
protected IOpenIddictScopeCache<TScope> Cache { get; } protected IOpenIddictScopeCache<TScope> Cache { get; }
/// <summary>
/// Gets the string localizer associated with the current manager.
/// </summary>
protected IStringLocalizer Localizer { get; }
/// <summary> /// <summary>
/// Gets the logger associated with the current manager. /// Gets the logger associated with the current manager.
/// </summary> /// </summary>
@ -116,7 +126,7 @@ namespace OpenIddict.Core
if (results.Any(result => result != ValidationResult.Success)) if (results.Any(result => result != ValidationResult.Success))
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine("One or more validation error(s) occurred while trying to create a new scope:"); builder.AppendLine(SR.GetResourceString(SR.ID1221));
builder.AppendLine(); builder.AppendLine();
foreach (var result in results) foreach (var result in results)
@ -167,7 +177,7 @@ namespace OpenIddict.Core
var scope = await Store.InstantiateAsync(cancellationToken); var scope = await Store.InstantiateAsync(cancellationToken);
if (scope == null) if (scope == null)
{ {
throw new InvalidOperationException("An error occurred while trying to create a new scope."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1222));
} }
await PopulateAsync(scope, descriptor, cancellationToken); await PopulateAsync(scope, descriptor, cancellationToken);
@ -212,7 +222,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var scope = Options.CurrentValue.DisableEntityCaching ? var scope = Options.CurrentValue.DisableEntityCaching ?
@ -249,7 +259,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The scope name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1201), nameof(name));
} }
var scope = Options.CurrentValue.DisableEntityCaching ? var scope = Options.CurrentValue.DisableEntityCaching ?
@ -285,7 +295,7 @@ namespace OpenIddict.Core
{ {
if (names.Any(name => string.IsNullOrEmpty(name))) if (names.Any(name => string.IsNullOrEmpty(name)))
{ {
throw new ArgumentException("Scope names cannot be null or empty.", nameof(names)); throw new ArgumentException(SR.GetResourceString(SR.ID1202), nameof(names));
} }
var scopes = Options.CurrentValue.DisableEntityCaching ? var scopes = Options.CurrentValue.DisableEntityCaching ?
@ -326,7 +336,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(resource)) if (string.IsNullOrEmpty(resource))
{ {
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource)); throw new ArgumentException(SR.GetResourceString(SR.ID1061), nameof(resource));
} }
var scopes = Options.CurrentValue.DisableEntityCaching ? var scopes = Options.CurrentValue.DisableEntityCaching ?
@ -833,7 +843,7 @@ namespace OpenIddict.Core
if (results.Any(result => result != ValidationResult.Success)) if (results.Any(result => result != ValidationResult.Success))
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine("One or more validation error(s) occurred while trying to update an existing scope:"); builder.AppendLine(SR.GetResourceString(SR.ID1223));
builder.AppendLine(); builder.AppendLine();
foreach (var result in results) foreach (var result in results)
@ -911,12 +921,12 @@ namespace OpenIddict.Core
var name = await Store.GetNameAsync(scope, cancellationToken); var name = await Store.GetNameAsync(scope, cancellationToken);
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
yield return new ValidationResult("The scope name cannot be null or empty."); yield return new ValidationResult(Localizer[SR.ID3044]);
} }
else if (name.Contains(Separators.Space[0])) else if (name.Contains(Separators.Space[0]))
{ {
yield return new ValidationResult("The scope name cannot contain spaces."); yield return new ValidationResult(Localizer[SR.ID3045]);
} }
else else
@ -930,7 +940,7 @@ namespace OpenIddict.Core
await Store.GetIdAsync(other, cancellationToken), await Store.GetIdAsync(other, cancellationToken),
await Store.GetIdAsync(scope, cancellationToken), StringComparison.Ordinal)) await Store.GetIdAsync(scope, cancellationToken), StringComparison.Ordinal))
{ {
yield return new ValidationResult("A scope with the same name already exists."); yield return new ValidationResult(Localizer[SR.ID3060]);
} }
} }
} }

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

@ -15,11 +15,14 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.Abstractions.Resources;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Abstractions.OpenIddictExceptions; using static OpenIddict.Abstractions.OpenIddictExceptions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Core namespace OpenIddict.Core
{ {
@ -36,14 +39,16 @@ namespace OpenIddict.Core
{ {
public OpenIddictTokenManager( public OpenIddictTokenManager(
[NotNull] IOpenIddictTokenCache<TToken> cache, [NotNull] IOpenIddictTokenCache<TToken> cache,
[NotNull] IOpenIddictTokenStoreResolver resolver, [NotNull] IStringLocalizer<OpenIddictResources> localizer,
[NotNull] ILogger<OpenIddictTokenManager<TToken>> logger, [NotNull] ILogger<OpenIddictTokenManager<TToken>> logger,
[NotNull] IOptionsMonitor<OpenIddictCoreOptions> options) [NotNull] IOptionsMonitor<OpenIddictCoreOptions> options,
[NotNull] IOpenIddictTokenStoreResolver resolver)
{ {
Cache = cache; Cache = cache;
Store = resolver.Get<TToken>(); Localizer = localizer;
Logger = logger; Logger = logger;
Options = options; Options = options;
Store = resolver.Get<TToken>();
} }
/// <summary> /// <summary>
@ -51,6 +56,11 @@ namespace OpenIddict.Core
/// </summary> /// </summary>
protected IOpenIddictTokenCache<TToken> Cache { get; } protected IOpenIddictTokenCache<TToken> Cache { get; }
/// <summary>
/// Gets the string localizer associated with the current manager.
/// </summary>
protected IStringLocalizer Localizer { get; }
/// <summary> /// <summary>
/// Gets the logger associated with the current manager. /// Gets the logger associated with the current manager.
/// </summary> /// </summary>
@ -131,7 +141,7 @@ namespace OpenIddict.Core
if (results.Any(result => result != ValidationResult.Success)) if (results.Any(result => result != ValidationResult.Success))
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine("One or more validation error(s) occurred while trying to create a new token:"); builder.AppendLine(SR.GetResourceString(SR.ID1224));
builder.AppendLine(); builder.AppendLine();
foreach (var result in results) foreach (var result in results)
@ -182,7 +192,7 @@ namespace OpenIddict.Core
var token = await Store.InstantiateAsync(cancellationToken); var token = await Store.InstantiateAsync(cancellationToken);
if (token == null) if (token == null)
{ {
throw new InvalidOperationException("An error occurred while trying to create a new token"); throw new InvalidOperationException(SR.GetResourceString(SR.ID1225));
} }
await PopulateAsync(token, descriptor, cancellationToken); await PopulateAsync(token, descriptor, cancellationToken);
@ -227,12 +237,12 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
var tokens = Options.CurrentValue.DisableEntityCaching ? var tokens = Options.CurrentValue.DisableEntityCaching ?
@ -276,17 +286,17 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
var tokens = Options.CurrentValue.DisableEntityCaching ? var tokens = Options.CurrentValue.DisableEntityCaching ?
@ -331,22 +341,22 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
var tokens = Options.CurrentValue.DisableEntityCaching ? var tokens = Options.CurrentValue.DisableEntityCaching ?
@ -387,7 +397,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var tokens = Options.CurrentValue.DisableEntityCaching ? var tokens = Options.CurrentValue.DisableEntityCaching ?
@ -428,7 +438,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var tokens = Options.CurrentValue.DisableEntityCaching ? var tokens = Options.CurrentValue.DisableEntityCaching ?
@ -471,7 +481,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var token = Options.CurrentValue.DisableEntityCaching ? var token = Options.CurrentValue.DisableEntityCaching ?
@ -509,7 +519,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
identifier = await ObfuscateReferenceIdAsync(identifier, cancellationToken); identifier = await ObfuscateReferenceIdAsync(identifier, cancellationToken);
@ -547,7 +557,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
var tokens = Options.CurrentValue.DisableEntityCaching ? var tokens = Options.CurrentValue.DisableEntityCaching ?
@ -830,7 +840,7 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
return string.Equals(await Store.GetStatusAsync(token, cancellationToken), status, StringComparison.OrdinalIgnoreCase); return string.Equals(await Store.GetStatusAsync(token, cancellationToken), status, StringComparison.OrdinalIgnoreCase);
@ -852,7 +862,7 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
return string.Equals(await Store.GetTypeAsync(token, cancellationToken), type, StringComparison.OrdinalIgnoreCase); return string.Equals(await Store.GetTypeAsync(token, cancellationToken), type, StringComparison.OrdinalIgnoreCase);
@ -1250,7 +1260,7 @@ namespace OpenIddict.Core
if (results.Any(result => result != ValidationResult.Success)) if (results.Any(result => result != ValidationResult.Success))
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine("One or more validation error(s) occurred while trying to update an existing token:"); builder.AppendLine(SR.GetResourceString(SR.ID1226));
builder.AppendLine(); builder.AppendLine();
foreach (var result in results) foreach (var result in results)
@ -1348,26 +1358,19 @@ namespace OpenIddict.Core
await Store.GetIdAsync(other, cancellationToken), await Store.GetIdAsync(other, cancellationToken),
await Store.GetIdAsync(token, cancellationToken), StringComparison.Ordinal)) await Store.GetIdAsync(token, cancellationToken), StringComparison.Ordinal))
{ {
yield return new ValidationResult("A token with the same reference identifier already exists."); yield return new ValidationResult(Localizer[SR.ID3085]);
} }
} }
var type = await Store.GetTypeAsync(token, cancellationToken); var type = await Store.GetTypeAsync(token, cancellationToken);
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
yield return new ValidationResult("The token type cannot be null or empty."); yield return new ValidationResult(Localizer[SR.ID3086]);
} }
if (string.IsNullOrEmpty(await Store.GetStatusAsync(token, cancellationToken))) if (string.IsNullOrEmpty(await Store.GetStatusAsync(token, cancellationToken)))
{ {
yield return new ValidationResult("The status cannot be null or empty."); yield return new ValidationResult(Localizer[SR.ID3038]);
}
if (string.IsNullOrEmpty(await Store.GetSubjectAsync(token, cancellationToken)) &&
!string.Equals(type, TokenTypeHints.DeviceCode, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(type, TokenTypeHints.UserCode, StringComparison.OrdinalIgnoreCase))
{
yield return new ValidationResult("The subject cannot be null or empty.");
} }
} }
@ -1384,7 +1387,7 @@ namespace OpenIddict.Core
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
// Compute the digest of the generated identifier and use it as the hashed identifier of the reference token. // Compute the digest of the generated identifier and use it as the hashed identifier of the reference token.

1
src/OpenIddict.Core/OpenIddict.Core.csproj

@ -15,6 +15,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" />
<PackageReference Include="Microsoft.Extensions.Localization" />
<PackageReference Include="Microsoft.Extensions.Logging" /> <PackageReference Include="Microsoft.Extensions.Logging" />
<PackageReference Include="Microsoft.Extensions.Options" /> <PackageReference Include="Microsoft.Extensions.Options" />
</ItemGroup> </ItemGroup>

51
src/OpenIddict.Core/OpenIddictCoreBuilder.cs

@ -11,6 +11,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.Core; using OpenIddict.Core;
using OpenIddict.Extensions; using OpenIddict.Extensions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
@ -83,7 +84,7 @@ namespace Microsoft.Extensions.DependencyInjection
var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(IOpenIddictApplicationStore<>)); var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(IOpenIddictApplicationStore<>));
if (root == null) if (root == null)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
// Note: managers can be either open generics (e.g OpenIddictApplicationStore<>) // Note: managers can be either open generics (e.g OpenIddictApplicationStore<>)
@ -92,7 +93,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (type.GetGenericArguments().Length != 1) if (type.GetGenericArguments().Length != 1)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
Services.Replace(new ServiceDescriptor(typeof(IOpenIddictApplicationStore<>), type, lifetime)); Services.Replace(new ServiceDescriptor(typeof(IOpenIddictApplicationStore<>), type, lifetime));
@ -140,7 +141,7 @@ namespace Microsoft.Extensions.DependencyInjection
var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(IOpenIddictAuthorizationStore<>)); var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(IOpenIddictAuthorizationStore<>));
if (root == null) if (root == null)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
// Note: managers can be either open generics (e.g OpenIddictAuthorizationStore<>) // Note: managers can be either open generics (e.g OpenIddictAuthorizationStore<>)
@ -149,7 +150,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (type.GetGenericArguments().Length != 1) if (type.GetGenericArguments().Length != 1)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
Services.Replace(new ServiceDescriptor(typeof(IOpenIddictAuthorizationStore<>), type, lifetime)); Services.Replace(new ServiceDescriptor(typeof(IOpenIddictAuthorizationStore<>), type, lifetime));
@ -197,7 +198,7 @@ namespace Microsoft.Extensions.DependencyInjection
var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(IOpenIddictScopeStore<>)); var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(IOpenIddictScopeStore<>));
if (root == null) if (root == null)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
// Note: managers can be either open generics (e.g OpenIddictScopeStore<>) // Note: managers can be either open generics (e.g OpenIddictScopeStore<>)
@ -206,7 +207,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (type.GetGenericArguments().Length != 1) if (type.GetGenericArguments().Length != 1)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
Services.Replace(new ServiceDescriptor(typeof(IOpenIddictScopeStore<>), type, lifetime)); Services.Replace(new ServiceDescriptor(typeof(IOpenIddictScopeStore<>), type, lifetime));
@ -254,7 +255,7 @@ namespace Microsoft.Extensions.DependencyInjection
var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(IOpenIddictTokenStore<>)); var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(IOpenIddictTokenStore<>));
if (root == null) if (root == null)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
// Note: managers can be either open generics (e.g OpenIddictTokenStore<>) // Note: managers can be either open generics (e.g OpenIddictTokenStore<>)
@ -263,7 +264,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (type.GetGenericArguments().Length != 1) if (type.GetGenericArguments().Length != 1)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
Services.Replace(new ServiceDescriptor(typeof(IOpenIddictTokenStore<>), type, lifetime)); Services.Replace(new ServiceDescriptor(typeof(IOpenIddictTokenStore<>), type, lifetime));
@ -308,7 +309,7 @@ namespace Microsoft.Extensions.DependencyInjection
var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(OpenIddictApplicationManager<>)); var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(OpenIddictApplicationManager<>));
if (root == null) if (root == null)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
// Note: managers can be either open generics (e.g OpenIddictApplicationManager<>) // Note: managers can be either open generics (e.g OpenIddictApplicationManager<>)
@ -317,7 +318,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (type.GetGenericArguments().Length != 1) if (type.GetGenericArguments().Length != 1)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
Services.Replace(ServiceDescriptor.Scoped(type, type)); Services.Replace(ServiceDescriptor.Scoped(type, type));
@ -364,7 +365,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (!typeof(IOpenIddictApplicationStoreResolver).IsAssignableFrom(type)) if (!typeof(IOpenIddictApplicationStoreResolver).IsAssignableFrom(type))
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
Services.Replace(new ServiceDescriptor(typeof(IOpenIddictApplicationStoreResolver), type, lifetime)); Services.Replace(new ServiceDescriptor(typeof(IOpenIddictApplicationStoreResolver), type, lifetime));
@ -402,7 +403,7 @@ namespace Microsoft.Extensions.DependencyInjection
var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(OpenIddictAuthorizationManager<>)); var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(OpenIddictAuthorizationManager<>));
if (root == null) if (root == null)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
// Note: managers can be either open generics (e.g OpenIddictAuthorizationManager<>) // Note: managers can be either open generics (e.g OpenIddictAuthorizationManager<>)
@ -411,7 +412,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (type.GetGenericArguments().Length != 1) if (type.GetGenericArguments().Length != 1)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
Services.Replace(ServiceDescriptor.Scoped(type, type)); Services.Replace(ServiceDescriptor.Scoped(type, type));
@ -458,7 +459,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (!typeof(IOpenIddictAuthorizationStoreResolver).IsAssignableFrom(type)) if (!typeof(IOpenIddictAuthorizationStoreResolver).IsAssignableFrom(type))
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
Services.Replace(new ServiceDescriptor(typeof(IOpenIddictAuthorizationStoreResolver), type, lifetime)); Services.Replace(new ServiceDescriptor(typeof(IOpenIddictAuthorizationStoreResolver), type, lifetime));
@ -496,7 +497,7 @@ namespace Microsoft.Extensions.DependencyInjection
var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(OpenIddictScopeManager<>)); var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(OpenIddictScopeManager<>));
if (root == null) if (root == null)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
// Note: managers can be either open generics (e.g OpenIddictScopeManager<>) // Note: managers can be either open generics (e.g OpenIddictScopeManager<>)
@ -505,7 +506,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (type.GetGenericArguments().Length != 1) if (type.GetGenericArguments().Length != 1)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
Services.Replace(ServiceDescriptor.Scoped(type, type)); Services.Replace(ServiceDescriptor.Scoped(type, type));
@ -552,7 +553,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (!typeof(IOpenIddictScopeStoreResolver).IsAssignableFrom(type)) if (!typeof(IOpenIddictScopeStoreResolver).IsAssignableFrom(type))
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
Services.Replace(new ServiceDescriptor(typeof(IOpenIddictScopeStoreResolver), type, lifetime)); Services.Replace(new ServiceDescriptor(typeof(IOpenIddictScopeStoreResolver), type, lifetime));
@ -590,7 +591,7 @@ namespace Microsoft.Extensions.DependencyInjection
var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(OpenIddictTokenManager<>)); var root = OpenIddictHelpers.FindGenericBaseType(type, typeof(OpenIddictTokenManager<>));
if (root == null) if (root == null)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
// Note: managers can be either open generics (e.g OpenIddictTokenManager<>) // Note: managers can be either open generics (e.g OpenIddictTokenManager<>)
@ -599,7 +600,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (type.GetGenericArguments().Length != 1) if (type.GetGenericArguments().Length != 1)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
Services.Replace(ServiceDescriptor.Scoped(type, type)); Services.Replace(ServiceDescriptor.Scoped(type, type));
@ -646,7 +647,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (!typeof(IOpenIddictTokenStoreResolver).IsAssignableFrom(type)) if (!typeof(IOpenIddictTokenStoreResolver).IsAssignableFrom(type))
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
Services.Replace(new ServiceDescriptor(typeof(IOpenIddictTokenStoreResolver), type, lifetime)); Services.Replace(new ServiceDescriptor(typeof(IOpenIddictTokenStoreResolver), type, lifetime));
@ -695,7 +696,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (type.IsValueType) if (type.IsValueType)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
return Configure(options => options.DefaultApplicationType = type); return Configure(options => options.DefaultApplicationType = type);
@ -722,7 +723,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (type.IsValueType) if (type.IsValueType)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
return Configure(options => options.DefaultAuthorizationType = type); return Configure(options => options.DefaultAuthorizationType = type);
@ -749,7 +750,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (type.IsValueType) if (type.IsValueType)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
return Configure(options => options.DefaultScopeType = type); return Configure(options => options.DefaultScopeType = type);
@ -776,7 +777,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (type.IsValueType) if (type.IsValueType)
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
return Configure(options => options.DefaultTokenType = type); return Configure(options => options.DefaultTokenType = type);
@ -792,7 +793,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (limit < 10) if (limit < 10)
{ {
throw new ArgumentException("The cache size cannot be less than 10.", nameof(limit)); throw new ArgumentException(SR.GetResourceString(SR.ID1232), nameof(limit));
} }
return Configure(options => options.EntityCacheLimit = limit); return Configure(options => options.EntityCacheLimit = limit);

19
src/OpenIddict.Core/OpenIddictCoreExtensions.cs

@ -8,12 +8,16 @@ using System;
using System.Text; using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging.Abstractions;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.Abstractions.Resources;
using OpenIddict.Core; using OpenIddict.Core;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
using Microsoft.Extensions.Options;
/// <summary> /// <summary>
/// Exposes extensions allowing to register the OpenIddict core services. /// Exposes extensions allowing to register the OpenIddict core services.
/// </summary> /// </summary>
@ -32,6 +36,7 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentNullException(nameof(builder)); throw new ArgumentNullException(nameof(builder));
} }
builder.Services.AddLocalization();
builder.Services.AddLogging(); builder.Services.AddLogging();
builder.Services.AddMemoryCache(); builder.Services.AddMemoryCache();
builder.Services.AddOptions(); builder.Services.AddOptions();
@ -119,6 +124,18 @@ namespace Microsoft.Extensions.DependencyInjection
typeof(OpenIddictTokenManager<>).MakeGenericType(options.DefaultTokenType)); typeof(OpenIddictTokenManager<>).MakeGenericType(options.DefaultTokenType));
}); });
builder.Services.TryAddSingleton<IStringLocalizer<OpenIddictResources>>(provider =>
{
// Note: the string localizer factory is deliberately not resolved from
// the DI container to ensure the built-in .resx files are always used
// even if the factory was replaced by a different implementation in DI.
var factory = new ResourceManagerStringLocalizerFactory(
localizationOptions: Options.Create(new LocalizationOptions()),
loggerFactory: NullLoggerFactory.Instance);
return new StringLocalizer<OpenIddictResources>(factory);
});
return new OpenIddictCoreBuilder(builder.Services); return new OpenIddictCoreBuilder(builder.Services);
} }

19
src/OpenIddict.Core/Resolvers/OpenIddictApplicationStoreResolver.cs

@ -1,8 +1,8 @@
using System; using System;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Core namespace OpenIddict.Core
{ {
@ -23,20 +23,7 @@ namespace OpenIddict.Core
/// <typeparam name="TApplication">The type of the Application entity.</typeparam> /// <typeparam name="TApplication">The type of the Application entity.</typeparam>
/// <returns>An <see cref="IOpenIddictApplicationStore{TApplication}"/>.</returns> /// <returns>An <see cref="IOpenIddictApplicationStore{TApplication}"/>.</returns>
public IOpenIddictApplicationStore<TApplication> Get<TApplication>() where TApplication : class public IOpenIddictApplicationStore<TApplication> Get<TApplication>() where TApplication : class
{ => _provider.GetService<IOpenIddictApplicationStore<TApplication>>() ??
var store = _provider.GetService<IOpenIddictApplicationStore<TApplication>>(); throw new InvalidOperationException(SR.GetResourceString(SR.ID1227));
if (store == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("No application store has been registered in the dependency injection container.")
.Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ")
.AppendLine("package and call 'services.AddOpenIddict().AddCore().UseEntityFrameworkCore()'.")
.Append("To register a custom store, create an implementation of 'IOpenIddictApplicationStore' and ")
.Append("use 'services.AddOpenIddict().AddCore().AddApplicationStore()' to add it to the DI container.")
.ToString());
}
return store;
}
} }
} }

19
src/OpenIddict.Core/Resolvers/OpenIddictAuthorizationStoreResolver.cs

@ -1,8 +1,8 @@
using System; using System;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Core namespace OpenIddict.Core
{ {
@ -23,20 +23,7 @@ namespace OpenIddict.Core
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam> /// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
/// <returns>An <see cref="IOpenIddictAuthorizationStore{TAuthorization}"/>.</returns> /// <returns>An <see cref="IOpenIddictAuthorizationStore{TAuthorization}"/>.</returns>
public IOpenIddictAuthorizationStore<TAuthorization> Get<TAuthorization>() where TAuthorization : class public IOpenIddictAuthorizationStore<TAuthorization> Get<TAuthorization>() where TAuthorization : class
{ => _provider.GetService<IOpenIddictAuthorizationStore<TAuthorization>>() ??
var store = _provider.GetService<IOpenIddictAuthorizationStore<TAuthorization>>(); throw new InvalidOperationException(SR.GetResourceString(SR.ID1228));
if (store == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("No authorization store has been registered in the dependency injection container.")
.Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ")
.AppendLine("package and call 'services.AddOpenIddict().AddCore().UseEntityFrameworkCore()'.")
.Append("To register a custom store, create an implementation of 'IOpenIddictAuthorizationStore' and ")
.Append("use 'services.AddOpenIddict().AddCore().AddAuthorizationStore()' to add it to the DI container.")
.ToString());
}
return store;
}
} }
} }

19
src/OpenIddict.Core/Resolvers/OpenIddictScopeStoreResolver.cs

@ -1,8 +1,8 @@
using System; using System;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Core namespace OpenIddict.Core
{ {
@ -23,20 +23,7 @@ namespace OpenIddict.Core
/// <typeparam name="TScope">The type of the Scope entity.</typeparam> /// <typeparam name="TScope">The type of the Scope entity.</typeparam>
/// <returns>An <see cref="IOpenIddictScopeStore{TScope}"/>.</returns> /// <returns>An <see cref="IOpenIddictScopeStore{TScope}"/>.</returns>
public IOpenIddictScopeStore<TScope> Get<TScope>() where TScope : class public IOpenIddictScopeStore<TScope> Get<TScope>() where TScope : class
{ => _provider.GetService<IOpenIddictScopeStore<TScope>>() ??
var store = _provider.GetService<IOpenIddictScopeStore<TScope>>(); throw new InvalidOperationException(SR.GetResourceString(SR.ID1229));
if (store == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("No scope store has been registered in the dependency injection container.")
.Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ")
.AppendLine("package and call 'services.AddOpenIddict().AddCore().UseEntityFrameworkCore()'.")
.Append("To register a custom store, create an implementation of 'IOpenIddictScopeStore' and ")
.Append("use 'services.AddOpenIddict().AddCore().AddScopeStore()' to add it to the DI container.")
.ToString());
}
return store;
}
} }
} }

19
src/OpenIddict.Core/Resolvers/OpenIddictTokenStoreResolver.cs

@ -1,8 +1,8 @@
using System; using System;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Core namespace OpenIddict.Core
{ {
@ -23,20 +23,7 @@ namespace OpenIddict.Core
/// <typeparam name="TToken">The type of the Token entity.</typeparam> /// <typeparam name="TToken">The type of the Token entity.</typeparam>
/// <returns>An <see cref="IOpenIddictTokenStore{TToken}"/>.</returns> /// <returns>An <see cref="IOpenIddictTokenStore{TToken}"/>.</returns>
public IOpenIddictTokenStore<TToken> Get<TToken>() where TToken : class public IOpenIddictTokenStore<TToken> Get<TToken>() where TToken : class
{ => _provider.GetService<IOpenIddictTokenStore<TToken>>() ??
var store = _provider.GetService<IOpenIddictTokenStore<TToken>>(); throw new InvalidOperationException(SR.GetResourceString(SR.ID1230));
if (store == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("No token store has been registered in the dependency injection container.")
.Append("To register the Entity Framework Core stores, reference the 'OpenIddict.EntityFrameworkCore' ")
.AppendLine("package and call 'services.AddOpenIddict().AddCore().UseEntityFrameworkCore()'.")
.Append("To register a custom store, create an implementation of 'IOpenIddictTokenStore' and ")
.Append("use 'services.AddOpenIddict().AddCore().AddTokenStore()' to add it to the DI container.")
.ToString());
}
return store;
}
} }
} }

3
src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkBuilder.cs

@ -13,6 +13,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenIddict.Core; using OpenIddict.Core;
using OpenIddict.EntityFramework; using OpenIddict.EntityFramework;
using OpenIddict.EntityFramework.Models; using OpenIddict.EntityFramework.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
@ -111,7 +112,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (!typeof(DbContext).IsAssignableFrom(type)) if (!typeof(DbContext).IsAssignableFrom(type))
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
Services.TryAddScoped(type); Services.TryAddScoped(type);

15
src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkApplicationStoreResolver.cs

@ -6,13 +6,13 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFramework.Models; using OpenIddict.EntityFramework.Models;
using OpenIddict.Extensions; using OpenIddict.Extensions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFramework namespace OpenIddict.EntityFramework
{ {
@ -54,22 +54,13 @@ namespace OpenIddict.EntityFramework
var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkApplication<,,>)); var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkApplication<,,>));
if (root == null) if (root == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1233));
.AppendLine("The specified application type is not compatible with the Entity Framework 6.x stores.")
.Append("When enabling the Entity Framework 6.x stores, make sure you use the built-in ")
.Append("'OpenIddictEntityFrameworkApplication' entity or a custom entity that inherits ")
.Append("from the generic 'OpenIddictEntityFrameworkApplication' entity.")
.ToString());
} }
var context = _options.CurrentValue.DbContextType; var context = _options.CurrentValue.DbContextType;
if (context == null) if (context == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1234));
.AppendLine("No Entity Framework 6.x context was specified in the OpenIddict options.")
.Append("To configure the OpenIddict Entity Framework 6.x stores to use a specific 'DbContext', ")
.Append("use 'options.UseEntityFramework().UseDbContext<TContext>()'.")
.ToString());
} }
return typeof(OpenIddictEntityFrameworkApplicationStore<,,,,>).MakeGenericType( return typeof(OpenIddictEntityFrameworkApplicationStore<,,,,>).MakeGenericType(

15
src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkAuthorizationStoreResolver.cs

@ -6,13 +6,13 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFramework.Models; using OpenIddict.EntityFramework.Models;
using OpenIddict.Extensions; using OpenIddict.Extensions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFramework namespace OpenIddict.EntityFramework
{ {
@ -54,22 +54,13 @@ namespace OpenIddict.EntityFramework
var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkAuthorization<,,>)); var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkAuthorization<,,>));
if (root == null) if (root == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1235));
.AppendLine("The specified authorization type is not compatible with the Entity Framework 6.x stores.")
.Append("When enabling the Entity Framework 6.x stores, make sure you use the built-in ")
.Append("'OpenIddictEntityFrameworkAuthorization' entity or a custom entity that inherits ")
.Append("from the generic 'OpenIddictEntityFrameworkAuthorization' entity.")
.ToString());
} }
var context = _options.CurrentValue.DbContextType; var context = _options.CurrentValue.DbContextType;
if (context == null) if (context == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1234));
.AppendLine("No Entity Framework 6.x context was specified in the OpenIddict options.")
.Append("To configure the OpenIddict Entity Framework 6.x stores to use a specific 'DbContext', ")
.Append("use 'options.UseEntityFramework().UseDbContext<TContext>()'.")
.ToString());
} }
return typeof(OpenIddictEntityFrameworkAuthorizationStore<,,,,>).MakeGenericType( return typeof(OpenIddictEntityFrameworkAuthorizationStore<,,,,>).MakeGenericType(

15
src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkScopeStoreResolver.cs

@ -6,13 +6,13 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFramework.Models; using OpenIddict.EntityFramework.Models;
using OpenIddict.Extensions; using OpenIddict.Extensions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFramework namespace OpenIddict.EntityFramework
{ {
@ -54,22 +54,13 @@ namespace OpenIddict.EntityFramework
var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkScope<>)); var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkScope<>));
if (root == null) if (root == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1236));
.AppendLine("The specified scope type is not compatible with the Entity Framework 6.x stores.")
.Append("When enabling the Entity Framework 6.x stores, make sure you use the built-in ")
.Append("'OpenIddictEntityFrameworkScope' entity or a custom entity that inherits ")
.Append("from the generic 'OpenIddictEntityFrameworkScope' entity.")
.ToString());
} }
var context = _options.CurrentValue.DbContextType; var context = _options.CurrentValue.DbContextType;
if (context == null) if (context == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1234));
.AppendLine("No Entity Framework 6.x context was specified in the OpenIddict options.")
.Append("To configure the OpenIddict Entity Framework 6.x stores to use a specific 'DbContext', ")
.Append("use 'options.UseEntityFramework().UseDbContext<TContext>()'.")
.ToString());
} }
return typeof(OpenIddictEntityFrameworkScopeStore<,,>).MakeGenericType( return typeof(OpenIddictEntityFrameworkScopeStore<,,>).MakeGenericType(

15
src/OpenIddict.EntityFramework/Resolvers/OpenIddictEntityFrameworkTokenStoreResolver.cs

@ -6,13 +6,13 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFramework.Models; using OpenIddict.EntityFramework.Models;
using OpenIddict.Extensions; using OpenIddict.Extensions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFramework namespace OpenIddict.EntityFramework
{ {
@ -54,22 +54,13 @@ namespace OpenIddict.EntityFramework
var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkToken<,,>)); var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkToken<,,>));
if (root == null) if (root == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1237));
.AppendLine("The specified token type is not compatible with the Entity Framework 6.x stores.")
.Append("When enabling the Entity Framework 6.x stores, make sure you use the built-in ")
.Append("'OpenIddictEntityFrameworkToken' entity or a custom entity that inherits ")
.Append("from the generic 'OpenIddictEntityFrameworkToken' entity.")
.ToString());
} }
var context = _options.CurrentValue.DbContextType; var context = _options.CurrentValue.DbContextType;
if (context == null) if (context == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1234));
.AppendLine("No Entity Framework 6.x context was specified in the OpenIddict options.")
.Append("To configure the OpenIddict Entity Framework 6.x stores to use a specific 'DbContext', ")
.Append("use 'options.UseEntityFramework().UseDbContext<TContext>()'.")
.ToString());
} }
return typeof(OpenIddictEntityFrameworkTokenStore<,,,,>).MakeGenericType( return typeof(OpenIddictEntityFrameworkTokenStore<,,,,>).MakeGenericType(

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

@ -25,6 +25,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFramework.Models; using OpenIddict.EntityFramework.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFramework namespace OpenIddict.EntityFramework
{ {
@ -236,10 +237,7 @@ namespace OpenIddict.EntityFramework
Context.Entry(token).State = EntityState.Unchanged; Context.Entry(token).State = EntityState.Unchanged;
} }
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1238), exception);
.AppendLine("The application was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the application from the database and retry the operation.")
.ToString(), exception);
} }
} }
@ -256,7 +254,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
@ -279,7 +277,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
return await (from application in Applications return await (from application in Applications
@ -298,7 +296,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("The address cannot be null or empty.", nameof(address)); throw new ArgumentException(SR.GetResourceString(SR.ID1142), nameof(address));
} }
// To optimize the efficiency of the query a bit, only applications whose stringified // To optimize the efficiency of the query a bit, only applications whose stringified
@ -337,7 +335,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("The address cannot be null or empty.", nameof(address)); throw new ArgumentException(SR.GetResourceString(SR.ID1142), nameof(address));
} }
// To optimize the efficiency of the query a bit, only applications whose stringified // To optimize the efficiency of the query a bit, only applications whose stringified
@ -734,11 +732,7 @@ namespace OpenIddict.EntityFramework
catch (MemberAccessException exception) catch (MemberAccessException exception)
{ {
return new ValueTask<TApplication>(Task.FromException<TApplication>( return new ValueTask<TApplication>(Task.FromException<TApplication>(
new InvalidOperationException(new StringBuilder() new InvalidOperationException(SR.GetResourceString(SR.ID1239), exception)));
.AppendLine("An error occurred while trying to create a new application instance.")
.Append("Make sure that the application entity is not abstract and has a public parameterless constructor ")
.Append("or create a custom application store that overrides 'InstantiateAsync()' to use a custom factory.")
.ToString(), exception)));
} }
} }
@ -1119,10 +1113,7 @@ namespace OpenIddict.EntityFramework
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing. // Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(application).State = EntityState.Unchanged; Context.Entry(application).State = EntityState.Unchanged;
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1238), exception);
.AppendLine("The application was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the application from the database and retry the operation.")
.ToString(), exception);
} }
} }

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

@ -13,7 +13,6 @@ using System.Data.Entity;
using System.Data.Entity.Infrastructure; using System.Data.Entity.Infrastructure;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
@ -23,6 +22,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFramework.Models; using OpenIddict.EntityFramework.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFramework namespace OpenIddict.EntityFramework
{ {
@ -210,10 +210,7 @@ namespace OpenIddict.EntityFramework
Context.Entry(token).State = EntityState.Unchanged; Context.Entry(token).State = EntityState.Unchanged;
} }
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1240), exception);
.AppendLine("The authorization was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the authorization from the database and retry the operation.")
.ToString(), exception);
} }
} }
@ -230,12 +227,12 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
var key = ConvertIdentifierFromString(client); var key = ConvertIdentifierFromString(client);
@ -261,17 +258,17 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
var key = ConvertIdentifierFromString(client); var key = ConvertIdentifierFromString(client);
@ -299,22 +296,22 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
var key = ConvertIdentifierFromString(client); var key = ConvertIdentifierFromString(client);
@ -345,22 +342,22 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -398,7 +395,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
@ -421,7 +418,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
@ -442,7 +439,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
return (from authorization in Authorizations.Include(authorization => authorization.Application) return (from authorization in Authorizations.Include(authorization => authorization.Application)
@ -675,11 +672,7 @@ namespace OpenIddict.EntityFramework
catch (MemberAccessException exception) catch (MemberAccessException exception)
{ {
return new ValueTask<TAuthorization>(Task.FromException<TAuthorization>( return new ValueTask<TAuthorization>(Task.FromException<TAuthorization>(
new InvalidOperationException(new StringBuilder() new InvalidOperationException(SR.GetResourceString(SR.ID1241), exception)));
.AppendLine("An error occurred while trying to create a new authorization instance.")
.Append("Make sure that the authorization entity is not abstract and has a public parameterless constructor ")
.Append("or create a custom authorization store that overrides 'InstantiateAsync()' to use a custom factory.")
.ToString(), exception)));
} }
} }
@ -810,7 +803,7 @@ namespace OpenIddict.EntityFramework
if (exceptions != null) if (exceptions != null)
{ {
throw new AggregateException("An error occurred while pruning authorizations.", exceptions); throw new AggregateException(SR.GetResourceString(SR.ID1242), exceptions);
} }
} }
@ -836,7 +829,7 @@ namespace OpenIddict.EntityFramework
var application = await Applications.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier)); var application = await Applications.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier));
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The application associated with the authorization cannot be found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1243));
} }
authorization.Application = application; authorization.Application = application;
@ -1025,10 +1018,7 @@ namespace OpenIddict.EntityFramework
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing. // Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(authorization).State = EntityState.Unchanged; Context.Entry(authorization).State = EntityState.Unchanged;
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1240), exception);
.AppendLine("The authorization was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the authorization from the database and retry the operation.")
.ToString(), exception);
} }
} }

25
src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkScopeStore.cs

@ -24,6 +24,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFramework.Models; using OpenIddict.EntityFramework.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFramework namespace OpenIddict.EntityFramework
{ {
@ -159,10 +160,7 @@ namespace OpenIddict.EntityFramework
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing. // Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(scope).State = EntityState.Unchanged; Context.Entry(scope).State = EntityState.Unchanged;
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1244), exception);
.AppendLine("The scope was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the scope from the database and retry the operation.")
.ToString(), exception);
} }
} }
@ -179,7 +177,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
@ -202,7 +200,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The scope name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1201), nameof(name));
} }
return await (from scope in Scopes return await (from scope in Scopes
@ -221,7 +219,7 @@ namespace OpenIddict.EntityFramework
{ {
if (names.Any(name => string.IsNullOrEmpty(name))) if (names.Any(name => string.IsNullOrEmpty(name)))
{ {
throw new ArgumentException("Scope names cannot be null or empty.", nameof(names)); throw new ArgumentException(SR.GetResourceString(SR.ID1202), nameof(names));
} }
// Note: Enumerable.Contains() is deliberately used without the extension method syntax to ensure // Note: Enumerable.Contains() is deliberately used without the extension method syntax to ensure
@ -242,7 +240,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(resource)) if (string.IsNullOrEmpty(resource))
{ {
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource)); throw new ArgumentException(SR.GetResourceString(SR.ID1061), nameof(resource));
} }
// To optimize the efficiency of the query a bit, only scopes whose stringified // To optimize the efficiency of the query a bit, only scopes whose stringified
@ -530,11 +528,7 @@ namespace OpenIddict.EntityFramework
catch (MemberAccessException exception) catch (MemberAccessException exception)
{ {
return new ValueTask<TScope>(Task.FromException<TScope>( return new ValueTask<TScope>(Task.FromException<TScope>(
new InvalidOperationException(new StringBuilder() new InvalidOperationException(SR.GetResourceString(SR.ID1245), exception)));
.AppendLine("An error occurred while trying to create a new scope instance.")
.Append("Make sure that the scope entity is not abstract and has a public parameterless constructor ")
.Append("or create a custom scope store that overrides 'InstantiateAsync()' to use a custom factory.")
.ToString(), exception)));
} }
} }
@ -823,10 +817,7 @@ namespace OpenIddict.EntityFramework
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing. // Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(scope).State = EntityState.Unchanged; Context.Entry(scope).State = EntityState.Unchanged;
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1244), exception);
.AppendLine("The scope was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the scope from the database and retry the operation.")
.ToString(), exception);
} }
} }

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

@ -12,7 +12,6 @@ using System.Data;
using System.Data.Entity; using System.Data.Entity;
using System.Data.Entity.Infrastructure; using System.Data.Entity.Infrastructure;
using System.Linq; using System.Linq;
using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
@ -22,6 +21,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFramework.Models; using OpenIddict.EntityFramework.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFramework namespace OpenIddict.EntityFramework
{ {
@ -173,10 +173,7 @@ namespace OpenIddict.EntityFramework
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing. // Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged; Context.Entry(token).State = EntityState.Unchanged;
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1246), exception);
.AppendLine("The token was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the token from the database and retry the operation.")
.ToString(), exception);
} }
} }
@ -193,12 +190,12 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
var key = ConvertIdentifierFromString(client); var key = ConvertIdentifierFromString(client);
@ -224,17 +221,17 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
var key = ConvertIdentifierFromString(client); var key = ConvertIdentifierFromString(client);
@ -262,22 +259,22 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
var key = ConvertIdentifierFromString(client); var key = ConvertIdentifierFromString(client);
@ -301,7 +298,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
@ -322,7 +319,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
@ -346,7 +343,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
@ -370,7 +367,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
return await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization) return await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
@ -388,7 +385,7 @@ namespace OpenIddict.EntityFramework
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization) return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
@ -701,11 +698,7 @@ namespace OpenIddict.EntityFramework
catch (MemberAccessException exception) catch (MemberAccessException exception)
{ {
return new ValueTask<TToken>(Task.FromException<TToken>( return new ValueTask<TToken>(Task.FromException<TToken>(
new InvalidOperationException(new StringBuilder() new InvalidOperationException(SR.GetResourceString(SR.ID1247), exception)));
.AppendLine("An error occurred while trying to create a new token instance.")
.Append("Make sure that the token entity is not abstract and has a public parameterless constructor ")
.Append("or create a custom token store that overrides 'InstantiateAsync()' to use a custom factory.")
.ToString(), exception)));
} }
} }
@ -833,7 +826,7 @@ namespace OpenIddict.EntityFramework
if (exceptions != null) if (exceptions != null)
{ {
throw new AggregateException("An error occurred while pruning tokens.", exceptions); throw new AggregateException(SR.GetResourceString(SR.ID1248), exceptions);
} }
} }
@ -857,7 +850,7 @@ namespace OpenIddict.EntityFramework
var application = await Applications.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier)); var application = await Applications.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier));
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The application associated with the token cannot be found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1249));
} }
token.Application = application; token.Application = application;
@ -901,7 +894,7 @@ namespace OpenIddict.EntityFramework
var authorization = await Authorizations.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier)); var authorization = await Authorizations.FindAsync(cancellationToken, ConvertIdentifierFromString(identifier));
if (authorization == null) if (authorization == null)
{ {
throw new InvalidOperationException("The authorization associated with the token cannot be found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1250));
} }
token.Authorization = authorization; token.Authorization = authorization;
@ -1124,10 +1117,7 @@ namespace OpenIddict.EntityFramework
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing. // Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged; Context.Entry(token).State = EntityState.Unchanged;
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1246), exception);
.AppendLine("The token was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the token from the database and retry the operation.")
.ToString(), exception);
} }
} }

3
src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreBuilder.cs

@ -11,6 +11,7 @@ using Microsoft.EntityFrameworkCore;
using OpenIddict.Core; using OpenIddict.Core;
using OpenIddict.EntityFrameworkCore; using OpenIddict.EntityFrameworkCore;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
@ -108,7 +109,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (!typeof(DbContext).IsAssignableFrom(type)) if (!typeof(DbContext).IsAssignableFrom(type))
{ {
throw new ArgumentException("The specified type is invalid.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1231), nameof(type));
} }
return Configure(options => options.DbContextType = type); return Configure(options => options.DbContextType = type);

15
src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreApplicationStoreResolver.cs

@ -6,13 +6,13 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
using OpenIddict.Extensions; using OpenIddict.Extensions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFrameworkCore namespace OpenIddict.EntityFrameworkCore
{ {
@ -54,22 +54,13 @@ namespace OpenIddict.EntityFrameworkCore
var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkCoreApplication<,,>)); var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkCoreApplication<,,>));
if (root == null) if (root == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1251));
.AppendLine("The specified application type is not compatible with the Entity Framework Core stores.")
.Append("When enabling the Entity Framework Core stores, make sure you use the built-in ")
.Append("'OpenIddictEntityFrameworkCoreApplication' entity or a custom entity that inherits ")
.Append("from the generic 'OpenIddictEntityFrameworkCoreApplication' entity.")
.ToString());
} }
var context = _options.CurrentValue.DbContextType; var context = _options.CurrentValue.DbContextType;
if (context == null) if (context == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1252));
.AppendLine("No Entity Framework Core context was specified in the OpenIddict options.")
.Append("To configure the OpenIddict Entity Framework Core stores to use a specific 'DbContext', ")
.Append("use 'options.UseEntityFrameworkCore().UseDbContext<TContext>()'.")
.ToString());
} }
return typeof(OpenIddictEntityFrameworkCoreApplicationStore<,,,,>).MakeGenericType( return typeof(OpenIddictEntityFrameworkCoreApplicationStore<,,,,>).MakeGenericType(

15
src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreAuthorizationStoreResolver.cs

@ -6,13 +6,13 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
using OpenIddict.Extensions; using OpenIddict.Extensions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFrameworkCore namespace OpenIddict.EntityFrameworkCore
{ {
@ -54,22 +54,13 @@ namespace OpenIddict.EntityFrameworkCore
var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkCoreAuthorization<,,>)); var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkCoreAuthorization<,,>));
if (root == null) if (root == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1253));
.AppendLine("The specified authorization type is not compatible with the Entity Framework Core stores.")
.Append("When enabling the Entity Framework Core stores, make sure you use the built-in ")
.Append("'OpenIddictEntityFrameworkCoreAuthorization' entity or a custom entity that inherits ")
.Append("from the generic 'OpenIddictEntityFrameworkCoreAuthorization' entity.")
.ToString());
} }
var context = _options.CurrentValue.DbContextType; var context = _options.CurrentValue.DbContextType;
if (context == null) if (context == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1252));
.AppendLine("No Entity Framework Core context was specified in the OpenIddict options.")
.Append("To configure the OpenIddict Entity Framework Core stores to use a specific 'DbContext', ")
.Append("use 'options.UseEntityFrameworkCore().UseDbContext<TContext>()'.")
.ToString());
} }
return typeof(OpenIddictEntityFrameworkCoreAuthorizationStore<,,,,>).MakeGenericType( return typeof(OpenIddictEntityFrameworkCoreAuthorizationStore<,,,,>).MakeGenericType(

15
src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreScopeStoreResolver.cs

@ -6,13 +6,13 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
using OpenIddict.Extensions; using OpenIddict.Extensions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFrameworkCore namespace OpenIddict.EntityFrameworkCore
{ {
@ -54,22 +54,13 @@ namespace OpenIddict.EntityFrameworkCore
var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkCoreScope<>)); var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkCoreScope<>));
if (root == null) if (root == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1254));
.AppendLine("The specified scope type is not compatible with the Entity Framework Core stores.")
.Append("When enabling the Entity Framework Core stores, make sure you use the built-in ")
.Append("'OpenIddictEntityFrameworkCoreScope' entity or a custom entity that inherits ")
.Append("from the generic 'OpenIddictEntityFrameworkCoreScope' entity.")
.ToString());
} }
var context = _options.CurrentValue.DbContextType; var context = _options.CurrentValue.DbContextType;
if (context == null) if (context == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1252));
.AppendLine("No Entity Framework Core context was specified in the OpenIddict options.")
.Append("To configure the OpenIddict Entity Framework Core stores to use a specific 'DbContext', ")
.Append("use 'options.UseEntityFrameworkCore().UseDbContext<TContext>()'.")
.ToString());
} }
return typeof(OpenIddictEntityFrameworkCoreScopeStore<,,>).MakeGenericType( return typeof(OpenIddictEntityFrameworkCoreScopeStore<,,>).MakeGenericType(

15
src/OpenIddict.EntityFrameworkCore/Resolvers/OpenIddictEntityFrameworkCoreTokenStoreResolver.cs

@ -6,13 +6,13 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
using OpenIddict.Extensions; using OpenIddict.Extensions;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFrameworkCore namespace OpenIddict.EntityFrameworkCore
{ {
@ -54,22 +54,13 @@ namespace OpenIddict.EntityFrameworkCore
var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkCoreToken<,,>)); var root = OpenIddictHelpers.FindGenericBaseType(key, typeof(OpenIddictEntityFrameworkCoreToken<,,>));
if (root == null) if (root == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1255));
.AppendLine("The specified token type is not compatible with the Entity Framework Core stores.")
.Append("When enabling the Entity Framework Core stores, make sure you use the built-in ")
.Append("'OpenIddictEntityFrameworkCoreToken' entity or a custom entity that inherits ")
.Append("from the generic 'OpenIddictEntityFrameworkCoreToken' entity.")
.ToString());
} }
var context = _options.CurrentValue.DbContextType; var context = _options.CurrentValue.DbContextType;
if (context == null) if (context == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1252));
.AppendLine("No Entity Framework Core context was specified in the OpenIddict options.")
.Append("To configure the OpenIddict Entity Framework Core stores to use a specific 'DbContext', ")
.Append("use 'options.UseEntityFrameworkCore().UseDbContext<TContext>()'.")
.ToString());
} }
return typeof(OpenIddictEntityFrameworkCoreTokenStore<,,,,>).MakeGenericType( return typeof(OpenIddictEntityFrameworkCoreTokenStore<,,,,>).MakeGenericType(

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

@ -26,6 +26,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFrameworkCore namespace OpenIddict.EntityFrameworkCore
{ {
@ -280,10 +281,7 @@ namespace OpenIddict.EntityFrameworkCore
Context.Entry(token).State = EntityState.Unchanged; Context.Entry(token).State = EntityState.Unchanged;
} }
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1238), exception);
.AppendLine("The application was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the application from the database and retry the operation.")
.ToString(), exception);
} }
} }
@ -300,7 +298,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
return await (from application in Applications.AsTracking() return await (from application in Applications.AsTracking()
@ -321,7 +319,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
@ -342,7 +340,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("The address cannot be null or empty.", nameof(address)); throw new ArgumentException(SR.GetResourceString(SR.ID1142), nameof(address));
} }
// To optimize the efficiency of the query a bit, only applications whose stringified // To optimize the efficiency of the query a bit, only applications whose stringified
@ -381,7 +379,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("The address cannot be null or empty.", nameof(address)); throw new ArgumentException(SR.GetResourceString(SR.ID1142), nameof(address));
} }
// To optimize the efficiency of the query a bit, only applications whose stringified // To optimize the efficiency of the query a bit, only applications whose stringified
@ -778,11 +776,7 @@ namespace OpenIddict.EntityFrameworkCore
catch (MemberAccessException exception) catch (MemberAccessException exception)
{ {
return new ValueTask<TApplication>(Task.FromException<TApplication>( return new ValueTask<TApplication>(Task.FromException<TApplication>(
new InvalidOperationException(new StringBuilder() new InvalidOperationException(SR.GetResourceString(SR.ID1239), exception)));
.AppendLine("An error occurred while trying to create a new application instance.")
.Append("Make sure that the application entity is not abstract and has a public parameterless constructor ")
.Append("or create a custom application store that overrides 'InstantiateAsync()' to use a custom factory.")
.ToString(), exception)));
} }
} }
@ -1163,10 +1157,7 @@ namespace OpenIddict.EntityFrameworkCore
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing. // Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(application).State = EntityState.Unchanged; Context.Entry(application).State = EntityState.Unchanged;
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1238), exception);
.AppendLine("The application was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the application from the database and retry the operation.")
.ToString(), exception);
} }
} }

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

@ -11,7 +11,6 @@ using System.ComponentModel;
using System.Data; using System.Data;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
@ -24,6 +23,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFrameworkCore namespace OpenIddict.EntityFrameworkCore
{ {
@ -248,10 +248,7 @@ namespace OpenIddict.EntityFrameworkCore
Context.Entry(token).State = EntityState.Unchanged; Context.Entry(token).State = EntityState.Unchanged;
} }
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1240), exception);
.AppendLine("The authorization was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the authorization from the database and retry the operation.")
.ToString(), exception);
} }
} }
@ -268,12 +265,12 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be // Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
@ -304,17 +301,17 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be // Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
@ -346,22 +343,22 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be // Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
@ -397,22 +394,22 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -455,7 +452,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be // Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
@ -481,7 +478,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
@ -502,7 +499,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
return (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking() return (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
@ -736,11 +733,7 @@ namespace OpenIddict.EntityFrameworkCore
catch (MemberAccessException exception) catch (MemberAccessException exception)
{ {
return new ValueTask<TAuthorization>(Task.FromException<TAuthorization>( return new ValueTask<TAuthorization>(Task.FromException<TAuthorization>(
new InvalidOperationException(new StringBuilder() new InvalidOperationException(SR.GetResourceString(SR.ID1241), exception)));
.AppendLine("An error occurred while trying to create a new authorization instance.")
.Append("Make sure that the authorization entity is not abstract and has a public parameterless constructor ")
.Append("or create a custom authorization store that overrides 'InstantiateAsync()' to use a custom factory.")
.ToString(), exception)));
} }
} }
@ -883,7 +876,7 @@ namespace OpenIddict.EntityFrameworkCore
if (exceptions != null) if (exceptions != null)
{ {
throw new AggregateException("An error occurred while pruning authorizations.", exceptions); throw new AggregateException(SR.GetResourceString(SR.ID1242), exceptions);
} }
} }
@ -913,7 +906,7 @@ namespace OpenIddict.EntityFrameworkCore
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The application associated with the authorization cannot be found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1243));
} }
authorization.Application = application; authorization.Application = application;
@ -1090,10 +1083,7 @@ namespace OpenIddict.EntityFrameworkCore
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing. // Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(authorization).State = EntityState.Unchanged; Context.Entry(authorization).State = EntityState.Unchanged;
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1240), exception);
.AppendLine("The authorization was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the authorization from the database and retry the operation.")
.ToString(), exception);
} }
} }

25
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreScopeStore.cs

@ -23,6 +23,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFrameworkCore namespace OpenIddict.EntityFrameworkCore
{ {
@ -175,10 +176,7 @@ namespace OpenIddict.EntityFrameworkCore
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing. // Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(scope).State = EntityState.Unchanged; Context.Entry(scope).State = EntityState.Unchanged;
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1244), exception);
.AppendLine("The scope was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the scope from the database and retry the operation.")
.ToString(), exception);
} }
} }
@ -195,7 +193,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
@ -218,7 +216,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The scope name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1201), nameof(name));
} }
return await (from scope in Scopes.AsTracking() return await (from scope in Scopes.AsTracking()
@ -237,7 +235,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (names.Any(name => string.IsNullOrEmpty(name))) if (names.Any(name => string.IsNullOrEmpty(name)))
{ {
throw new ArgumentException("Scope names cannot be null or empty.", nameof(names)); throw new ArgumentException(SR.GetResourceString(SR.ID1202), nameof(names));
} }
// Note: Enumerable.Contains() is deliberately used without the extension method syntax to ensure // Note: Enumerable.Contains() is deliberately used without the extension method syntax to ensure
@ -258,7 +256,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(resource)) if (string.IsNullOrEmpty(resource))
{ {
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource)); throw new ArgumentException(SR.GetResourceString(SR.ID1061), nameof(resource));
} }
// To optimize the efficiency of the query a bit, only scopes whose stringified // To optimize the efficiency of the query a bit, only scopes whose stringified
@ -546,11 +544,7 @@ namespace OpenIddict.EntityFrameworkCore
catch (MemberAccessException exception) catch (MemberAccessException exception)
{ {
return new ValueTask<TScope>(Task.FromException<TScope>( return new ValueTask<TScope>(Task.FromException<TScope>(
new InvalidOperationException(new StringBuilder() new InvalidOperationException(SR.GetResourceString(SR.ID1245), exception)));
.AppendLine("An error occurred while trying to create a new scope instance.")
.Append("Make sure that the scope entity is not abstract and has a public parameterless constructor ")
.Append("or create a custom scope store that overrides 'InstantiateAsync()' to use a custom factory.")
.ToString(), exception)));
} }
} }
@ -839,10 +833,7 @@ namespace OpenIddict.EntityFrameworkCore
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing. // Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(scope).State = EntityState.Unchanged; Context.Entry(scope).State = EntityState.Unchanged;
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1244), exception);
.AppendLine("The scope was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the scope from the database and retry the operation.")
.ToString(), exception);
} }
} }

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

@ -10,7 +10,6 @@ using System.Collections.Immutable;
using System.ComponentModel; using System.ComponentModel;
using System.Data; using System.Data;
using System.Linq; using System.Linq;
using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
@ -23,6 +22,7 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.EntityFrameworkCore namespace OpenIddict.EntityFrameworkCore
{ {
@ -195,10 +195,7 @@ namespace OpenIddict.EntityFrameworkCore
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing. // Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged; Context.Entry(token).State = EntityState.Unchanged;
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1246), exception);
.AppendLine("The token was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the token from the database and retry the operation.")
.ToString(), exception);
} }
} }
@ -215,12 +212,12 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be // Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
@ -251,17 +248,17 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be // Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
@ -294,22 +291,22 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be // Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
@ -338,7 +335,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
// Note: due to a bug in Entity Framework Core's query visitor, the tokens can't be // Note: due to a bug in Entity Framework Core's query visitor, the tokens can't be
@ -364,7 +361,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
// Note: due to a bug in Entity Framework Core's query visitor, the tokens can't be // Note: due to a bug in Entity Framework Core's query visitor, the tokens can't be
@ -393,7 +390,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var key = ConvertIdentifierFromString(identifier); var key = ConvertIdentifierFromString(identifier);
@ -417,7 +414,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
return await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() return await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
@ -435,7 +432,7 @@ namespace OpenIddict.EntityFrameworkCore
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
@ -749,11 +746,7 @@ namespace OpenIddict.EntityFrameworkCore
catch (MemberAccessException exception) catch (MemberAccessException exception)
{ {
return new ValueTask<TToken>(Task.FromException<TToken>( return new ValueTask<TToken>(Task.FromException<TToken>(
new InvalidOperationException(new StringBuilder() new InvalidOperationException(SR.GetResourceString(SR.ID1247), exception)));
.AppendLine("An error occurred while trying to create a new token instance.")
.Append("Make sure that the token entity is not abstract and has a public parameterless constructor ")
.Append("or create a custom token store that overrides 'InstantiateAsync()' to use a custom factory.")
.ToString(), exception)));
} }
} }
@ -892,7 +885,7 @@ namespace OpenIddict.EntityFrameworkCore
if (exceptions != null) if (exceptions != null)
{ {
throw new AggregateException("An error occurred while pruning tokens.", exceptions); throw new AggregateException(SR.GetResourceString(SR.ID1248), exceptions);
} }
} }
@ -924,7 +917,7 @@ namespace OpenIddict.EntityFrameworkCore
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The application associated with the token cannot be found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1249));
} }
token.Application = application; token.Application = application;
@ -976,7 +969,7 @@ namespace OpenIddict.EntityFrameworkCore
if (authorization == null) if (authorization == null)
{ {
throw new InvalidOperationException("The authorization associated with the token cannot be found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1250));
} }
token.Authorization = authorization; token.Authorization = authorization;
@ -1217,10 +1210,7 @@ namespace OpenIddict.EntityFrameworkCore
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing. // Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged; Context.Entry(token).State = EntityState.Unchanged;
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1246), exception);
.AppendLine("The token was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the token from the database and retry the operation.")
.ToString(), exception);
} }
} }

9
src/OpenIddict.MongoDb/OpenIddictMongoDbBuilder.cs

@ -11,6 +11,7 @@ using MongoDB.Driver;
using OpenIddict.Core; using OpenIddict.Core;
using OpenIddict.MongoDb; using OpenIddict.MongoDb;
using OpenIddict.MongoDb.Models; using OpenIddict.MongoDb.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
@ -107,7 +108,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The collection name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1260), nameof(name));
} }
return Configure(options => options.ApplicationsCollectionName = name); return Configure(options => options.ApplicationsCollectionName = name);
@ -122,7 +123,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The collection name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1260), nameof(name));
} }
return Configure(options => options.AuthorizationsCollectionName = name); return Configure(options => options.AuthorizationsCollectionName = name);
@ -137,7 +138,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The collection name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1260), nameof(name));
} }
return Configure(options => options.ScopesCollectionName = name); return Configure(options => options.ScopesCollectionName = name);
@ -152,7 +153,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The collection name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1260), nameof(name));
} }
return Configure(options => options.TokensCollectionName = name); return Configure(options => options.TokensCollectionName = name);

9
src/OpenIddict.MongoDb/OpenIddictMongoDbContext.cs

@ -5,13 +5,13 @@
*/ */
using System; using System;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using MongoDB.Driver; using MongoDB.Driver;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.MongoDb namespace OpenIddict.MongoDb
{ {
@ -54,12 +54,7 @@ namespace OpenIddict.MongoDb
if (database == null) if (database == null)
{ {
return new ValueTask<IMongoDatabase>(Task.FromException<IMongoDatabase>( return new ValueTask<IMongoDatabase>(Task.FromException<IMongoDatabase>(
new InvalidOperationException(new StringBuilder() new InvalidOperationException(SR.GetResourceString(SR.ID1261))));
.AppendLine("No suitable MongoDB database service can be found.")
.Append("To configure the OpenIddict MongoDB stores to use a specific database, use ")
.Append("'services.AddOpenIddict().AddCore().UseMongoDb().UseDatabase()' or register an ")
.Append("'IMongoDatabase' in the dependency injection container in 'ConfigureServices()'.")
.ToString())));
} }
return new ValueTask<IMongoDatabase>(database); return new ValueTask<IMongoDatabase>(database);

1
src/OpenIddict.MongoDb/OpenIddictMongoDbOptions.cs

@ -4,7 +4,6 @@
* the license and the contributors participating to this project. * the license and the contributors participating to this project.
*/ */
using System;
using MongoDB.Driver; using MongoDB.Driver;
namespace OpenIddict.MongoDb namespace OpenIddict.MongoDb

9
src/OpenIddict.MongoDb/Resolvers/OpenIddictMongoDbApplicationStoreResolver.cs

@ -6,11 +6,11 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.MongoDb.Models; using OpenIddict.MongoDb.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.MongoDb namespace OpenIddict.MongoDb
{ {
@ -43,12 +43,7 @@ namespace OpenIddict.MongoDb
{ {
if (!typeof(OpenIddictMongoDbApplication).IsAssignableFrom(key)) if (!typeof(OpenIddictMongoDbApplication).IsAssignableFrom(key))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1256));
.AppendLine("The specified application type is not compatible with the MongoDB stores.")
.Append("When enabling the MongoDB stores, make sure you use the built-in ")
.Append("'OpenIddictMongoDbApplication' entity or a custom entity that inherits ")
.Append("from the 'OpenIddictMongoDbApplication' entity.")
.ToString());
} }
return typeof(OpenIddictMongoDbApplicationStore<>).MakeGenericType(key); return typeof(OpenIddictMongoDbApplicationStore<>).MakeGenericType(key);

9
src/OpenIddict.MongoDb/Resolvers/OpenIddictMongoDbAuthorizationStoreResolver.cs

@ -6,11 +6,11 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.MongoDb.Models; using OpenIddict.MongoDb.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.MongoDb namespace OpenIddict.MongoDb
{ {
@ -43,12 +43,7 @@ namespace OpenIddict.MongoDb
{ {
if (!typeof(OpenIddictMongoDbAuthorization).IsAssignableFrom(key)) if (!typeof(OpenIddictMongoDbAuthorization).IsAssignableFrom(key))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1257));
.AppendLine("The specified authorization type is not compatible with the MongoDB stores.")
.Append("When enabling the MongoDB stores, make sure you use the built-in ")
.Append("'OpenIddictMongoDbAuthorization' entity or a custom entity that inherits ")
.Append("from the 'OpenIddictMongoDbAuthorization' entity.")
.ToString());
} }
return typeof(OpenIddictMongoDbAuthorizationStore<>).MakeGenericType(key); return typeof(OpenIddictMongoDbAuthorizationStore<>).MakeGenericType(key);

9
src/OpenIddict.MongoDb/Resolvers/OpenIddictMongoDbScopeStoreResolver.cs

@ -6,11 +6,11 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.MongoDb.Models; using OpenIddict.MongoDb.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.MongoDb namespace OpenIddict.MongoDb
{ {
@ -43,12 +43,7 @@ namespace OpenIddict.MongoDb
{ {
if (!typeof(OpenIddictMongoDbScope).IsAssignableFrom(key)) if (!typeof(OpenIddictMongoDbScope).IsAssignableFrom(key))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1258));
.AppendLine("The specified scope type is not compatible with the MongoDB stores.")
.Append("When enabling the MongoDB stores, make sure you use the built-in ")
.Append("'OpenIddictMongoDbScope' entity or a custom entity that inherits ")
.Append("from the 'OpenIddictMongoDbScope' entity.")
.ToString());
} }
return typeof(OpenIddictMongoDbScopeStore<>).MakeGenericType(key); return typeof(OpenIddictMongoDbScopeStore<>).MakeGenericType(key);

9
src/OpenIddict.MongoDb/Resolvers/OpenIddictMongoDbTokenStoreResolver.cs

@ -6,11 +6,11 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.MongoDb.Models; using OpenIddict.MongoDb.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.MongoDb namespace OpenIddict.MongoDb
{ {
@ -43,12 +43,7 @@ namespace OpenIddict.MongoDb
{ {
if (!typeof(OpenIddictMongoDbToken).IsAssignableFrom(key)) if (!typeof(OpenIddictMongoDbToken).IsAssignableFrom(key))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1259));
.AppendLine("The specified token type is not compatible with the MongoDB stores.")
.Append("When enabling the MongoDB stores, make sure you use the built-in ")
.Append("'OpenIddictMongoDbToken' entity or a custom entity that inherits ")
.Append("from the 'OpenIddictMongoDbToken' entity.")
.ToString());
} }
return typeof(OpenIddictMongoDbTokenStore<>).MakeGenericType(key); return typeof(OpenIddictMongoDbTokenStore<>).MakeGenericType(key);

26
src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbApplicationStore.cs

@ -10,7 +10,6 @@ using System.Collections.Immutable;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
@ -22,6 +21,7 @@ using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.MongoDb.Models; using OpenIddict.MongoDb.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.MongoDb namespace OpenIddict.MongoDb
{ {
@ -129,10 +129,7 @@ namespace OpenIddict.MongoDb
entity.Id == application.Id && entity.Id == application.Id &&
entity.ConcurrencyToken == application.ConcurrencyToken)).DeletedCount == 0) entity.ConcurrencyToken == application.ConcurrencyToken)).DeletedCount == 0)
{ {
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1238));
.AppendLine("The application was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the application from the database and retry the operation.")
.ToString());
} }
// Delete the authorizations associated with the application. // Delete the authorizations associated with the application.
@ -157,7 +154,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var database = await Context.GetDatabaseAsync(cancellationToken); var database = await Context.GetDatabaseAsync(cancellationToken);
@ -179,7 +176,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var database = await Context.GetDatabaseAsync(cancellationToken); var database = await Context.GetDatabaseAsync(cancellationToken);
@ -200,7 +197,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("The address cannot be null or empty.", nameof(address)); throw new ArgumentException(SR.GetResourceString(SR.ID1142), nameof(address));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -229,7 +226,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("The address cannot be null or empty.", nameof(address)); throw new ArgumentException(SR.GetResourceString(SR.ID1142), nameof(address));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -556,11 +553,7 @@ namespace OpenIddict.MongoDb
catch (MemberAccessException exception) catch (MemberAccessException exception)
{ {
return new ValueTask<TApplication>(Task.FromException<TApplication>( return new ValueTask<TApplication>(Task.FromException<TApplication>(
new InvalidOperationException(new StringBuilder() new InvalidOperationException(SR.GetResourceString(SR.ID1239), exception)));
.AppendLine("An error occurred while trying to create a new application instance.")
.Append("Make sure that the application entity is not abstract and has a public parameterless constructor ")
.Append("or create a custom application store that overrides 'InstantiateAsync()' to use a custom factory.")
.ToString(), exception)));
} }
} }
@ -912,10 +905,7 @@ namespace OpenIddict.MongoDb
entity.Id == application.Id && entity.Id == application.Id &&
entity.ConcurrencyToken == timestamp, application, null as ReplaceOptions, cancellationToken)).MatchedCount == 0) entity.ConcurrencyToken == timestamp, application, null as ReplaceOptions, cancellationToken)).MatchedCount == 0)
{ {
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1238));
.AppendLine("The application was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the application from the database and retry the operation.")
.ToString());
} }
} }
} }

50
src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbAuthorizationStore.cs

@ -9,7 +9,6 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
@ -21,6 +20,7 @@ using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.MongoDb.Models; using OpenIddict.MongoDb.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.MongoDb namespace OpenIddict.MongoDb
{ {
@ -128,10 +128,7 @@ namespace OpenIddict.MongoDb
entity.Id == authorization.Id && entity.Id == authorization.Id &&
entity.ConcurrencyToken == authorization.ConcurrencyToken)).DeletedCount == 0) entity.ConcurrencyToken == authorization.ConcurrencyToken)).DeletedCount == 0)
{ {
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1240));
.AppendLine("The authorization was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the authorization from the database and retry the operation.")
.ToString());
} }
// Delete the tokens associated with the authorization. // Delete the tokens associated with the authorization.
@ -152,12 +149,12 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -190,17 +187,17 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -235,22 +232,22 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -288,22 +285,22 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -338,7 +335,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -369,7 +366,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var database = await Context.GetDatabaseAsync(cancellationToken); var database = await Context.GetDatabaseAsync(cancellationToken);
@ -390,7 +387,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -598,11 +595,7 @@ namespace OpenIddict.MongoDb
catch (MemberAccessException exception) catch (MemberAccessException exception)
{ {
return new ValueTask<TAuthorization>(Task.FromException<TAuthorization>( return new ValueTask<TAuthorization>(Task.FromException<TAuthorization>(
new InvalidOperationException(new StringBuilder() new InvalidOperationException(SR.GetResourceString(SR.ID1241), exception)));
.AppendLine("An error occurred while trying to create a new authorization instance.")
.Append("Make sure that the authorization entity is not abstract and has a public parameterless constructor ")
.Append("or create a custom authorization store that overrides 'InstantiateAsync()' to use a custom factory.")
.ToString(), exception)));
} }
} }
@ -903,10 +896,7 @@ namespace OpenIddict.MongoDb
entity.Id == authorization.Id && entity.Id == authorization.Id &&
entity.ConcurrencyToken == timestamp, authorization, null as ReplaceOptions, cancellationToken)).MatchedCount == 0) entity.ConcurrencyToken == timestamp, authorization, null as ReplaceOptions, cancellationToken)).MatchedCount == 0)
{ {
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1240));
.AppendLine("The authorization was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the authorization from the database and retry the operation.")
.ToString());
} }
} }
} }

26
src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbScopeStore.cs

@ -10,7 +10,6 @@ using System.Collections.Immutable;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
@ -22,6 +21,7 @@ using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.MongoDb.Models; using OpenIddict.MongoDb.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.MongoDb namespace OpenIddict.MongoDb
{ {
@ -129,10 +129,7 @@ namespace OpenIddict.MongoDb
entity.Id == scope.Id && entity.Id == scope.Id &&
entity.ConcurrencyToken == scope.ConcurrencyToken)).DeletedCount == 0) entity.ConcurrencyToken == scope.ConcurrencyToken)).DeletedCount == 0)
{ {
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1244));
.AppendLine("The scope was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the scope from the database and retry the operation.")
.ToString());
} }
} }
@ -149,7 +146,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var database = await Context.GetDatabaseAsync(cancellationToken); var database = await Context.GetDatabaseAsync(cancellationToken);
@ -171,7 +168,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The scope name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1201), nameof(name));
} }
var database = await Context.GetDatabaseAsync(cancellationToken); var database = await Context.GetDatabaseAsync(cancellationToken);
@ -191,7 +188,7 @@ namespace OpenIddict.MongoDb
{ {
if (names.Any(name => string.IsNullOrEmpty(name))) if (names.Any(name => string.IsNullOrEmpty(name)))
{ {
throw new ArgumentException("Scope names cannot be null or empty.", nameof(names)); throw new ArgumentException(SR.GetResourceString(SR.ID1202), nameof(names));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -221,7 +218,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(resource)) if (string.IsNullOrEmpty(resource))
{ {
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource)); throw new ArgumentException(SR.GetResourceString(SR.ID1061), nameof(resource));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -456,11 +453,7 @@ namespace OpenIddict.MongoDb
catch (MemberAccessException exception) catch (MemberAccessException exception)
{ {
return new ValueTask<TScope>(Task.FromException<TScope>( return new ValueTask<TScope>(Task.FromException<TScope>(
new InvalidOperationException(new StringBuilder() new InvalidOperationException(SR.GetResourceString(SR.ID1245), exception)));
.AppendLine("An error occurred while trying to create a new scope instance.")
.Append("Make sure that the scope entity is not abstract and has a public parameterless constructor ")
.Append("or create a custom scope store that overrides 'InstantiateAsync()' to use a custom factory.")
.ToString(), exception)));
} }
} }
@ -706,10 +699,7 @@ namespace OpenIddict.MongoDb
entity.Id == scope.Id && entity.Id == scope.Id &&
entity.ConcurrencyToken == timestamp, scope, null as ReplaceOptions, cancellationToken)).MatchedCount == 0) entity.ConcurrencyToken == timestamp, scope, null as ReplaceOptions, cancellationToken)).MatchedCount == 0)
{ {
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1244));
.AppendLine("The scope was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the scope from the database and retry the operation.")
.ToString());
} }
} }
} }

46
src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbTokenStore.cs

@ -9,7 +9,6 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
@ -21,6 +20,7 @@ using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using OpenIddict.MongoDb.Models; using OpenIddict.MongoDb.Models;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.MongoDb namespace OpenIddict.MongoDb
{ {
@ -128,10 +128,7 @@ namespace OpenIddict.MongoDb
entity.Id == token.Id && entity.Id == token.Id &&
entity.ConcurrencyToken == token.ConcurrencyToken)).DeletedCount == 0) entity.ConcurrencyToken == token.ConcurrencyToken)).DeletedCount == 0)
{ {
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1246));
.AppendLine("The token was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the token from the database and retry the operation.")
.ToString());
} }
} }
@ -148,12 +145,12 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -186,17 +183,17 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -231,22 +228,22 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (string.IsNullOrEmpty(client))
{ {
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); throw new ArgumentException(SR.GetResourceString(SR.ID1123), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); throw new ArgumentException(SR.GetResourceString(SR.ID1198), nameof(status));
} }
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1199), nameof(type));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -278,7 +275,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -307,7 +304,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -338,7 +335,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var database = await Context.GetDatabaseAsync(cancellationToken); var database = await Context.GetDatabaseAsync(cancellationToken);
@ -361,7 +358,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(identifier)) if (string.IsNullOrEmpty(identifier))
{ {
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); throw new ArgumentException(SR.GetResourceString(SR.ID1194), nameof(identifier));
} }
var database = await Context.GetDatabaseAsync(cancellationToken); var database = await Context.GetDatabaseAsync(cancellationToken);
@ -380,7 +377,7 @@ namespace OpenIddict.MongoDb
{ {
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); throw new ArgumentException(SR.GetResourceString(SR.ID1197), nameof(subject));
} }
return ExecuteAsync(cancellationToken); return ExecuteAsync(cancellationToken);
@ -659,11 +656,7 @@ namespace OpenIddict.MongoDb
catch (MemberAccessException exception) catch (MemberAccessException exception)
{ {
return new ValueTask<TToken>(Task.FromException<TToken>( return new ValueTask<TToken>(Task.FromException<TToken>(
new InvalidOperationException(new StringBuilder() new InvalidOperationException(SR.GetResourceString(SR.ID1247), exception)));
.AppendLine("An error occurred while trying to create a new token instance.")
.Append("Make sure that the token entity is not abstract and has a public parameterless constructor ")
.Append("or create a custom token store that overrides 'InstantiateAsync()' to use a custom factory.")
.ToString(), exception)));
} }
} }
@ -993,10 +986,7 @@ namespace OpenIddict.MongoDb
entity.Id == token.Id && entity.Id == token.Id &&
entity.ConcurrencyToken == timestamp, token, null as ReplaceOptions, cancellationToken)).MatchedCount == 0) entity.ConcurrencyToken == timestamp, token, null as ReplaceOptions, cancellationToken)).MatchedCount == 0)
{ {
throw new OpenIddictExceptions.ConcurrencyException(new StringBuilder() throw new OpenIddictExceptions.ConcurrencyException(SR.GetResourceString(SR.ID1246));
.AppendLine("The token was concurrently updated and cannot be persisted in its current state.")
.Append("Reload the token from the database and retry the operation.")
.ToString());
} }
} }
} }

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

@ -11,6 +11,7 @@ using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Distributed;
using OpenIddict.Server.AspNetCore; using OpenIddict.Server.AspNetCore;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
@ -158,7 +159,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (string.IsNullOrEmpty(realm)) if (string.IsNullOrEmpty(realm))
{ {
throw new ArgumentException("The realm cannot be null or empty.", nameof(realm)); throw new ArgumentException(SR.GetResourceString(SR.ID1106), nameof(realm));
} }
return Configure(options => options.Realm = realm); return Configure(options => options.Realm = realm);

18
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreConfiguration.cs

@ -6,10 +6,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server.AspNetCore namespace OpenIddict.Server.AspNetCore
{ {
@ -36,10 +36,7 @@ namespace OpenIddict.Server.AspNetCore
if (options.SchemeMap.TryGetValue(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, out var builder) && if (options.SchemeMap.TryGetValue(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, out var builder) &&
builder.HandlerType != typeof(OpenIddictServerAspNetCoreHandler)) builder.HandlerType != typeof(OpenIddictServerAspNetCoreHandler))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1107));
.AppendLine("The OpenIddict ASP.NET Core server handler cannot be registered as an authentication scheme.")
.Append("This may indicate that an instance of another handler was registered with the same scheme.")
.ToString());
} }
options.AddScheme<OpenIddictServerAspNetCoreHandler>( options.AddScheme<OpenIddictServerAspNetCoreHandler>(
@ -87,12 +84,7 @@ namespace OpenIddict.Server.AspNetCore
!TryValidate(options.SchemeMap, options.DefaultSignInScheme) || !TryValidate(options.SchemeMap, options.DefaultSignInScheme) ||
!TryValidate(options.SchemeMap, options.DefaultSignOutScheme)) !TryValidate(options.SchemeMap, options.DefaultSignOutScheme))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1108));
.AppendLine("The OpenIddict ASP.NET Core server cannot be used as the default scheme handler.")
.Append("Make sure that neither DefaultAuthenticateScheme, DefaultChallengeScheme, ")
.Append("DefaultForbidScheme, DefaultSignInScheme, DefaultSignOutScheme nor DefaultScheme ")
.Append("point to an instance of the OpenIddict ASP.NET Core server handler.")
.ToString());
} }
} }
@ -111,9 +103,7 @@ namespace OpenIddict.Server.AspNetCore
if (options.EnableErrorPassthrough && options.EnableStatusCodePagesIntegration) if (options.EnableErrorPassthrough && options.EnableStatusCodePagesIntegration)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1109));
.Append("The error pass-through mode cannot be used when the status code pages integration is enabled.")
.ToString());
} }
} }
} }

36
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandler.cs

@ -7,7 +7,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Claims; using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
@ -18,6 +17,7 @@ using Microsoft.Extensions.Options;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server.AspNetCore namespace OpenIddict.Server.AspNetCore
{ {
@ -101,11 +101,7 @@ namespace OpenIddict.Server.AspNetCore
return false; return false;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1110));
.Append("The OpenID Connect response was not correctly processed. This may indicate ")
.Append("that the event handler responsible of processing OpenID Connect responses ")
.Append("was not registered or was explicitly removed from the handlers list.")
.ToString());
} }
return false; return false;
@ -114,7 +110,7 @@ namespace OpenIddict.Server.AspNetCore
protected override async Task<AuthenticateResult> HandleAuthenticateAsync() protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{ {
var transaction = Context.Features.Get<OpenIddictServerAspNetCoreFeature>()?.Transaction ?? var transaction = Context.Features.Get<OpenIddictServerAspNetCoreFeature>()?.Transaction ??
throw new InvalidOperationException("An unknown error occurred while retrieving the OpenIddict server context."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1111));
// Note: in many cases, the authentication token was already validated by the time this action is called // Note: in many cases, the authentication token was already validated by the time this action is called
// (generally later in the pipeline, when using the pass-through mode). To avoid having to re-validate it, // (generally later in the pipeline, when using the pass-through mode). To avoid having to re-validate it,
@ -152,7 +148,7 @@ namespace OpenIddict.Server.AspNetCore
[OpenIddictServerAspNetCoreConstants.Properties.ErrorUri] = context.ErrorUri [OpenIddictServerAspNetCoreConstants.Properties.ErrorUri] = context.ErrorUri
}); });
return AuthenticateResult.Fail("An error occurred while authenticating the current request.", properties); return AuthenticateResult.Fail(SR.GetResourceString(SR.ID1112), properties);
} }
else else
@ -178,7 +174,7 @@ namespace OpenIddict.Server.AspNetCore
protected override async Task HandleChallengeAsync([CanBeNull] AuthenticationProperties properties) protected override async Task HandleChallengeAsync([CanBeNull] AuthenticationProperties properties)
{ {
var transaction = Context.Features.Get<OpenIddictServerAspNetCoreFeature>()?.Transaction ?? var transaction = Context.Features.Get<OpenIddictServerAspNetCoreFeature>()?.Transaction ??
throw new InvalidOperationException("An unknown error occurred while retrieving the OpenIddict server context."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1111));
transaction.Properties[typeof(AuthenticationProperties).FullName] = properties ?? new AuthenticationProperties(); transaction.Properties[typeof(AuthenticationProperties).FullName] = properties ?? new AuthenticationProperties();
@ -213,11 +209,7 @@ namespace OpenIddict.Server.AspNetCore
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1110));
.Append("The OpenID Connect response was not correctly processed. This may indicate ")
.Append("that the event handler responsible of processing OpenID Connect responses ")
.Append("was not registered or was explicitly removed from the handlers list.")
.ToString());
} }
} }
@ -232,7 +224,7 @@ namespace OpenIddict.Server.AspNetCore
} }
var transaction = Context.Features.Get<OpenIddictServerAspNetCoreFeature>()?.Transaction ?? var transaction = Context.Features.Get<OpenIddictServerAspNetCoreFeature>()?.Transaction ??
throw new InvalidOperationException("An unknown error occurred while retrieving the OpenIddict server context."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1111));
transaction.Properties[typeof(AuthenticationProperties).FullName] = properties ?? new AuthenticationProperties(); transaction.Properties[typeof(AuthenticationProperties).FullName] = properties ?? new AuthenticationProperties();
@ -268,18 +260,14 @@ namespace OpenIddict.Server.AspNetCore
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1110));
.Append("The OpenID Connect response was not correctly processed. This may indicate ")
.Append("that the event handler responsible of processing OpenID Connect responses ")
.Append("was not registered or was explicitly removed from the handlers list.")
.ToString());
} }
} }
public async Task SignOutAsync([CanBeNull] AuthenticationProperties properties) public async Task SignOutAsync([CanBeNull] AuthenticationProperties properties)
{ {
var transaction = Context.Features.Get<OpenIddictServerAspNetCoreFeature>()?.Transaction ?? var transaction = Context.Features.Get<OpenIddictServerAspNetCoreFeature>()?.Transaction ??
throw new InvalidOperationException("An unknown error occurred while retrieving the OpenIddict server context."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1111));
var context = new ProcessSignOutContext(transaction) var context = new ProcessSignOutContext(transaction)
{ {
@ -314,11 +302,7 @@ namespace OpenIddict.Server.AspNetCore
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1110));
.Append("The OpenID Connect response was not correctly processed. This may indicate ")
.Append("that the event handler responsible of processing OpenID Connect responses ")
.Append("was not registered or was explicitly removed from the handlers list.")
.ToString());
} }
} }
} }

36
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Authentication.cs

@ -28,6 +28,7 @@ using static OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreConstants;
using static OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlerFilters; using static OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlerFilters;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using JsonWebTokenTypes = OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreConstants.JsonWebTokenTypes; using JsonWebTokenTypes = OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreConstants.JsonWebTokenTypes;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server.AspNetCore namespace OpenIddict.Server.AspNetCore
{ {
@ -69,12 +70,7 @@ namespace OpenIddict.Server.AspNetCore
{ {
private readonly IDistributedCache _cache; private readonly IDistributedCache _cache;
public RestoreCachedRequestParameters() => throw new InvalidOperationException(new StringBuilder() public RestoreCachedRequestParameters() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1115));
.AppendLine("A distributed cache instance must be registered when enabling request caching.")
.Append("To register the default in-memory distributed cache implementation, reference the ")
.Append("'Microsoft.Extensions.Caching.Memory' package and call ")
.Append("'services.AddDistributedMemoryCache()' from 'ConfigureServices'.")
.ToString());
public RestoreCachedRequestParameters([NotNull] IDistributedCache cache) public RestoreCachedRequestParameters([NotNull] IDistributedCache cache)
=> _cache = cache; => _cache = cache;
@ -123,7 +119,7 @@ namespace OpenIddict.Server.AspNetCore
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'request_id' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.RequestId]);
return; return;
} }
@ -141,7 +137,7 @@ namespace OpenIddict.Server.AspNetCore
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'request_id' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.RequestId]);
return; return;
} }
@ -150,7 +146,7 @@ namespace OpenIddict.Server.AspNetCore
Base64UrlEncoder.Decode(((JsonWebToken) result.SecurityToken).InnerToken.EncodedPayload)); Base64UrlEncoder.Decode(((JsonWebToken) result.SecurityToken).InnerToken.EncodedPayload));
if (document.RootElement.ValueKind != JsonValueKind.Object) if (document.RootElement.ValueKind != JsonValueKind.Object)
{ {
throw new InvalidOperationException("The authorization request payload is malformed."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1116));
} }
// Restore the authorization request parameters from the serialized payload. // Restore the authorization request parameters from the serialized payload.
@ -176,12 +172,7 @@ namespace OpenIddict.Server.AspNetCore
private readonly IDistributedCache _cache; private readonly IDistributedCache _cache;
private readonly IOptionsMonitor<OpenIddictServerAspNetCoreOptions> _options; private readonly IOptionsMonitor<OpenIddictServerAspNetCoreOptions> _options;
public CacheRequestParameters() => throw new InvalidOperationException(new StringBuilder() public CacheRequestParameters() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1115));
.AppendLine("A distributed cache instance must be registered when enabling request caching.")
.Append("To register the default in-memory distributed cache implementation, reference the ")
.Append("'Microsoft.Extensions.Caching.Memory' package and call ")
.Append("'services.AddDistributedMemoryCache()' from 'ConfigureServices'.")
.ToString());
public CacheRequestParameters( public CacheRequestParameters(
[NotNull] IDistributedCache cache, [NotNull] IDistributedCache cache,
@ -222,7 +213,7 @@ namespace OpenIddict.Server.AspNetCore
var request = context.Transaction.GetHttpRequest(); var request = context.Transaction.GetHttpRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
// Don't cache the request if the request doesn't include any parameter. // Don't cache the request if the request doesn't include any parameter.
@ -294,12 +285,7 @@ namespace OpenIddict.Server.AspNetCore
{ {
private readonly IDistributedCache _cache; private readonly IDistributedCache _cache;
public RemoveCachedRequest() => throw new InvalidOperationException(new StringBuilder() public RemoveCachedRequest() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1115));
.AppendLine("A distributed cache instance must be registered when enabling request caching.")
.Append("To register the default in-memory distributed cache implementation, reference the ")
.Append("'Microsoft.Extensions.Caching.Memory' package and call ")
.Append("'services.AddDistributedMemoryCache()' from 'ConfigureServices'.")
.ToString());
public RemoveCachedRequest([NotNull] IDistributedCache cache) public RemoveCachedRequest([NotNull] IDistributedCache cache)
=> _cache = cache; => _cache = cache;
@ -386,7 +372,7 @@ namespace OpenIddict.Server.AspNetCore
var response = context.Transaction.GetHttpRequest()?.HttpContext.Response; var response = context.Transaction.GetHttpRequest()?.HttpContext.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
if (string.IsNullOrEmpty(context.RedirectUri) || if (string.IsNullOrEmpty(context.RedirectUri) ||
@ -483,7 +469,7 @@ namespace OpenIddict.Server.AspNetCore
var response = context.Transaction.GetHttpRequest()?.HttpContext.Response; var response = context.Transaction.GetHttpRequest()?.HttpContext.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
if (string.IsNullOrEmpty(context.RedirectUri) || if (string.IsNullOrEmpty(context.RedirectUri) ||
@ -554,7 +540,7 @@ namespace OpenIddict.Server.AspNetCore
var response = context.Transaction.GetHttpRequest()?.HttpContext.Response; var response = context.Transaction.GetHttpRequest()?.HttpContext.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
if (string.IsNullOrEmpty(context.RedirectUri) || if (string.IsNullOrEmpty(context.RedirectUri) ||

33
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Session.cs

@ -10,7 +10,6 @@ using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
@ -26,6 +25,7 @@ using static OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreConstants;
using static OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlerFilters; using static OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlerFilters;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using JsonWebTokenTypes = OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreConstants.JsonWebTokenTypes; using JsonWebTokenTypes = OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreConstants.JsonWebTokenTypes;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server.AspNetCore namespace OpenIddict.Server.AspNetCore
{ {
@ -67,12 +67,7 @@ namespace OpenIddict.Server.AspNetCore
{ {
private readonly IDistributedCache _cache; private readonly IDistributedCache _cache;
public RestoreCachedRequestParameters() => throw new InvalidOperationException(new StringBuilder() public RestoreCachedRequestParameters() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1115));
.AppendLine("A distributed cache instance must be registered when enabling request caching.")
.Append("To register the default in-memory distributed cache implementation, reference the ")
.Append("'Microsoft.Extensions.Caching.Memory' package and call ")
.Append("'services.AddDistributedMemoryCache()' from 'ConfigureServices'.")
.ToString());
public RestoreCachedRequestParameters([NotNull] IDistributedCache cache) public RestoreCachedRequestParameters([NotNull] IDistributedCache cache)
=> _cache = cache; => _cache = cache;
@ -121,7 +116,7 @@ namespace OpenIddict.Server.AspNetCore
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'request_id' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.RequestId]);
return; return;
} }
@ -139,7 +134,7 @@ namespace OpenIddict.Server.AspNetCore
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'request_id' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.RequestId]);
return; return;
} }
@ -148,7 +143,7 @@ namespace OpenIddict.Server.AspNetCore
Base64UrlEncoder.Decode(((JsonWebToken) result.SecurityToken).InnerToken.EncodedPayload)); Base64UrlEncoder.Decode(((JsonWebToken) result.SecurityToken).InnerToken.EncodedPayload));
if (document.RootElement.ValueKind != JsonValueKind.Object) if (document.RootElement.ValueKind != JsonValueKind.Object)
{ {
throw new InvalidOperationException("The logout request payload is malformed."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1117));
} }
// Restore the authorization request parameters from the serialized payload. // Restore the authorization request parameters from the serialized payload.
@ -174,12 +169,7 @@ namespace OpenIddict.Server.AspNetCore
private readonly IDistributedCache _cache; private readonly IDistributedCache _cache;
private readonly IOptionsMonitor<OpenIddictServerAspNetCoreOptions> _options; private readonly IOptionsMonitor<OpenIddictServerAspNetCoreOptions> _options;
public CacheRequestParameters() => throw new InvalidOperationException(new StringBuilder() public CacheRequestParameters() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1115));
.AppendLine("A distributed cache instance must be registered when enabling request caching.")
.Append("To register the default in-memory distributed cache implementation, reference the ")
.Append("'Microsoft.Extensions.Caching.Memory' package and call ")
.Append("'services.AddDistributedMemoryCache()' from 'ConfigureServices'.")
.ToString());
public CacheRequestParameters( public CacheRequestParameters(
[NotNull] IDistributedCache cache, [NotNull] IDistributedCache cache,
@ -220,7 +210,7 @@ namespace OpenIddict.Server.AspNetCore
var request = context.Transaction.GetHttpRequest(); var request = context.Transaction.GetHttpRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
// Don't cache the request if the request doesn't include any parameter. // Don't cache the request if the request doesn't include any parameter.
@ -292,12 +282,7 @@ namespace OpenIddict.Server.AspNetCore
{ {
private readonly IDistributedCache _cache; private readonly IDistributedCache _cache;
public RemoveCachedRequest() => throw new InvalidOperationException(new StringBuilder() public RemoveCachedRequest() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1115));
.AppendLine("A distributed cache instance must be registered when enabling request caching.")
.Append("To register the default in-memory distributed cache implementation, reference the ")
.Append("'Microsoft.Extensions.Caching.Memory' package and call ")
.Append("'services.AddDistributedMemoryCache()' from 'ConfigureServices'.")
.ToString());
public RemoveCachedRequest([NotNull] IDistributedCache cache) public RemoveCachedRequest([NotNull] IDistributedCache cache)
=> _cache = cache; => _cache = cache;
@ -379,7 +364,7 @@ namespace OpenIddict.Server.AspNetCore
var response = context.Transaction.GetHttpRequest()?.HttpContext.Response; var response = context.Transaction.GetHttpRequest()?.HttpContext.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
if (string.IsNullOrEmpty(context.PostLogoutRedirectUri)) if (string.IsNullOrEmpty(context.PostLogoutRedirectUri))

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

@ -28,6 +28,7 @@ using static OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlerFilte
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.OpenIddictServerHandlers; using static OpenIddict.Server.OpenIddictServerHandlers;
using Properties = OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreConstants.Properties; using Properties = OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreConstants.Properties;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server.AspNetCore namespace OpenIddict.Server.AspNetCore
{ {
@ -102,7 +103,7 @@ namespace OpenIddict.Server.AspNetCore
var request = context.Transaction.GetHttpRequest(); var request = context.Transaction.GetHttpRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
context.EndpointType = context.EndpointType =
@ -205,7 +206,7 @@ namespace OpenIddict.Server.AspNetCore
var request = context.Transaction.GetHttpRequest(); var request = context.Transaction.GetHttpRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
// Don't require that the request host be present if the request is not handled // Don't require that the request host be present if the request is not handled
@ -219,7 +220,7 @@ namespace OpenIddict.Server.AspNetCore
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'Host' header is missing."); description: context.Localizer[SR.ID3081]);
return default; return default;
} }
@ -229,7 +230,7 @@ namespace OpenIddict.Server.AspNetCore
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'Host' header is invalid."); description: context.Localizer[SR.ID3082]);
return default; return default;
} }
@ -277,7 +278,7 @@ namespace OpenIddict.Server.AspNetCore
var request = context.Transaction.GetHttpRequest(); var request = context.Transaction.GetHttpRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
// Don't require that the host be present if the request is not handled by OpenIddict. // Don't require that the host be present if the request is not handled by OpenIddict.
@ -291,7 +292,7 @@ namespace OpenIddict.Server.AspNetCore
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "This server only accepts HTTPS requests."); description: context.Localizer[SR.ID3083]);
return default; return default;
} }
@ -394,10 +395,7 @@ namespace OpenIddict.Server.AspNetCore
string value => value, string value => value,
string[] value => value, string[] value => value,
_ => throw new InvalidOperationException(new StringBuilder() _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID1114))
.Append("Only strings, booleans, integers, arrays of strings and instances of type ")
.Append("'OpenIddictParameter' or 'JsonElement' can be returned as custom parameters.")
.ToString())
}); });
} }
@ -441,7 +439,7 @@ namespace OpenIddict.Server.AspNetCore
var request = context.Transaction.GetHttpRequest(); var request = context.Transaction.GetHttpRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
if (HttpMethods.IsGet(request.Method)) if (HttpMethods.IsGet(request.Method))
@ -456,7 +454,7 @@ namespace OpenIddict.Server.AspNetCore
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified HTTP method is not valid."); description: context.Localizer[SR.ID3084]);
return default; return default;
} }
@ -501,7 +499,7 @@ namespace OpenIddict.Server.AspNetCore
var request = context.Transaction.GetHttpRequest(); var request = context.Transaction.GetHttpRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
if (HttpMethods.IsGet(request.Method)) if (HttpMethods.IsGet(request.Method))
@ -518,7 +516,7 @@ namespace OpenIddict.Server.AspNetCore
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'Content-Type' header must be specified."); description: context.Localizer[SR.ID3081, HeaderNames.ContentType]);
return; return;
} }
@ -531,7 +529,7 @@ namespace OpenIddict.Server.AspNetCore
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'Content-Type' header is not valid."); description: context.Localizer[SR.ID3082, HeaderNames.ContentType]);
return; return;
} }
@ -546,7 +544,7 @@ namespace OpenIddict.Server.AspNetCore
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified HTTP method is not valid."); description: context.Localizer[SR.ID3084]);
return; return;
} }
@ -589,7 +587,7 @@ namespace OpenIddict.Server.AspNetCore
var request = context.Transaction.GetHttpRequest(); var request = context.Transaction.GetHttpRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
if (HttpMethods.IsPost(request.Method)) if (HttpMethods.IsPost(request.Method))
@ -601,7 +599,7 @@ namespace OpenIddict.Server.AspNetCore
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'Content-Type' header must be specified."); description: context.Localizer[SR.ID3081, HeaderNames.ContentType]);
return; return;
} }
@ -614,7 +612,7 @@ namespace OpenIddict.Server.AspNetCore
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'Content-Type' header is not valid."); description: context.Localizer[SR.ID3082, HeaderNames.ContentType]);
return; return;
} }
@ -629,7 +627,7 @@ namespace OpenIddict.Server.AspNetCore
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified HTTP method is not valid."); description: context.Localizer[SR.ID3084]);
return; return;
} }
@ -673,7 +671,7 @@ namespace OpenIddict.Server.AspNetCore
var request = context.Transaction.GetHttpRequest(); var request = context.Transaction.GetHttpRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
string header = request.Headers[HeaderNames.Authorization]; string header = request.Headers[HeaderNames.Authorization];
@ -690,7 +688,7 @@ namespace OpenIddict.Server.AspNetCore
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "Multiple client credentials cannot be specified."); description: context.Localizer[SR.ID3087]);
return default; return default;
} }
@ -705,7 +703,7 @@ namespace OpenIddict.Server.AspNetCore
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified client credentials are invalid."); description: context.Localizer[SR.ID3055]);
return default; return default;
} }
@ -721,7 +719,7 @@ namespace OpenIddict.Server.AspNetCore
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified client credentials are invalid."); description: context.Localizer[SR.ID3055]);
return default; return default;
} }
@ -775,7 +773,7 @@ namespace OpenIddict.Server.AspNetCore
var request = context.Transaction.GetHttpRequest(); var request = context.Transaction.GetHttpRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
string header = request.Headers[HeaderNames.Authorization]; string header = request.Headers[HeaderNames.Authorization];
@ -867,7 +865,7 @@ namespace OpenIddict.Server.AspNetCore
var response = context.Transaction.GetHttpRequest()?.HttpContext.Response; var response = context.Transaction.GetHttpRequest()?.HttpContext.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
// When client authentication is made using basic authentication, the authorization server MUST return // When client authentication is made using basic authentication, the authorization server MUST return
@ -931,7 +929,7 @@ namespace OpenIddict.Server.AspNetCore
var response = context.Transaction.GetHttpRequest()?.HttpContext.Response; var response = context.Transaction.GetHttpRequest()?.HttpContext.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
// Prevent the response from being cached. // Prevent the response from being cached.
@ -984,7 +982,7 @@ namespace OpenIddict.Server.AspNetCore
var response = context.Transaction.GetHttpRequest()?.HttpContext.Response; var response = context.Transaction.GetHttpRequest()?.HttpContext.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
// When client authentication is made using basic authentication, the authorization server MUST return // When client authentication is made using basic authentication, the authorization server MUST return
@ -1102,7 +1100,7 @@ namespace OpenIddict.Server.AspNetCore
var response = context.Transaction.GetHttpRequest()?.HttpContext.Response; var response = context.Transaction.GetHttpRequest()?.HttpContext.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
// If the response doesn't contain a WWW-Authenticate header, don't return an empty response. // If the response doesn't contain a WWW-Authenticate header, don't return an empty response.
@ -1154,7 +1152,7 @@ namespace OpenIddict.Server.AspNetCore
var response = context.Transaction.GetHttpRequest()?.HttpContext.Response; var response = context.Transaction.GetHttpRequest()?.HttpContext.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
context.Logger.LogInformation("The response was successfully returned as a JSON document: {Response}.", context.Response); context.Logger.LogInformation("The response was successfully returned as a JSON document: {Response}.", context.Response);
@ -1217,7 +1215,7 @@ namespace OpenIddict.Server.AspNetCore
var response = context.Transaction.GetHttpRequest()?.HttpContext.Response; var response = context.Transaction.GetHttpRequest()?.HttpContext.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
if (string.IsNullOrEmpty(context.Response.Error)) if (string.IsNullOrEmpty(context.Response.Error))
@ -1269,7 +1267,7 @@ namespace OpenIddict.Server.AspNetCore
var response = context.Transaction.GetHttpRequest()?.HttpContext.Response; var response = context.Transaction.GetHttpRequest()?.HttpContext.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
if (string.IsNullOrEmpty(context.Response.Error)) if (string.IsNullOrEmpty(context.Response.Error))
@ -1332,7 +1330,7 @@ namespace OpenIddict.Server.AspNetCore
var response = context.Transaction.GetHttpRequest()?.HttpContext.Response; var response = context.Transaction.GetHttpRequest()?.HttpContext.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
if (string.IsNullOrEmpty(context.Response.Error)) if (string.IsNullOrEmpty(context.Response.Error))
@ -1414,7 +1412,7 @@ namespace OpenIddict.Server.AspNetCore
var response = context.Transaction.GetHttpRequest()?.HttpContext.Response; var response = context.Transaction.GetHttpRequest()?.HttpContext.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1113));
} }
var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName); var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName);

7
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.cs

@ -24,6 +24,7 @@ using static OpenIddict.Server.OpenIddictServerHandlerFilters;
using static OpenIddict.Server.OpenIddictServerHandlers; using static OpenIddict.Server.OpenIddictServerHandlers;
using Properties = OpenIddict.Server.OpenIddictServerConstants.Properties; using Properties = OpenIddict.Server.OpenIddictServerConstants.Properties;
using Schemes = OpenIddict.Server.DataProtection.OpenIddictServerDataProtectionConstants.Purposes.Schemes; using Schemes = OpenIddict.Server.DataProtection.OpenIddictServerDataProtectionConstants.Purposes.Schemes;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server.DataProtection namespace OpenIddict.Server.DataProtection
{ {
@ -35,7 +36,7 @@ namespace OpenIddict.Server.DataProtection
* Authentication processing: * Authentication processing:
*/ */
ValidateDataProtectionToken.Descriptor, ValidateDataProtectionToken.Descriptor,
/* /*
* Sign-in processing: * Sign-in processing:
*/ */
@ -108,7 +109,7 @@ namespace OpenIddict.Server.DataProtection
OpenIddictServerEndpointType.Token => Errors.InvalidGrant, OpenIddictServerEndpointType.Token => Errors.InvalidGrant,
_ => Errors.InvalidToken _ => Errors.InvalidToken
}, },
description: "The specified token is not valid."); description: context.Localizer[SR.ID3027]);
return default; return default;
} }
@ -146,7 +147,7 @@ namespace OpenIddict.Server.DataProtection
TokenTypeHints.RefreshToken => new[] { Handlers.Server, Formats.RefreshToken, Schemes.Server }, TokenTypeHints.RefreshToken => new[] { Handlers.Server, Formats.RefreshToken, Schemes.Server },
TokenTypeHints.UserCode => new[] { Handlers.Server, Formats.UserCode, Schemes.Server }, TokenTypeHints.UserCode => new[] { Handlers.Server, Formats.UserCode, Schemes.Server },
_ => throw new InvalidOperationException("The specified token type is not supported.") _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID1002))
}); });
try try

3
src/OpenIddict.Server.Owin/OpenIddictServerOwinBuilder.cs

@ -11,6 +11,7 @@ using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Owin; using Microsoft.Owin;
using OpenIddict.Server.Owin; using OpenIddict.Server.Owin;
using Owin; using Owin;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
@ -147,7 +148,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (string.IsNullOrEmpty(realm)) if (string.IsNullOrEmpty(realm))
{ {
throw new ArgumentException("The realm cannot be null or empty.", nameof(realm)); throw new ArgumentException(SR.GetResourceString(SR.ID1106), nameof(realm));
} }
return Configure(options => options.Realm = realm); return Configure(options => options.Realm = realm);

7
src/OpenIddict.Server.Owin/OpenIddictServerOwinConfiguration.cs

@ -5,10 +5,10 @@
*/ */
using System; using System;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Owin.Security; using Microsoft.Owin.Security;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server.Owin namespace OpenIddict.Server.Owin
{ {
@ -38,10 +38,7 @@ namespace OpenIddict.Server.Owin
if (options.AuthenticationMode == AuthenticationMode.Active) if (options.AuthenticationMode == AuthenticationMode.Active)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1118));
.AppendLine("The OpenIddict OWIN server handler cannot be used as an active authentication handler.")
.Append("Make sure that 'OpenIddictServerOwinOptions.AuthenticationMode' is not set to 'Active'.")
.ToString());
} }
} }
} }

38
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandler.cs

@ -7,7 +7,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Claims; using System.Security.Claims;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Owin; using Microsoft.Owin;
@ -16,6 +15,7 @@ using Microsoft.Owin.Security.Infrastructure;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server.Owin namespace OpenIddict.Server.Owin
{ {
@ -70,10 +70,10 @@ namespace OpenIddict.Server.Owin
// active authentication is used, as AuthenticateCoreAsync() is always called before InvokeAsync() in this case. // active authentication is used, as AuthenticateCoreAsync() is always called before InvokeAsync() in this case.
var transaction = Context.Get<OpenIddictServerTransaction>(typeof(OpenIddictServerTransaction).FullName) ?? var transaction = Context.Get<OpenIddictServerTransaction>(typeof(OpenIddictServerTransaction).FullName) ??
throw new InvalidOperationException("An unknown error occurred while retrieving the OpenIddict server context."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1111));
var context = transaction.GetProperty<ProcessRequestContext>(typeof(ProcessRequestContext).FullName) ?? var context = transaction.GetProperty<ProcessRequestContext>(typeof(ProcessRequestContext).FullName) ??
throw new InvalidOperationException("An unknown error occurred while retrieving the OpenIddict server context."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1111));
if (context.IsRequestHandled) if (context.IsRequestHandled)
{ {
@ -108,12 +108,8 @@ namespace OpenIddict.Server.Owin
{ {
return false; return false;
} }
throw new InvalidOperationException(SR.GetResourceString(SR.ID1110));
throw new InvalidOperationException(new StringBuilder()
.Append("The OpenID Connect response was not correctly processed. This may indicate ")
.Append("that the event handler responsible of processing OpenID Connect responses ")
.Append("was not registered or was explicitly removed from the handlers list.")
.ToString());
} }
return false; return false;
@ -124,7 +120,7 @@ namespace OpenIddict.Server.Owin
var transaction = Context.Get<OpenIddictServerTransaction>(typeof(OpenIddictServerTransaction).FullName); var transaction = Context.Get<OpenIddictServerTransaction>(typeof(OpenIddictServerTransaction).FullName);
if (transaction == null) if (transaction == null)
{ {
throw new InvalidOperationException("An unknown error occurred while retrieving the OpenIddict server context."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1111));
} }
// Note: in many cases, the authentication token was already validated by the time this action is called // Note: in many cases, the authentication token was already validated by the time this action is called
@ -200,7 +196,7 @@ namespace OpenIddict.Server.Owin
if (challenge != null && (Response.StatusCode == 401 || Response.StatusCode == 403)) if (challenge != null && (Response.StatusCode == 401 || Response.StatusCode == 403))
{ {
var transaction = Context.Get<OpenIddictServerTransaction>(typeof(OpenIddictServerTransaction).FullName) ?? var transaction = Context.Get<OpenIddictServerTransaction>(typeof(OpenIddictServerTransaction).FullName) ??
throw new InvalidOperationException("An unknown error occurred while retrieving the OpenIddict server context."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1111));
transaction.Properties[typeof(AuthenticationProperties).FullName] = challenge.Properties ?? new AuthenticationProperties(); transaction.Properties[typeof(AuthenticationProperties).FullName] = challenge.Properties ?? new AuthenticationProperties();
@ -235,11 +231,7 @@ namespace OpenIddict.Server.Owin
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1110));
.Append("The OpenID Connect response was not correctly processed. This may indicate ")
.Append("that the event handler responsible of processing OpenID Connect responses ")
.Append("was not registered or was explicitly removed from the handlers list.")
.ToString());
} }
} }
@ -247,7 +239,7 @@ namespace OpenIddict.Server.Owin
if (signin != null) if (signin != null)
{ {
var transaction = Context.Get<OpenIddictServerTransaction>(typeof(OpenIddictServerTransaction).FullName) ?? var transaction = Context.Get<OpenIddictServerTransaction>(typeof(OpenIddictServerTransaction).FullName) ??
throw new InvalidOperationException("An unknown error occurred while retrieving the OpenIddict server context."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1111));
transaction.Properties[typeof(AuthenticationProperties).FullName] = signin.Properties ?? new AuthenticationProperties(); transaction.Properties[typeof(AuthenticationProperties).FullName] = signin.Properties ?? new AuthenticationProperties();
@ -283,11 +275,7 @@ namespace OpenIddict.Server.Owin
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1110));
.Append("The OpenID Connect response was not correctly processed. This may indicate ")
.Append("that the event handler responsible of processing OpenID Connect responses ")
.Append("was not registered or was explicitly removed from the handlers list.")
.ToString());
} }
} }
@ -295,7 +283,7 @@ namespace OpenIddict.Server.Owin
if (signout != null) if (signout != null)
{ {
var transaction = Context.Get<OpenIddictServerTransaction>(typeof(OpenIddictServerTransaction).FullName) ?? var transaction = Context.Get<OpenIddictServerTransaction>(typeof(OpenIddictServerTransaction).FullName) ??
throw new InvalidOperationException("An unknown error occurred while retrieving the OpenIddict server context."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1111));
transaction.Properties[typeof(AuthenticationProperties).FullName] = signout.Properties ?? new AuthenticationProperties(); transaction.Properties[typeof(AuthenticationProperties).FullName] = signout.Properties ?? new AuthenticationProperties();
@ -330,11 +318,7 @@ namespace OpenIddict.Server.Owin
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1110));
.Append("The OpenID Connect response was not correctly processed. This may indicate ")
.Append("that the event handler responsible of processing OpenID Connect responses ")
.Append("was not registered or was explicitly removed from the handlers list.")
.ToString());
} }
} }
} }

36
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Authentication.cs

@ -28,6 +28,7 @@ using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.Owin.OpenIddictServerOwinConstants; using static OpenIddict.Server.Owin.OpenIddictServerOwinConstants;
using static OpenIddict.Server.Owin.OpenIddictServerOwinHandlerFilters; using static OpenIddict.Server.Owin.OpenIddictServerOwinHandlerFilters;
using JsonWebTokenTypes = OpenIddict.Server.Owin.OpenIddictServerOwinConstants.JsonWebTokenTypes; using JsonWebTokenTypes = OpenIddict.Server.Owin.OpenIddictServerOwinConstants.JsonWebTokenTypes;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server.Owin namespace OpenIddict.Server.Owin
{ {
@ -68,12 +69,7 @@ namespace OpenIddict.Server.Owin
{ {
private readonly IDistributedCache _cache; private readonly IDistributedCache _cache;
public RestoreCachedRequestParameters() => throw new InvalidOperationException(new StringBuilder() public RestoreCachedRequestParameters() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1115));
.AppendLine("A distributed cache instance must be registered when enabling request caching.")
.Append("To register the default in-memory distributed cache implementation, reference the ")
.Append("'Microsoft.Extensions.Caching.Memory' package and call ")
.Append("'services.AddDistributedMemoryCache()' from 'ConfigureServices'.")
.ToString());
public RestoreCachedRequestParameters([NotNull] IDistributedCache cache) public RestoreCachedRequestParameters([NotNull] IDistributedCache cache)
=> _cache = cache; => _cache = cache;
@ -122,7 +118,7 @@ namespace OpenIddict.Server.Owin
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'request_id' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.RequestId]);
return; return;
} }
@ -140,7 +136,7 @@ namespace OpenIddict.Server.Owin
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'request_id' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.RequestId]);
return; return;
} }
@ -149,7 +145,7 @@ namespace OpenIddict.Server.Owin
Base64UrlEncoder.Decode(((JsonWebToken) result.SecurityToken).InnerToken.EncodedPayload)); Base64UrlEncoder.Decode(((JsonWebToken) result.SecurityToken).InnerToken.EncodedPayload));
if (document.RootElement.ValueKind != JsonValueKind.Object) if (document.RootElement.ValueKind != JsonValueKind.Object)
{ {
throw new InvalidOperationException("The authorization request payload is malformed."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1116));
} }
// Restore the authorization request parameters from the serialized payload. // Restore the authorization request parameters from the serialized payload.
@ -175,12 +171,7 @@ namespace OpenIddict.Server.Owin
private readonly IDistributedCache _cache; private readonly IDistributedCache _cache;
private readonly IOptionsMonitor<OpenIddictServerOwinOptions> _options; private readonly IOptionsMonitor<OpenIddictServerOwinOptions> _options;
public CacheRequestParameters() => throw new InvalidOperationException(new StringBuilder() public CacheRequestParameters() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1115));
.AppendLine("A distributed cache instance must be registered when enabling request caching.")
.Append("To register the default in-memory distributed cache implementation, reference the ")
.Append("'Microsoft.Extensions.Caching.Memory' package and call ")
.Append("'services.AddDistributedMemoryCache()' from 'ConfigureServices'.")
.ToString());
public CacheRequestParameters( public CacheRequestParameters(
[NotNull] IDistributedCache cache, [NotNull] IDistributedCache cache,
@ -221,7 +212,7 @@ namespace OpenIddict.Server.Owin
var request = context.Transaction.GetOwinRequest(); var request = context.Transaction.GetOwinRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
// Don't cache the request if the request doesn't include any parameter. // Don't cache the request if the request doesn't include any parameter.
@ -288,12 +279,7 @@ namespace OpenIddict.Server.Owin
{ {
private readonly IDistributedCache _cache; private readonly IDistributedCache _cache;
public RemoveCachedRequest() => throw new InvalidOperationException(new StringBuilder() public RemoveCachedRequest() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1115));
.AppendLine("A distributed cache instance must be registered when enabling request caching.")
.Append("To register the default in-memory distributed cache implementation, reference the ")
.Append("'Microsoft.Extensions.Caching.Memory' package and call ")
.Append("'services.AddDistributedMemoryCache()' from 'ConfigureServices'.")
.ToString());
public RemoveCachedRequest([NotNull] IDistributedCache cache) public RemoveCachedRequest([NotNull] IDistributedCache cache)
=> _cache = cache; => _cache = cache;
@ -380,7 +366,7 @@ namespace OpenIddict.Server.Owin
var response = context.Transaction.GetOwinRequest()?.Context.Response; var response = context.Transaction.GetOwinRequest()?.Context.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
if (string.IsNullOrEmpty(context.RedirectUri) || if (string.IsNullOrEmpty(context.RedirectUri) ||
@ -478,7 +464,7 @@ namespace OpenIddict.Server.Owin
var response = context.Transaction.GetOwinRequest()?.Context.Response; var response = context.Transaction.GetOwinRequest()?.Context.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
if (string.IsNullOrEmpty(context.RedirectUri) || if (string.IsNullOrEmpty(context.RedirectUri) ||
@ -549,7 +535,7 @@ namespace OpenIddict.Server.Owin
var response = context.Transaction.GetOwinRequest()?.Context.Response; var response = context.Transaction.GetOwinRequest()?.Context.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
if (string.IsNullOrEmpty(context.RedirectUri) || if (string.IsNullOrEmpty(context.RedirectUri) ||

2
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Device.cs

@ -5,8 +5,8 @@
*/ */
using System.Collections.Immutable; using System.Collections.Immutable;
using static OpenIddict.Server.Owin.OpenIddictServerOwinHandlerFilters;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.Owin.OpenIddictServerOwinHandlerFilters;
namespace OpenIddict.Server.Owin namespace OpenIddict.Server.Owin
{ {

33
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Session.cs

@ -10,7 +10,6 @@ using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
@ -26,6 +25,7 @@ using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.Owin.OpenIddictServerOwinConstants; using static OpenIddict.Server.Owin.OpenIddictServerOwinConstants;
using static OpenIddict.Server.Owin.OpenIddictServerOwinHandlerFilters; using static OpenIddict.Server.Owin.OpenIddictServerOwinHandlerFilters;
using JsonWebTokenTypes = OpenIddict.Server.Owin.OpenIddictServerOwinConstants.JsonWebTokenTypes; using JsonWebTokenTypes = OpenIddict.Server.Owin.OpenIddictServerOwinConstants.JsonWebTokenTypes;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server.Owin namespace OpenIddict.Server.Owin
{ {
@ -66,12 +66,7 @@ namespace OpenIddict.Server.Owin
{ {
private readonly IDistributedCache _cache; private readonly IDistributedCache _cache;
public RestoreCachedRequestParameters() => throw new InvalidOperationException(new StringBuilder() public RestoreCachedRequestParameters() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1115));
.AppendLine("A distributed cache instance must be registered when enabling request caching.")
.Append("To register the default in-memory distributed cache implementation, reference the ")
.Append("'Microsoft.Extensions.Caching.Memory' package and call ")
.Append("'services.AddDistributedMemoryCache()' from 'ConfigureServices'.")
.ToString());
public RestoreCachedRequestParameters([NotNull] IDistributedCache cache) public RestoreCachedRequestParameters([NotNull] IDistributedCache cache)
=> _cache = cache; => _cache = cache;
@ -120,7 +115,7 @@ namespace OpenIddict.Server.Owin
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'request_id' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.RequestId]);
return; return;
} }
@ -138,7 +133,7 @@ namespace OpenIddict.Server.Owin
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'request_id' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.RequestId]);
return; return;
} }
@ -147,7 +142,7 @@ namespace OpenIddict.Server.Owin
Base64UrlEncoder.Decode(((JsonWebToken) result.SecurityToken).InnerToken.EncodedPayload)); Base64UrlEncoder.Decode(((JsonWebToken) result.SecurityToken).InnerToken.EncodedPayload));
if (document.RootElement.ValueKind != JsonValueKind.Object) if (document.RootElement.ValueKind != JsonValueKind.Object)
{ {
throw new InvalidOperationException("The logout request payload is malformed."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1117));
} }
// Restore the authorization request parameters from the serialized payload // Restore the authorization request parameters from the serialized payload
@ -173,12 +168,7 @@ namespace OpenIddict.Server.Owin
private readonly IDistributedCache _cache; private readonly IDistributedCache _cache;
private readonly IOptionsMonitor<OpenIddictServerOwinOptions> _options; private readonly IOptionsMonitor<OpenIddictServerOwinOptions> _options;
public CacheRequestParameters() => throw new InvalidOperationException(new StringBuilder() public CacheRequestParameters() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1115));
.AppendLine("A distributed cache instance must be registered when enabling request caching.")
.Append("To register the default in-memory distributed cache implementation, reference the ")
.Append("'Microsoft.Extensions.Caching.Memory' package and call ")
.Append("'services.AddDistributedMemoryCache()' from 'ConfigureServices'.")
.ToString());
public CacheRequestParameters( public CacheRequestParameters(
[NotNull] IDistributedCache cache, [NotNull] IDistributedCache cache,
@ -219,7 +209,7 @@ namespace OpenIddict.Server.Owin
var request = context.Transaction.GetOwinRequest(); var request = context.Transaction.GetOwinRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
// Don't cache the request if the request doesn't include any parameter. // Don't cache the request if the request doesn't include any parameter.
@ -286,12 +276,7 @@ namespace OpenIddict.Server.Owin
{ {
private readonly IDistributedCache _cache; private readonly IDistributedCache _cache;
public RemoveCachedRequest() => throw new InvalidOperationException(new StringBuilder() public RemoveCachedRequest() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1115));
.AppendLine("A distributed cache instance must be registered when enabling request caching.")
.Append("To register the default in-memory distributed cache implementation, reference the ")
.Append("'Microsoft.Extensions.Caching.Memory' package and call ")
.Append("'services.AddDistributedMemoryCache()' from 'ConfigureServices'.")
.ToString());
public RemoveCachedRequest([NotNull] IDistributedCache cache) public RemoveCachedRequest([NotNull] IDistributedCache cache)
=> _cache = cache; => _cache = cache;
@ -373,7 +358,7 @@ namespace OpenIddict.Server.Owin
var response = context.Transaction.GetOwinRequest()?.Context.Response; var response = context.Transaction.GetOwinRequest()?.Context.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
if (string.IsNullOrEmpty(context.PostLogoutRedirectUri)) if (string.IsNullOrEmpty(context.PostLogoutRedirectUri))

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

@ -25,6 +25,7 @@ using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.OpenIddictServerHandlers; using static OpenIddict.Server.OpenIddictServerHandlers;
using static OpenIddict.Server.Owin.OpenIddictServerOwinHandlerFilters; using static OpenIddict.Server.Owin.OpenIddictServerOwinHandlerFilters;
using Properties = OpenIddict.Server.Owin.OpenIddictServerOwinConstants.Properties; using Properties = OpenIddict.Server.Owin.OpenIddictServerOwinConstants.Properties;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server.Owin namespace OpenIddict.Server.Owin
{ {
@ -38,7 +39,7 @@ namespace OpenIddict.Server.Owin
InferEndpointType.Descriptor, InferEndpointType.Descriptor,
InferIssuerFromHost.Descriptor, InferIssuerFromHost.Descriptor,
ValidateTransportSecurityRequirement.Descriptor, ValidateTransportSecurityRequirement.Descriptor,
/* /*
* Challenge processing: * Challenge processing:
*/ */
@ -90,7 +91,7 @@ namespace OpenIddict.Server.Owin
var request = context.Transaction.GetOwinRequest(); var request = context.Transaction.GetOwinRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
context.EndpointType = context.EndpointType =
@ -193,7 +194,7 @@ namespace OpenIddict.Server.Owin
var request = context.Transaction.GetOwinRequest(); var request = context.Transaction.GetOwinRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
// Don't require that the request host be present if the request is not handled // Don't require that the request host be present if the request is not handled
@ -207,7 +208,7 @@ namespace OpenIddict.Server.Owin
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'Host' header is missing."); description: context.Localizer[SR.ID3081]);
return default; return default;
} }
@ -217,7 +218,7 @@ namespace OpenIddict.Server.Owin
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'Host' header is invalid."); description: context.Localizer[SR.ID3082]);
return default; return default;
} }
@ -265,7 +266,7 @@ namespace OpenIddict.Server.Owin
var request = context.Transaction.GetOwinRequest(); var request = context.Transaction.GetOwinRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
// Don't require that the host be present if the request is not handled by OpenIddict. // Don't require that the host be present if the request is not handled by OpenIddict.
@ -279,7 +280,7 @@ namespace OpenIddict.Server.Owin
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "This server only accepts HTTPS requests."); description: context.Localizer[SR.ID3083]);
return default; return default;
} }
@ -371,7 +372,7 @@ namespace OpenIddict.Server.Owin
var request = context.Transaction.GetOwinRequest(); var request = context.Transaction.GetOwinRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
if (string.Equals(request.Method, "GET", StringComparison.OrdinalIgnoreCase)) if (string.Equals(request.Method, "GET", StringComparison.OrdinalIgnoreCase))
@ -386,7 +387,7 @@ namespace OpenIddict.Server.Owin
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified HTTP method is not valid."); description: context.Localizer[SR.ID3084]);
return default; return default;
} }
@ -431,7 +432,7 @@ namespace OpenIddict.Server.Owin
var request = context.Transaction.GetOwinRequest(); var request = context.Transaction.GetOwinRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
if (string.Equals(request.Method, "GET", StringComparison.OrdinalIgnoreCase)) if (string.Equals(request.Method, "GET", StringComparison.OrdinalIgnoreCase))
@ -448,7 +449,7 @@ namespace OpenIddict.Server.Owin
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'Content-Type' header must be specified."); description: context.Localizer[SR.ID3081, "Content-Type"]);
return; return;
} }
@ -461,7 +462,7 @@ namespace OpenIddict.Server.Owin
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'Content-Type' header is not valid."); description: context.Localizer[SR.ID3082, "Content-Type"]);
return; return;
} }
@ -476,7 +477,7 @@ namespace OpenIddict.Server.Owin
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified HTTP method is not valid."); description: context.Localizer[SR.ID3084]);
return; return;
} }
@ -519,7 +520,7 @@ namespace OpenIddict.Server.Owin
var request = context.Transaction.GetOwinRequest(); var request = context.Transaction.GetOwinRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
if (string.Equals(request.Method, "POST", StringComparison.OrdinalIgnoreCase)) if (string.Equals(request.Method, "POST", StringComparison.OrdinalIgnoreCase))
@ -531,7 +532,7 @@ namespace OpenIddict.Server.Owin
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'Content-Type' header must be specified."); description: context.Localizer[SR.ID3081, "Content-Type"]);
return; return;
} }
@ -544,7 +545,7 @@ namespace OpenIddict.Server.Owin
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'Content-Type' header is not valid."); description: context.Localizer[SR.ID3082, "Content-Type"]);
return; return;
} }
@ -559,7 +560,7 @@ namespace OpenIddict.Server.Owin
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified HTTP method is not valid."); description: context.Localizer[SR.ID3084]);
return; return;
} }
@ -603,7 +604,7 @@ namespace OpenIddict.Server.Owin
var request = context.Transaction.GetOwinRequest(); var request = context.Transaction.GetOwinRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
var header = request.Headers["Authorization"]; var header = request.Headers["Authorization"];
@ -620,7 +621,7 @@ namespace OpenIddict.Server.Owin
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "Multiple client credentials cannot be specified."); description: context.Localizer[SR.ID3087]);
return default; return default;
} }
@ -635,7 +636,7 @@ namespace OpenIddict.Server.Owin
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified client credentials are invalid."); description: context.Localizer[SR.ID3055]);
return default; return default;
} }
@ -651,7 +652,7 @@ namespace OpenIddict.Server.Owin
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified client credentials are invalid."); description: context.Localizer[SR.ID3055]);
return default; return default;
} }
@ -705,7 +706,7 @@ namespace OpenIddict.Server.Owin
var request = context.Transaction.GetOwinRequest(); var request = context.Transaction.GetOwinRequest();
if (request == null) if (request == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
var header = request.Headers["Authorization"]; var header = request.Headers["Authorization"];
@ -797,7 +798,7 @@ namespace OpenIddict.Server.Owin
var response = context.Transaction.GetOwinRequest()?.Context.Response; var response = context.Transaction.GetOwinRequest()?.Context.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
// When client authentication is made using basic authentication, the authorization server MUST return // When client authentication is made using basic authentication, the authorization server MUST return
@ -861,7 +862,7 @@ namespace OpenIddict.Server.Owin
var response = context.Transaction.GetOwinRequest()?.Context.Response; var response = context.Transaction.GetOwinRequest()?.Context.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
// Prevent the response from being cached. // Prevent the response from being cached.
@ -914,7 +915,7 @@ namespace OpenIddict.Server.Owin
var response = context.Transaction.GetOwinRequest()?.Context.Response; var response = context.Transaction.GetOwinRequest()?.Context.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
// When client authentication is made using basic authentication, the authorization server MUST return // When client authentication is made using basic authentication, the authorization server MUST return
@ -1032,7 +1033,7 @@ namespace OpenIddict.Server.Owin
var response = context.Transaction.GetOwinRequest()?.Context.Response; var response = context.Transaction.GetOwinRequest()?.Context.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
// If the response doesn't contain a WWW-Authenticate header, don't return an empty response. // If the response doesn't contain a WWW-Authenticate header, don't return an empty response.
@ -1084,7 +1085,7 @@ namespace OpenIddict.Server.Owin
var response = context.Transaction.GetOwinRequest()?.Context.Response; var response = context.Transaction.GetOwinRequest()?.Context.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
context.Logger.LogInformation("The response was successfully returned as a JSON document: {Response}.", context.Response); context.Logger.LogInformation("The response was successfully returned as a JSON document: {Response}.", context.Response);
@ -1147,7 +1148,7 @@ namespace OpenIddict.Server.Owin
var response = context.Transaction.GetOwinRequest()?.Context.Response; var response = context.Transaction.GetOwinRequest()?.Context.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
if (string.IsNullOrEmpty(context.Response.Error)) if (string.IsNullOrEmpty(context.Response.Error))
@ -1201,7 +1202,7 @@ namespace OpenIddict.Server.Owin
var response = context.Transaction.GetOwinRequest()?.Context.Response; var response = context.Transaction.GetOwinRequest()?.Context.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
if (string.IsNullOrEmpty(context.Response.Error)) if (string.IsNullOrEmpty(context.Response.Error))
@ -1283,7 +1284,7 @@ namespace OpenIddict.Server.Owin
var response = context.Transaction.GetOwinRequest()?.Context.Response; var response = context.Transaction.GetOwinRequest()?.Context.Response;
if (response == null) if (response == null)
{ {
throw new InvalidOperationException("The OWIN request cannot be resolved."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1119));
} }
var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName); var properties = context.Transaction.GetProperty<AuthenticationProperties>(typeof(AuthenticationProperties).FullName);

17
src/OpenIddict.Server.Owin/OpenIddictServerOwinMiddlewareFactory.cs

@ -5,12 +5,12 @@
*/ */
using System; using System;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Owin; using Microsoft.Owin;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server.Owin namespace OpenIddict.Server.Owin
{ {
@ -48,13 +48,7 @@ namespace OpenIddict.Server.Owin
var provider = context.Get<IServiceProvider>(typeof(IServiceProvider).FullName); var provider = context.Get<IServiceProvider>(typeof(IServiceProvider).FullName);
if (provider == null) if (provider == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1120));
.Append("No service provider was found in the OWIN context. For the OpenIddict server ")
.Append("services to work correctly, a per-request 'IServiceProvider' must be attached ")
.AppendLine("to the OWIN environment with the dictionary key 'System.IServiceProvider'.")
.Append("Note: when using a dependency injection container supporting middleware resolution ")
.Append("(like Autofac), the 'app.UseOpenIddictServer()' extension MUST NOT be called.")
.ToString());
} }
// Note: the Microsoft.Extensions.DependencyInjection container doesn't support resolving services // Note: the Microsoft.Extensions.DependencyInjection container doesn't support resolving services
@ -69,11 +63,8 @@ namespace OpenIddict.Server.Owin
return middleware.Invoke(context); return middleware.Invoke(context);
static T GetRequiredService<T>(IServiceProvider provider) static T GetRequiredService<T>(IServiceProvider provider) => provider.GetService<T>() ??
=> provider.GetService<T>() ?? throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1121));
.AppendLine("The OpenIddict server services cannot be resolved from the DI container.")
.Append("To register the OWIN services, use 'services.AddOpenIddict().AddServer().UseOwin()'.")
.ToString());
} }
} }
} }

1
src/OpenIddict.Server/OpenIddict.Server.csproj

@ -17,6 +17,7 @@ To use the server feature on ASP.NET Core or OWIN/Katana, reference the OpenIddi
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Localization" />
<PackageReference Include="Microsoft.Extensions.Logging" /> <PackageReference Include="Microsoft.Extensions.Logging" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" /> <PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" />
</ItemGroup> </ItemGroup>

102
src/OpenIddict.Server/OpenIddictServerBuilder.cs

@ -12,12 +12,12 @@ using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using OpenIddict.Server; using OpenIddict.Server;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute; using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
@ -171,7 +171,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (key is AsymmetricSecurityKey asymmetricSecurityKey && if (key is AsymmetricSecurityKey asymmetricSecurityKey &&
asymmetricSecurityKey.PrivateKeyStatus == PrivateKeyStatus.DoesNotExist) asymmetricSecurityKey.PrivateKeyStatus == PrivateKeyStatus.DoesNotExist)
{ {
throw new InvalidOperationException("The asymmetric encryption key doesn't contain the required private key."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1054));
} }
if (key.IsSupportedAlgorithm(SecurityAlgorithms.Aes256KW)) if (key.IsSupportedAlgorithm(SecurityAlgorithms.Aes256KW))
@ -186,10 +186,7 @@ namespace Microsoft.Extensions.DependencyInjection
SecurityAlgorithms.RsaOAEP, SecurityAlgorithms.Aes256CbcHmacSha512)); SecurityAlgorithms.RsaOAEP, SecurityAlgorithms.Aes256CbcHmacSha512));
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1055));
.AppendLine("An encryption algorithm cannot be automatically inferred from the encrypting key.")
.Append("Consider using 'options.AddEncryptionCredentials(EncryptingCredentials)' instead.")
.ToString());
} }
/// <summary> /// <summary>
@ -277,7 +274,7 @@ namespace Microsoft.Extensions.DependencyInjection
return AddEncryptionCertificate(certificate); return AddEncryptionCertificate(certificate);
#else #else
throw new PlatformNotSupportedException("X.509 certificate generation is not supported on this platform."); throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID1263));
#endif #endif
} }
@ -303,7 +300,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (string.IsNullOrEmpty(algorithm)) if (string.IsNullOrEmpty(algorithm))
{ {
throw new ArgumentException("The algorithm cannot be null or empty.", nameof(algorithm)); throw new ArgumentException(SR.GetResourceString(SR.ID1056), nameof(algorithm));
} }
switch (algorithm) switch (algorithm)
@ -317,7 +314,7 @@ namespace Microsoft.Extensions.DependencyInjection
return AddEncryptionCredentials(new EncryptingCredentials(CreateRsaSecurityKey(2048), return AddEncryptionCredentials(new EncryptingCredentials(CreateRsaSecurityKey(2048),
algorithm, SecurityAlgorithms.Aes256CbcHmacSha512)); algorithm, SecurityAlgorithms.Aes256CbcHmacSha512));
default: throw new InvalidOperationException("The specified algorithm is not supported."); default: throw new InvalidOperationException(SR.GetResourceString(SR.ID1057));
} }
static SymmetricSecurityKey CreateSymmetricSecurityKey(int size) static SymmetricSecurityKey CreateSymmetricSecurityKey(int size)
@ -359,7 +356,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (algorithm.KeySize < size) if (algorithm.KeySize < size)
{ {
throw new InvalidOperationException("RSA key generation failed."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1058));
} }
return new RsaSecurityKey(algorithm); return new RsaSecurityKey(algorithm);
@ -386,13 +383,13 @@ namespace Microsoft.Extensions.DependencyInjection
var extensions = certificate.Extensions.OfType<X509KeyUsageExtension>().ToList(); var extensions = certificate.Extensions.OfType<X509KeyUsageExtension>().ToList();
if (extensions.Count != 0 && !extensions.Any(extension => extension.KeyUsages.HasFlag(X509KeyUsageFlags.KeyEncipherment))) if (extensions.Count != 0 && !extensions.Any(extension => extension.KeyUsages.HasFlag(X509KeyUsageFlags.KeyEncipherment)))
{ {
throw new InvalidOperationException("The specified certificate is not a key encryption certificate."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1059));
} }
} }
if (!certificate.HasPrivateKey) if (!certificate.HasPrivateKey)
{ {
throw new InvalidOperationException("The specified certificate doesn't contain the required private key."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1060));
} }
return AddEncryptionKey(new X509SecurityKey(certificate)); return AddEncryptionKey(new X509SecurityKey(certificate));
@ -435,18 +432,18 @@ namespace Microsoft.Extensions.DependencyInjection
if (string.IsNullOrEmpty(resource)) if (string.IsNullOrEmpty(resource))
{ {
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource)); throw new ArgumentException(SR.GetResourceString(SR.ID1061), nameof(resource));
} }
if (string.IsNullOrEmpty(password)) if (string.IsNullOrEmpty(password))
{ {
throw new ArgumentException("The password cannot be null or empty.", nameof(password)); throw new ArgumentException(SR.GetResourceString(SR.ID1062), nameof(password));
} }
using var stream = assembly.GetManifestResourceStream(resource); using var stream = assembly.GetManifestResourceStream(resource);
if (stream == null) if (stream == null)
{ {
throw new InvalidOperationException("The certificate was not found in the specified assembly."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1063));
} }
return AddEncryptionCertificate(stream, password, flags); return AddEncryptionCertificate(stream, password, flags);
@ -490,7 +487,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (string.IsNullOrEmpty(password)) if (string.IsNullOrEmpty(password))
{ {
throw new ArgumentException("The password cannot be null or empty.", nameof(password)); throw new ArgumentException(SR.GetResourceString(SR.ID1062), nameof(password));
} }
using var buffer = new MemoryStream(); using var buffer = new MemoryStream();
@ -508,13 +505,13 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (string.IsNullOrEmpty(thumbprint)) if (string.IsNullOrEmpty(thumbprint))
{ {
throw new ArgumentException("The thumbprint cannot be null or empty.", nameof(thumbprint)); throw new ArgumentException(SR.GetResourceString(SR.ID1064), nameof(thumbprint));
} }
var certificate = GetCertificate(StoreLocation.CurrentUser, thumbprint) ?? GetCertificate(StoreLocation.LocalMachine, thumbprint); var certificate = GetCertificate(StoreLocation.CurrentUser, thumbprint) ?? GetCertificate(StoreLocation.LocalMachine, thumbprint);
if (certificate == null) if (certificate == null)
{ {
throw new InvalidOperationException("The certificate corresponding to the specified thumbprint was not found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1065));
} }
return AddEncryptionCertificate(certificate); return AddEncryptionCertificate(certificate);
@ -542,7 +539,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (string.IsNullOrEmpty(thumbprint)) if (string.IsNullOrEmpty(thumbprint))
{ {
throw new ArgumentException("The thumbprint cannot be null or empty.", nameof(thumbprint)); throw new ArgumentException(SR.GetResourceString(SR.ID1064), nameof(thumbprint));
} }
using var store = new X509Store(name, location); using var store = new X509Store(name, location);
@ -554,7 +551,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (certificate == null) if (certificate == null)
{ {
throw new InvalidOperationException("The certificate corresponding to the specified thumbprint was not found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1065));
} }
return AddEncryptionCertificate(certificate); return AddEncryptionCertificate(certificate);
@ -591,7 +588,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (key is AsymmetricSecurityKey asymmetricSecurityKey && if (key is AsymmetricSecurityKey asymmetricSecurityKey &&
asymmetricSecurityKey.PrivateKeyStatus == PrivateKeyStatus.DoesNotExist) asymmetricSecurityKey.PrivateKeyStatus == PrivateKeyStatus.DoesNotExist)
{ {
throw new InvalidOperationException("The asymmetric signing key doesn't contain the required private key."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1066));
} }
if (key.IsSupportedAlgorithm(SecurityAlgorithms.RsaSha256)) if (key.IsSupportedAlgorithm(SecurityAlgorithms.RsaSha256))
@ -625,14 +622,11 @@ namespace Microsoft.Extensions.DependencyInjection
key.IsSupportedAlgorithm(SecurityAlgorithms.EcdsaSha384) || key.IsSupportedAlgorithm(SecurityAlgorithms.EcdsaSha384) ||
key.IsSupportedAlgorithm(SecurityAlgorithms.EcdsaSha512)) key.IsSupportedAlgorithm(SecurityAlgorithms.EcdsaSha512))
{ {
throw new PlatformNotSupportedException("ECDSA signing keys are not supported on this platform."); throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID1068));
} }
#endif #endif
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1067));
.AppendLine("A signature algorithm cannot be automatically inferred from the signing key.")
.Append("Consider using 'options.AddSigningCredentials(SigningCredentials)' instead.")
.ToString());
} }
/// <summary> /// <summary>
@ -720,7 +714,7 @@ namespace Microsoft.Extensions.DependencyInjection
return AddSigningCertificate(certificate); return AddSigningCertificate(certificate);
#else #else
throw new PlatformNotSupportedException("X.509 certificate generation is not supported on this platform."); throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID1263));
#endif #endif
} }
@ -748,7 +742,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (string.IsNullOrEmpty(algorithm)) if (string.IsNullOrEmpty(algorithm))
{ {
throw new ArgumentException("The algorithm cannot be null or empty.", nameof(algorithm)); throw new ArgumentException(SR.GetResourceString(SR.ID1056), nameof(algorithm));
} }
switch (algorithm) switch (algorithm)
@ -790,10 +784,10 @@ namespace Microsoft.Extensions.DependencyInjection
case SecurityAlgorithms.EcdsaSha256Signature: case SecurityAlgorithms.EcdsaSha256Signature:
case SecurityAlgorithms.EcdsaSha384Signature: case SecurityAlgorithms.EcdsaSha384Signature:
case SecurityAlgorithms.EcdsaSha512Signature: case SecurityAlgorithms.EcdsaSha512Signature:
throw new PlatformNotSupportedException("ECDSA signing keys are not supported on this platform."); throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID1068));
#endif #endif
default: throw new InvalidOperationException("The specified algorithm is not supported."); default: throw new InvalidOperationException(SR.GetResourceString(SR.ID1057));
} }
[SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope",
@ -821,7 +815,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (algorithm.KeySize < size) if (algorithm.KeySize < size)
{ {
throw new InvalidOperationException("RSA key generation failed."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1058));
} }
return new RsaSecurityKey(algorithm); return new RsaSecurityKey(algorithm);
@ -848,13 +842,13 @@ namespace Microsoft.Extensions.DependencyInjection
var extensions = certificate.Extensions.OfType<X509KeyUsageExtension>().ToList(); var extensions = certificate.Extensions.OfType<X509KeyUsageExtension>().ToList();
if (extensions.Count != 0 && !extensions.Any(extension => extension.KeyUsages.HasFlag(X509KeyUsageFlags.DigitalSignature))) if (extensions.Count != 0 && !extensions.Any(extension => extension.KeyUsages.HasFlag(X509KeyUsageFlags.DigitalSignature)))
{ {
throw new InvalidOperationException("The specified certificate is not a signing certificate."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1069));
} }
} }
if (!certificate.HasPrivateKey) if (!certificate.HasPrivateKey)
{ {
throw new InvalidOperationException("The specified certificate doesn't contain the required private key."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1060));
} }
return AddSigningKey(new X509SecurityKey(certificate)); return AddSigningKey(new X509SecurityKey(certificate));
@ -897,18 +891,18 @@ namespace Microsoft.Extensions.DependencyInjection
if (string.IsNullOrEmpty(resource)) if (string.IsNullOrEmpty(resource))
{ {
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource)); throw new ArgumentException(SR.GetResourceString(SR.ID1061), nameof(resource));
} }
if (string.IsNullOrEmpty(password)) if (string.IsNullOrEmpty(password))
{ {
throw new ArgumentException("The password cannot be null or empty.", nameof(password)); throw new ArgumentException(SR.GetResourceString(SR.ID1062), nameof(password));
} }
using var stream = assembly.GetManifestResourceStream(resource); using var stream = assembly.GetManifestResourceStream(resource);
if (stream == null) if (stream == null)
{ {
throw new InvalidOperationException("The certificate was not found in the specified assembly."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1063));
} }
return AddSigningCertificate(stream, password, flags); return AddSigningCertificate(stream, password, flags);
@ -952,7 +946,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (string.IsNullOrEmpty(password)) if (string.IsNullOrEmpty(password))
{ {
throw new ArgumentException("The password cannot be null or empty.", nameof(password)); throw new ArgumentException(SR.GetResourceString(SR.ID1062), nameof(password));
} }
using var buffer = new MemoryStream(); using var buffer = new MemoryStream();
@ -970,13 +964,13 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (string.IsNullOrEmpty(thumbprint)) if (string.IsNullOrEmpty(thumbprint))
{ {
throw new ArgumentException("The thumbprint cannot be null or empty.", nameof(thumbprint)); throw new ArgumentException(SR.GetResourceString(SR.ID1064), nameof(thumbprint));
} }
var certificate = GetCertificate(StoreLocation.CurrentUser, thumbprint) ?? GetCertificate(StoreLocation.LocalMachine, thumbprint); var certificate = GetCertificate(StoreLocation.CurrentUser, thumbprint) ?? GetCertificate(StoreLocation.LocalMachine, thumbprint);
if (certificate == null) if (certificate == null)
{ {
throw new InvalidOperationException("The certificate corresponding to the specified thumbprint was not found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1065));
} }
return AddSigningCertificate(certificate); return AddSigningCertificate(certificate);
@ -1004,7 +998,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (string.IsNullOrEmpty(thumbprint)) if (string.IsNullOrEmpty(thumbprint))
{ {
throw new ArgumentException("The thumbprint cannot be null or empty.", nameof(thumbprint)); throw new ArgumentException(SR.GetResourceString(SR.ID1064), nameof(thumbprint));
} }
using var store = new X509Store(name, location); using var store = new X509Store(name, location);
@ -1016,7 +1010,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (certificate == null) if (certificate == null)
{ {
throw new InvalidOperationException("The certificate corresponding to the specified thumbprint was not found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1065));
} }
return AddSigningCertificate(certificate); return AddSigningCertificate(certificate);
@ -1049,7 +1043,7 @@ namespace Microsoft.Extensions.DependencyInjection
{ {
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new ArgumentException("The grant type cannot be null or empty.", nameof(type)); throw new ArgumentException(SR.GetResourceString(SR.ID1070), nameof(type));
} }
return Configure(options => options.GrantTypes.Add(type)); return Configure(options => options.GrantTypes.Add(type));
@ -1122,7 +1116,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (addresses.Any(address => !address.IsWellFormedOriginalString())) if (addresses.Any(address => !address.IsWellFormedOriginalString()))
{ {
throw new ArgumentException("One of the specified addresses is not valid.", nameof(addresses)); throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses));
} }
return Configure(options => return Configure(options =>
@ -1165,7 +1159,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (addresses.Any(address => !address.IsWellFormedOriginalString())) if (addresses.Any(address => !address.IsWellFormedOriginalString()))
{ {
throw new ArgumentException("One of the specified addresses is not valid.", nameof(addresses)); throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses));
} }
return Configure(options => return Configure(options =>
@ -1208,7 +1202,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (addresses.Any(address => !address.IsWellFormedOriginalString())) if (addresses.Any(address => !address.IsWellFormedOriginalString()))
{ {
throw new ArgumentException("One of the specified addresses is not valid.", nameof(addresses)); throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses));
} }
return Configure(options => return Configure(options =>
@ -1251,7 +1245,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (addresses.Any(address => !address.IsWellFormedOriginalString())) if (addresses.Any(address => !address.IsWellFormedOriginalString()))
{ {
throw new ArgumentException("One of the specified addresses is not valid.", nameof(addresses)); throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses));
} }
return Configure(options => return Configure(options =>
@ -1294,7 +1288,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (addresses.Any(address => !address.IsWellFormedOriginalString())) if (addresses.Any(address => !address.IsWellFormedOriginalString()))
{ {
throw new ArgumentException("One of the specified addresses is not valid.", nameof(addresses)); throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses));
} }
return Configure(options => return Configure(options =>
@ -1337,7 +1331,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (addresses.Any(address => !address.IsWellFormedOriginalString())) if (addresses.Any(address => !address.IsWellFormedOriginalString()))
{ {
throw new ArgumentException("One of the specified addresses is not valid.", nameof(addresses)); throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses));
} }
return Configure(options => return Configure(options =>
@ -1380,7 +1374,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (addresses.Any(address => !address.IsWellFormedOriginalString())) if (addresses.Any(address => !address.IsWellFormedOriginalString()))
{ {
throw new ArgumentException("One of the specified addresses is not valid.", nameof(addresses)); throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses));
} }
return Configure(options => return Configure(options =>
@ -1423,7 +1417,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (addresses.Any(address => !address.IsWellFormedOriginalString())) if (addresses.Any(address => !address.IsWellFormedOriginalString()))
{ {
throw new ArgumentException("One of the specified addresses is not valid.", nameof(addresses)); throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses));
} }
return Configure(options => return Configure(options =>
@ -1466,7 +1460,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (addresses.Any(address => !address.IsWellFormedOriginalString())) if (addresses.Any(address => !address.IsWellFormedOriginalString()))
{ {
throw new ArgumentException("One of the specified addresses is not valid.", nameof(addresses)); throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses));
} }
return Configure(options => return Configure(options =>
@ -1509,7 +1503,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (addresses.Any(address => !address.IsWellFormedOriginalString())) if (addresses.Any(address => !address.IsWellFormedOriginalString()))
{ {
throw new ArgumentException("One of the specified addresses is not valid.", nameof(addresses)); throw new ArgumentException(SR.GetResourceString(SR.ID1071), nameof(addresses));
} }
return Configure(options => return Configure(options =>
@ -1616,7 +1610,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (claims.Any(claim => string.IsNullOrEmpty(claim))) if (claims.Any(claim => string.IsNullOrEmpty(claim)))
{ {
throw new ArgumentException("Claims cannot be null or empty.", nameof(claims)); throw new ArgumentException(SR.GetResourceString(SR.ID1072), nameof(claims));
} }
return Configure(options => options.Claims.UnionWith(claims)); return Configure(options => options.Claims.UnionWith(claims));
@ -1637,7 +1631,7 @@ namespace Microsoft.Extensions.DependencyInjection
if (scopes.Any(scope => string.IsNullOrEmpty(scope))) if (scopes.Any(scope => string.IsNullOrEmpty(scope)))
{ {
throw new ArgumentException("Scopes cannot be null or empty.", nameof(scopes)); throw new ArgumentException(SR.GetResourceString(SR.ID1073), nameof(scopes));
} }
return Configure(options => options.Scopes.UnionWith(scopes)); return Configure(options => options.Scopes.UnionWith(scopes));

109
src/OpenIddict.Server/OpenIddictServerConfiguration.cs

@ -7,13 +7,13 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.OpenIddictServerHandlerFilters; using static OpenIddict.Server.OpenIddictServerHandlerFilters;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -37,13 +37,13 @@ namespace OpenIddict.Server
if (options.JsonWebTokenHandler == null) if (options.JsonWebTokenHandler == null)
{ {
throw new InvalidOperationException("The security token handler cannot be null."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1074));
} }
// Ensure at least one flow has been enabled. // Ensure at least one flow has been enabled.
if (options.GrantTypes.Count == 0) if (options.GrantTypes.Count == 0)
{ {
throw new InvalidOperationException("At least one OAuth 2.0/OpenID Connect flow must be enabled."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1075));
} }
// Ensure the authorization endpoint has been enabled when // Ensure the authorization endpoint has been enabled when
@ -51,15 +51,13 @@ namespace OpenIddict.Server
if (options.AuthorizationEndpointUris.Count == 0 && (options.GrantTypes.Contains(GrantTypes.AuthorizationCode) || if (options.AuthorizationEndpointUris.Count == 0 && (options.GrantTypes.Contains(GrantTypes.AuthorizationCode) ||
options.GrantTypes.Contains(GrantTypes.Implicit))) options.GrantTypes.Contains(GrantTypes.Implicit)))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1076));
.Append("The authorization endpoint must be enabled to use the authorization code and implicit flows.")
.ToString());
} }
// Ensure the device endpoint has been enabled when the device grant is supported. // Ensure the device endpoint has been enabled when the device grant is supported.
if (options.DeviceEndpointUris.Count == 0 && options.GrantTypes.Contains(GrantTypes.DeviceCode)) if (options.DeviceEndpointUris.Count == 0 && options.GrantTypes.Contains(GrantTypes.DeviceCode))
{ {
throw new InvalidOperationException("The device endpoint must be enabled to use the device flow."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1077));
} }
// Ensure the token endpoint has been enabled when the authorization code, // Ensure the token endpoint has been enabled when the authorization code,
@ -70,83 +68,60 @@ namespace OpenIddict.Server
options.GrantTypes.Contains(GrantTypes.Password) || options.GrantTypes.Contains(GrantTypes.Password) ||
options.GrantTypes.Contains(GrantTypes.RefreshToken))) options.GrantTypes.Contains(GrantTypes.RefreshToken)))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1078));
.Append("The token endpoint must be enabled to use the authorization code, ")
.Append("client credentials, device, password and refresh token flows.")
.ToString());
} }
// Ensure the verification endpoint has been enabled when the device grant is supported. // Ensure the verification endpoint has been enabled when the device grant is supported.
if (options.VerificationEndpointUris.Count == 0 && options.GrantTypes.Contains(GrantTypes.DeviceCode)) if (options.VerificationEndpointUris.Count == 0 && options.GrantTypes.Contains(GrantTypes.DeviceCode))
{ {
throw new InvalidOperationException("The verification endpoint must be enabled to use the device flow."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1079));
} }
if (options.DisableTokenStorage) if (options.DisableTokenStorage)
{ {
if (options.DeviceEndpointUris.Count != 0 || options.VerificationEndpointUris.Count != 0) if (options.DeviceEndpointUris.Count != 0 || options.VerificationEndpointUris.Count != 0)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1080));
.Append("The device and verification endpoints cannot be enabled when token storage is disabled.")
.ToString());
} }
if (options.RevocationEndpointUris.Count != 0) if (options.RevocationEndpointUris.Count != 0)
{ {
throw new InvalidOperationException("The revocation endpoint cannot be enabled when token storage is disabled."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1081));
} }
if (options.UseReferenceAccessTokens || options.UseReferenceRefreshTokens) if (options.UseReferenceAccessTokens || options.UseReferenceRefreshTokens)
{ {
throw new InvalidOperationException("Reference tokens cannot be used when disabling token storage."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1082));
} }
if (!options.DisableSlidingRefreshTokenExpiration && !options.UseRollingRefreshTokens) if (!options.DisableSlidingRefreshTokenExpiration && !options.UseRollingRefreshTokens)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1083));
.Append("Sliding expiration must be disabled when turning off token storage if rolling tokens are not used.")
.ToString());
} }
} }
if (options.EncryptionCredentials.Count == 0) if (options.EncryptionCredentials.Count == 0)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1084));
.AppendLine("At least one encryption key must be registered in the OpenIddict server options.")
.Append("Consider registering a certificate using 'services.AddOpenIddict().AddServer().AddEncryptionCertificate()' ")
.Append("or 'services.AddOpenIddict().AddServer().AddDevelopmentEncryptionCertificate()' or call ")
.Append("'services.AddOpenIddict().AddServer().AddEphemeralEncryptionKey()' to use an ephemeral key.")
.ToString());
} }
if (!options.SigningCredentials.Any(credentials => credentials.Key is AsymmetricSecurityKey)) if (!options.SigningCredentials.Any(credentials => credentials.Key is AsymmetricSecurityKey))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1085));
.AppendLine("At least one asymmetric signing key must be registered in the OpenIddict server options.")
.Append("Consider registering a certificate using 'services.AddOpenIddict().AddServer().AddSigningCertificate()' ")
.Append("or 'services.AddOpenIddict().AddServer().AddDevelopmentSigningCertificate()' or call ")
.Append("'services.AddOpenIddict().AddServer().AddEphemeralSigningKey()' to use an ephemeral key.")
.ToString());
} }
// If all the registered encryption credentials are backed by a X.509 certificate, at least one of them must be valid. // If all the registered encryption credentials are backed by a X.509 certificate, at least one of them must be valid.
if (options.EncryptionCredentials.All(credentials => credentials.Key is X509SecurityKey x509SecurityKey && if (options.EncryptionCredentials.All(credentials => credentials.Key is X509SecurityKey x509SecurityKey &&
(x509SecurityKey.Certificate.NotBefore > DateTime.Now || x509SecurityKey.Certificate.NotAfter < DateTime.Now))) (x509SecurityKey.Certificate.NotBefore > DateTime.Now || x509SecurityKey.Certificate.NotAfter < DateTime.Now)))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1086));
.AppendLine("When using X.509 encryption credentials, at least one of the registered certificates must be valid.")
.Append("To use key rollover, register both the new certificate and the old one in the credentials collection.")
.ToString());
} }
// If all the registered signing credentials are backed by a X.509 certificate, at least one of them must be valid. // If all the registered signing credentials are backed by a X.509 certificate, at least one of them must be valid.
if (options.SigningCredentials.All(credentials => credentials.Key is X509SecurityKey x509SecurityKey && if (options.SigningCredentials.All(credentials => credentials.Key is X509SecurityKey x509SecurityKey &&
(x509SecurityKey.Certificate.NotBefore > DateTime.Now || x509SecurityKey.Certificate.NotAfter < DateTime.Now))) (x509SecurityKey.Certificate.NotBefore > DateTime.Now || x509SecurityKey.Certificate.NotAfter < DateTime.Now)))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1087));
.AppendLine("When using X.509 signing credentials, at least one of the registered certificates must be valid.")
.Append("To use key rollover, register both the new certificate and the old one in the credentials collection.")
.ToString());
} }
if (options.EnableDegradedMode) if (options.EnableDegradedMode)
@ -159,11 +134,7 @@ namespace OpenIddict.Server
descriptor.Type == OpenIddictServerHandlerType.Custom && descriptor.Type == OpenIddictServerHandlerType.Custom &&
descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type)))) descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type))))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1088));
.Append("No custom authorization request validation handler was found. When enabling the degraded mode, ")
.Append("a custom 'IOpenIddictServerHandler<ValidateAuthorizationRequestContext>' must be implemented ")
.Append("to validate authorization requests (e.g to ensure the client_id and redirect_uri are valid).")
.ToString());
} }
if (options.DeviceEndpointUris.Count != 0 && !options.Handlers.Any( if (options.DeviceEndpointUris.Count != 0 && !options.Handlers.Any(
@ -171,11 +142,7 @@ namespace OpenIddict.Server
descriptor.Type == OpenIddictServerHandlerType.Custom && descriptor.Type == OpenIddictServerHandlerType.Custom &&
descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type)))) descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type))))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1089));
.Append("No custom device request validation handler was found. When enabling the degraded mode, ")
.Append("a custom 'IOpenIddictServerHandler<ValidateDeviceRequestContext>' must be implemented ")
.Append("to validate device requests (e.g to ensure the client_id and client_secret are valid).")
.ToString());
} }
if (options.IntrospectionEndpointUris.Count != 0 && !options.Handlers.Any( if (options.IntrospectionEndpointUris.Count != 0 && !options.Handlers.Any(
@ -183,11 +150,7 @@ namespace OpenIddict.Server
descriptor.Type == OpenIddictServerHandlerType.Custom && descriptor.Type == OpenIddictServerHandlerType.Custom &&
descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type)))) descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type))))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1090));
.Append("No custom introspection request validation handler was found. When enabling the degraded mode, ")
.Append("a custom 'IOpenIddictServerHandler<ValidateIntrospectionRequestContext>' must be implemented ")
.Append("to validate introspection requests (e.g to ensure the client_id and client_secret are valid).")
.ToString());
} }
if (options.LogoutEndpointUris.Count != 0 && !options.Handlers.Any( if (options.LogoutEndpointUris.Count != 0 && !options.Handlers.Any(
@ -195,11 +158,7 @@ namespace OpenIddict.Server
descriptor.Type == OpenIddictServerHandlerType.Custom && descriptor.Type == OpenIddictServerHandlerType.Custom &&
descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type)))) descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type))))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1091));
.Append("No custom logout request validation handler was found. When enabling the degraded mode, ")
.Append("a custom 'IOpenIddictServerHandler<ValidateLogoutRequestContext>' must be implemented ")
.Append("to validate logout requests (e.g to ensure the post_logout_redirect_uri is valid).")
.ToString());
} }
if (options.RevocationEndpointUris.Count != 0 && !options.Handlers.Any( if (options.RevocationEndpointUris.Count != 0 && !options.Handlers.Any(
@ -207,11 +166,7 @@ namespace OpenIddict.Server
descriptor.Type == OpenIddictServerHandlerType.Custom && descriptor.Type == OpenIddictServerHandlerType.Custom &&
descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type)))) descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type))))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1092));
.Append("No custom revocation request validation handler was found. When enabling the degraded mode, ")
.Append("a custom 'IOpenIddictServerHandler<ValidateRevocationRequestContext>' must be implemented ")
.Append("to validate revocation requests (e.g to ensure the client_id and client_secret are valid).")
.ToString());
} }
if (options.TokenEndpointUris.Count != 0 && !options.Handlers.Any( if (options.TokenEndpointUris.Count != 0 && !options.Handlers.Any(
@ -219,11 +174,7 @@ namespace OpenIddict.Server
descriptor.Type == OpenIddictServerHandlerType.Custom && descriptor.Type == OpenIddictServerHandlerType.Custom &&
descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type)))) descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type))))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1093));
.Append("No custom token request validation handler was found. When enabling the degraded mode, ")
.Append("a custom 'IOpenIddictServerHandler<ValidateTokenRequestContext>' must be implemented ")
.Append("to validate token requests (e.g to ensure the client_id and client_secret are valid).")
.ToString());
} }
if (options.VerificationEndpointUris.Count != 0 && !options.Handlers.Any( if (options.VerificationEndpointUris.Count != 0 && !options.Handlers.Any(
@ -231,11 +182,7 @@ namespace OpenIddict.Server
descriptor.Type == OpenIddictServerHandlerType.Custom && descriptor.Type == OpenIddictServerHandlerType.Custom &&
descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type)))) descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type))))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1094));
.Append("No custom verification request validation handler was found. When enabling the degraded mode, ")
.Append("a custom 'IOpenIddictServerHandler<ValidateVerificationRequestContext>' must be implemented ")
.Append("to validate verification requests (e.g to ensure the user_code is valid).")
.ToString());
} }
// If the degraded mode was enabled, ensure custom authentication/sign-in handlers // If the degraded mode was enabled, ensure custom authentication/sign-in handlers
@ -248,11 +195,7 @@ namespace OpenIddict.Server
descriptor.Type == OpenIddictServerHandlerType.Custom && descriptor.Type == OpenIddictServerHandlerType.Custom &&
descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type)))) descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type))))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1095));
.Append("No custom verification authentication handler was found. When enabling the degraded mode, ")
.Append("a custom 'IOpenIddictServerHandler<ProcessAuthenticationContext>' must be implemented ")
.Append("to validate device and user codes (e.g by retrieving them from a database).")
.ToString());
} }
if (!options.Handlers.Any( if (!options.Handlers.Any(
@ -260,11 +203,7 @@ namespace OpenIddict.Server
descriptor.Type == OpenIddictServerHandlerType.Custom && descriptor.Type == OpenIddictServerHandlerType.Custom &&
descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type)))) descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type))))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1096));
.Append("No custom verification sign-in handler was found. When enabling the degraded mode, ")
.Append("a custom 'IOpenIddictServerHandler<ProcessSignInContext>' must be implemented ")
.Append("to generate device and user codes and storing them in a database, if applicable.")
.ToString());
} }
} }
} }

13
src/OpenIddict.Server/OpenIddictServerDispatcher.cs

@ -6,12 +6,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -115,11 +115,7 @@ namespace OpenIddict.Server
if (handler == null) if (handler == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.FormatID1097(descriptor.ServiceDescriptor.ServiceType));
.AppendLine($"The event handler of type '{descriptor.ServiceDescriptor.ServiceType}' couldn't be resolved.")
.AppendLine("This may indicate that it was not properly registered in the dependency injection container.")
.Append("To register an event handler, use 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
yield return handler; yield return handler;
@ -132,10 +128,7 @@ namespace OpenIddict.Server
{ {
if (!(_provider.GetService(descriptor.FilterTypes[index]) is IOpenIddictServerHandlerFilter<TContext> filter)) if (!(_provider.GetService(descriptor.FilterTypes[index]) is IOpenIddictServerHandlerFilter<TContext> filter))
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.FormatID1098(descriptor.FilterTypes[index]));
.AppendLine($"The event handler filter of type '{descriptor.FilterTypes[index]}' couldn't be resolved.")
.AppendLine("This may indicate that it was not properly registered in the dependency injection container.")
.ToString());
} }
if (!await filter.IsActiveAsync(context)) if (!await filter.IsActiveAsync(context))

7
src/OpenIddict.Server/OpenIddictServerEvents.Authentication.cs

@ -7,6 +7,7 @@
using System; using System;
using System.Security.Claims; using System.Security.Claims;
using JetBrains.Annotations; using JetBrains.Annotations;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -61,7 +62,7 @@ namespace OpenIddict.Server
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("The redirect_uri cannot be null or empty.", nameof(address)); throw new ArgumentException(SR.GetResourceString(SR.ID1099), nameof(address));
} }
// Don't allow validation to alter the redirect_uri parameter extracted // Don't allow validation to alter the redirect_uri parameter extracted
@ -69,9 +70,7 @@ namespace OpenIddict.Server
if (!string.IsNullOrEmpty(Request.RedirectUri) && if (!string.IsNullOrEmpty(Request.RedirectUri) &&
!string.Equals(Request.RedirectUri, address, StringComparison.Ordinal)) !string.Equals(Request.RedirectUri, address, StringComparison.Ordinal))
{ {
throw new InvalidOperationException( throw new InvalidOperationException(SR.GetResourceString(SR.ID1100));
"The authorization request cannot be validated because a different " +
"redirect_uri was specified by the client application.");
} }
RedirectUri = address; RedirectUri = address;

7
src/OpenIddict.Server/OpenIddictServerEvents.Session.cs

@ -6,6 +6,7 @@
using System; using System;
using JetBrains.Annotations; using JetBrains.Annotations;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -53,7 +54,7 @@ namespace OpenIddict.Server
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
throw new ArgumentException("The post_logout_redirect_uri cannot be null or empty.", nameof(address)); throw new ArgumentException(SR.GetResourceString(SR.ID1101), nameof(address));
} }
// Don't allow validation to alter the post_logout_redirect_uri parameter extracted // Don't allow validation to alter the post_logout_redirect_uri parameter extracted
@ -61,9 +62,7 @@ namespace OpenIddict.Server
if (!string.IsNullOrEmpty(Request.PostLogoutRedirectUri) && if (!string.IsNullOrEmpty(Request.PostLogoutRedirectUri) &&
!string.Equals(Request.PostLogoutRedirectUri, address, StringComparison.Ordinal)) !string.Equals(Request.PostLogoutRedirectUri, address, StringComparison.Ordinal))
{ {
throw new InvalidOperationException( throw new InvalidOperationException(SR.GetResourceString(SR.ID1102));
"The end session request cannot be validated because a different " +
"post_logout_redirect_uri was specified by the client application.");
} }
PostLogoutRedirectUri = address; PostLogoutRedirectUri = address;

2
src/OpenIddict.Server/OpenIddictServerEvents.Userinfo.cs

@ -7,8 +7,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Claims; using System.Security.Claims;
using JetBrains.Annotations;
using System.Text.Json; using System.Text.Json;
using JetBrains.Annotations;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
namespace OpenIddict.Server namespace OpenIddict.Server

7
src/OpenIddict.Server/OpenIddictServerEvents.cs

@ -5,10 +5,10 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Security.Claims; using System.Security.Claims;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
@ -51,6 +51,11 @@ namespace OpenIddict.Server
set => Transaction.EndpointType = value; set => Transaction.EndpointType = value;
} }
/// <summary>
/// Gets the localizer used to localize the messages generated by OpenIddict.
/// </summary>
public IStringLocalizer Localizer => Transaction.Localizer;
/// <summary> /// <summary>
/// Gets the logger responsible of logging processed operations. /// Gets the logger responsible of logging processed operations.
/// </summary> /// </summary>

19
src/OpenIddict.Server/OpenIddictServerExtensions.cs

@ -8,13 +8,17 @@ using System;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging.Abstractions;
using OpenIddict.Abstractions.Resources;
using OpenIddict.Server; using OpenIddict.Server;
using static OpenIddict.Server.OpenIddictServerHandlerFilters; using static OpenIddict.Server.OpenIddictServerHandlerFilters;
using static OpenIddict.Server.OpenIddictServerHandlers; using static OpenIddict.Server.OpenIddictServerHandlers;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
using Microsoft.Extensions.Options;
/// <summary> /// <summary>
/// Exposes extensions allowing to register the OpenIddict server services. /// Exposes extensions allowing to register the OpenIddict server services.
/// </summary> /// </summary>
@ -33,6 +37,7 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentNullException(nameof(builder)); throw new ArgumentNullException(nameof(builder));
} }
builder.Services.AddLocalization();
builder.Services.AddLogging(); builder.Services.AddLogging();
builder.Services.AddOptions(); builder.Services.AddOptions();
@ -75,6 +80,18 @@ namespace Microsoft.Extensions.DependencyInjection
builder.Services.TryAddSingleton<RequireUserinfoRequest>(); builder.Services.TryAddSingleton<RequireUserinfoRequest>();
builder.Services.TryAddSingleton<RequireVerificationRequest>(); builder.Services.TryAddSingleton<RequireVerificationRequest>();
builder.Services.TryAddSingleton<IStringLocalizer<OpenIddictResources>>(provider =>
{
// Note: the string localizer factory is deliberately not resolved from
// the DI container to ensure the built-in .resx files are always used
// even if the factory was replaced by a different implementation in DI.
var factory = new ResourceManagerStringLocalizerFactory(
localizationOptions: Options.Create(new LocalizationOptions()),
loggerFactory: NullLoggerFactory.Instance);
return new StringLocalizer<OpenIddictResources>(factory);
});
// Note: TryAddEnumerable() is used here to ensure the initializer is registered only once. // Note: TryAddEnumerable() is used here to ensure the initializer is registered only once.
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton< builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<
IPostConfigureOptions<OpenIddictServerOptions>, OpenIddictServerConfiguration>()); IPostConfigureOptions<OpenIddictServerOptions>, OpenIddictServerConfiguration>());

8
src/OpenIddict.Server/OpenIddictServerFactory.cs

@ -6,23 +6,28 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using OpenIddict.Abstractions.Resources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
public class OpenIddictServerFactory : IOpenIddictServerFactory public class OpenIddictServerFactory : IOpenIddictServerFactory
{ {
private readonly ILogger<OpenIddictServerDispatcher> _logger; private readonly IStringLocalizer _localizer;
private readonly ILogger _logger;
private readonly IOptionsMonitor<OpenIddictServerOptions> _options; private readonly IOptionsMonitor<OpenIddictServerOptions> _options;
/// <summary> /// <summary>
/// Creates a new instance of the <see cref="OpenIddictServerDispatcher"/> class. /// Creates a new instance of the <see cref="OpenIddictServerDispatcher"/> class.
/// </summary> /// </summary>
public OpenIddictServerFactory( public OpenIddictServerFactory(
[NotNull] IStringLocalizer<OpenIddictResources> localizer,
[NotNull] ILogger<OpenIddictServerDispatcher> logger, [NotNull] ILogger<OpenIddictServerDispatcher> logger,
[NotNull] IOptionsMonitor<OpenIddictServerOptions> options) [NotNull] IOptionsMonitor<OpenIddictServerOptions> options)
{ {
_localizer = localizer;
_logger = logger; _logger = logger;
_options = options; _options = options;
} }
@ -31,6 +36,7 @@ namespace OpenIddict.Server
=> new ValueTask<OpenIddictServerTransaction>(new OpenIddictServerTransaction => new ValueTask<OpenIddictServerTransaction>(new OpenIddictServerTransaction
{ {
Issuer = _options.CurrentValue.Issuer, Issuer = _options.CurrentValue.Issuer,
Localizer = _localizer,
Logger = _logger, Logger = _logger,
Options = _options.CurrentValue Options = _options.CurrentValue
}); });

7
src/OpenIddict.Server/OpenIddictServerHandlerDescriptor.cs

@ -13,6 +13,7 @@ using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -86,7 +87,7 @@ namespace OpenIddict.Server
if (!typeof(IOpenIddictServerHandlerFilter<>).MakeGenericType(typeof(TContext)).IsAssignableFrom(type)) if (!typeof(IOpenIddictServerHandlerFilter<>).MakeGenericType(typeof(TContext)).IsAssignableFrom(type))
{ {
throw new InvalidOperationException("The specified service type is not valid."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1103));
} }
_filterTypes.Add(type); _filterTypes.Add(type);
@ -118,7 +119,7 @@ namespace OpenIddict.Server
var type = descriptor.ServiceType; var type = descriptor.ServiceType;
if (!typeof(IOpenIddictServerHandler<>).MakeGenericType(typeof(TContext)).IsAssignableFrom(type)) if (!typeof(IOpenIddictServerHandler<>).MakeGenericType(typeof(TContext)).IsAssignableFrom(type))
{ {
throw new InvalidOperationException("The specified service type is not valid."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1103));
} }
_descriptor = descriptor; _descriptor = descriptor;
@ -216,7 +217,7 @@ namespace OpenIddict.Server
ContextType = typeof(TContext), ContextType = typeof(TContext),
FilterTypes = _filterTypes.ToImmutableArray(), FilterTypes = _filterTypes.ToImmutableArray(),
Order = _order, Order = _order,
ServiceDescriptor = _descriptor ?? throw new InvalidOperationException("No service descriptor was set."), ServiceDescriptor = _descriptor ?? throw new InvalidOperationException(SR.GetResourceString(SR.ID1104)),
Type = _type Type = _type
}; };
} }

169
src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs

@ -8,7 +8,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -16,6 +15,7 @@ using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.OpenIddictServerHandlerFilters; using static OpenIddict.Server.OpenIddictServerHandlerFilters;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -125,11 +125,7 @@ namespace OpenIddict.Server
if (notification.Request == null) if (notification.Request == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1026));
.Append("The authorization request was not correctly extracted. To extract authorization requests, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ExtractAuthorizationRequestContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
context.Logger.LogInformation("The authorization request was successfully extracted: {Request}.", notification.Request); context.Logger.LogInformation("The authorization request was successfully extracted: {Request}.", notification.Request);
@ -201,7 +197,7 @@ namespace OpenIddict.Server
if (string.IsNullOrEmpty(notification.RedirectUri)) if (string.IsNullOrEmpty(notification.RedirectUri))
{ {
throw new InvalidOperationException("The request cannot be validated because no redirect_uri was specified."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1027));
} }
context.Logger.LogInformation("The authorization request was successfully validated."); context.Logger.LogInformation("The authorization request was successfully validated.");
@ -299,14 +295,7 @@ namespace OpenIddict.Server
} }
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1028));
.Append("The authorization request was not handled. To handle authorization requests in a controller, ")
.Append("create a custom controller action with the same route as the authorization endpoint ")
.Append("and enable the pass-through mode in the server ASP.NET Core or OWIN options using ")
.AppendLine("'services.AddOpenIddict().AddServer().UseAspNetCore().EnableAuthorizationEndpointPassthrough()'.")
.Append("Alternatively, create a class implementing 'IOpenIddictServerHandler<HandleAuthorizationRequestContext>' ")
.Append("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
} }
@ -360,11 +349,7 @@ namespace OpenIddict.Server
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1029));
.Append("The authorization response was not correctly applied. To apply authorization responses, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ApplyAuthorizationResponseContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
} }
@ -401,11 +386,11 @@ namespace OpenIddict.Server
if (!string.IsNullOrEmpty(context.Request.Request)) if (!string.IsNullOrEmpty(context.Request.Request))
{ {
context.Logger.LogError("The authorization request was rejected because it contained " + context.Logger.LogError("The authorization request was rejected because it contained " +
"an unsupported parameter: {Parameter}.", "request"); "an unsupported parameter: {Parameter}.", Parameters.Request);
context.Reject( context.Reject(
error: Errors.RequestNotSupported, error: Errors.RequestNotSupported,
description: "The 'request' parameter is not supported."); description: context.Localizer[SR.ID3028, Parameters.Request]);
return default; return default;
} }
@ -447,11 +432,11 @@ namespace OpenIddict.Server
if (!string.IsNullOrEmpty(context.Request.RequestUri)) if (!string.IsNullOrEmpty(context.Request.RequestUri))
{ {
context.Logger.LogError("The authorization request was rejected because it contained " + context.Logger.LogError("The authorization request was rejected because it contained " +
"an unsupported parameter: {Parameter}.", "request_uri"); "an unsupported parameter: {Parameter}.", Parameters.RequestUri);
context.Reject( context.Reject(
error: Errors.RequestUriNotSupported, error: Errors.RequestUriNotSupported,
description: "The 'request_uri' parameter is not supported."); description: context.Localizer[SR.ID3028, Parameters.RequestUri]);
return default; return default;
} }
@ -498,7 +483,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'client_id' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.ClientId]);
return default; return default;
} }
@ -550,7 +535,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'redirect_uri' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.RedirectUri]);
return default; return default;
} }
@ -573,7 +558,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The 'redirect_uri' parameter must be a valid absolute URL."); description: context.Localizer[SR.ID3030, Parameters.RedirectUri]);
return default; return default;
} }
@ -588,7 +573,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The 'redirect_uri' parameter must not include a fragment."); description: context.Localizer[SR.ID3031, Parameters.RedirectUri]);
return default; return default;
} }
@ -634,7 +619,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'response_type' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.ResponseType]);
return default; return default;
} }
@ -649,7 +634,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnsupportedResponseType, error: Errors.UnsupportedResponseType,
description: "The specified 'response_type' parameter is not allowed."); description: context.Localizer[SR.ID3032, Parameters.ResponseType]);
return default; return default;
} }
@ -699,7 +684,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'response_type'/'response_mode' combination is invalid."); description: context.Localizer[SR.ID3033, Parameters.ResponseType, Parameters.ResponseMode]);
return default; return default;
} }
@ -713,7 +698,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'response_mode' parameter is not supported."); description: context.Localizer[SR.ID3032, Parameters.ResponseMode]);
return default; return default;
} }
@ -783,7 +768,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'openid' scope is missing."); description: context.Localizer[SR.ID3034, Scopes.OpenId]);
return default; return default;
} }
@ -793,7 +778,7 @@ namespace OpenIddict.Server
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The 'offline_access' scope is not allowed."); description: context.Localizer[SR.ID3035, Scopes.OfflineAccess]);
return default; return default;
} }
@ -847,7 +832,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'nonce' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.Nonce]);
return default; return default;
} }
@ -894,7 +879,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'prompt' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.Prompt]);
return default; return default;
} }
@ -945,7 +930,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The 'code_challenge_method' parameter cannot be used without 'code_challenge'."); description: context.Localizer[SR.ID3037, Parameters.CodeChallengeMethod, Parameters.CodeChallenge]);
return default; return default;
} }
@ -960,7 +945,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The 'code_challenge_method' parameter must be specified."); description: context.Localizer[SR.ID3029, Parameters.CodeChallengeMethod]);
return default; return default;
} }
@ -974,7 +959,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'code_challenge_method' parameter is not supported."); description: context.Localizer[SR.ID3032, Parameters.CodeChallengeMethod]);
return default; return default;
} }
@ -987,8 +972,8 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The 'code_challenge' and 'code_challenge_method' parameters " + description: context.Localizer[SR.ID3040, Parameters.CodeChallenge,
"can only be used with a response type containing 'code'."); Parameters.CodeChallengeMethod, ResponseTypes.Code]);
return default; return default;
} }
@ -1001,7 +986,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'response_type' parameter is not allowed when using PKCE."); description: context.Localizer[SR.ID3041, Parameters.ResponseType]);
return default; return default;
} }
@ -1018,13 +1003,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientId() => throw new InvalidOperationException(new StringBuilder() public ValidateClientId() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientId([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientId([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -1062,7 +1041,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'client_id' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.ClientId]);
return; return;
} }
@ -1078,13 +1057,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientType() => throw new InvalidOperationException(new StringBuilder() public ValidateClientType() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientType([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientType([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -1117,7 +1090,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// To prevent downgrade attacks, ensure that authorization requests returning an access token directly // To prevent downgrade attacks, ensure that authorization requests returning an access token directly
@ -1132,7 +1105,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnauthorizedClient, error: Errors.UnauthorizedClient,
description: "The specified 'response_type' parameter is not valid for this client application."); description: context.Localizer[SR.ID3043, Parameters.ResponseType]);
return; return;
} }
@ -1147,13 +1120,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientRedirectUri() => throw new InvalidOperationException(new StringBuilder() public ValidateClientRedirectUri() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientRedirectUri([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientRedirectUri([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -1186,7 +1153,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// If no explicit redirect_uri was specified, retrieve the addresses associated with // If no explicit redirect_uri was specified, retrieve the addresses associated with
@ -1201,7 +1168,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'redirect_uri' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.RedirectUri]);
return; return;
} }
@ -1219,7 +1186,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'redirect_uri' parameter is not valid for this client application."); description: context.Localizer[SR.ID3043, Parameters.RedirectUri]);
return; return;
} }
@ -1234,13 +1201,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictScopeManager _scopeManager; private readonly IOpenIddictScopeManager _scopeManager;
public ValidateScopes() => throw new InvalidOperationException(new StringBuilder() public ValidateScopes() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateScopes([NotNull] IOpenIddictScopeManager scopeManager) public ValidateScopes([NotNull] IOpenIddictScopeManager scopeManager)
=> _scopeManager = scopeManager; => _scopeManager = scopeManager;
@ -1291,7 +1252,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidScope, error: Errors.InvalidScope,
description: "The specified 'scope' parameter is not valid."); description: context.Localizer[SR.ID3052, Parameters.Scope]);
return; return;
} }
@ -1306,13 +1267,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateEndpointPermissions() => throw new InvalidOperationException(new StringBuilder() public ValidateEndpointPermissions() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateEndpointPermissions([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateEndpointPermissions([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -1346,7 +1301,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// Reject the request if the application is not allowed to use the authorization endpoint. // Reject the request if the application is not allowed to use the authorization endpoint.
@ -1357,7 +1312,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnauthorizedClient, error: Errors.UnauthorizedClient,
description: "This client application is not allowed to use the authorization endpoint."); description: context.Localizer[SR.ID3046]);
return; return;
} }
@ -1372,13 +1327,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateGrantTypePermissions() => throw new InvalidOperationException(new StringBuilder() public ValidateGrantTypePermissions() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateGrantTypePermissions([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateGrantTypePermissions([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -1412,7 +1361,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// Reject the request if the application is not allowed to use the authorization code flow. // Reject the request if the application is not allowed to use the authorization code flow.
@ -1424,7 +1373,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnauthorizedClient, error: Errors.UnauthorizedClient,
description: "The client application is not allowed to use the authorization code flow."); description: context.Localizer[SR.ID3047]);
return; return;
} }
@ -1438,7 +1387,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnauthorizedClient, error: Errors.UnauthorizedClient,
description: "The client application is not allowed to use the implicit flow."); description: context.Localizer[SR.ID3048]);
return; return;
} }
@ -1453,7 +1402,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnauthorizedClient, error: Errors.UnauthorizedClient,
description: "The client application is not allowed to use the hybrid flow."); description: context.Localizer[SR.ID3049]);
return; return;
} }
@ -1468,7 +1417,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The client application is not allowed to use the 'offline_access' scope."); description: context.Localizer[SR.ID3050]);
return; return;
} }
@ -1483,13 +1432,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateScopePermissions() => throw new InvalidOperationException(new StringBuilder() public ValidateScopePermissions() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateScopePermissions([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateScopePermissions([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -1523,7 +1466,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
foreach (var scope in context.Request.GetScopes()) foreach (var scope in context.Request.GetScopes())
@ -1543,7 +1486,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "This client application is not allowed to use the specified scope."); description: context.Localizer[SR.ID3051]);
return; return;
} }
@ -1560,13 +1503,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateProofKeyForCodeExchangeRequirement() => throw new InvalidOperationException(new StringBuilder() public ValidateProofKeyForCodeExchangeRequirement() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateProofKeyForCodeExchangeRequirement([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateProofKeyForCodeExchangeRequirement([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -1606,7 +1543,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
if (await _applicationManager.HasRequirementAsync(application, Requirements.Features.ProofKeyForCodeExchange)) if (await _applicationManager.HasRequirementAsync(application, Requirements.Features.ProofKeyForCodeExchange))
@ -1616,7 +1553,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'code_challenge' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.CodeChallenge]);
return; return;
} }

109
src/OpenIddict.Server/OpenIddictServerHandlers.Device.cs

@ -8,7 +8,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Security.Claims; using System.Security.Claims;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -16,6 +15,7 @@ using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.OpenIddictServerHandlerFilters; using static OpenIddict.Server.OpenIddictServerHandlerFilters;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -56,7 +56,7 @@ namespace OpenIddict.Server
ApplyVerificationResponse<ProcessErrorContext>.Descriptor, ApplyVerificationResponse<ProcessErrorContext>.Descriptor,
ApplyVerificationResponse<ProcessRequestContext>.Descriptor, ApplyVerificationResponse<ProcessRequestContext>.Descriptor,
ApplyVerificationResponse<ProcessSignInContext>.Descriptor, ApplyVerificationResponse<ProcessSignInContext>.Descriptor,
/* /*
* Verification request handling: * Verification request handling:
*/ */
@ -123,11 +123,7 @@ namespace OpenIddict.Server
if (notification.Request == null) if (notification.Request == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1030));
.Append("The device request was not correctly extracted. To extract device requests, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ExtractDeviceRequestContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
context.Logger.LogInformation("The device request was successfully extracted: {Request}.", notification.Request); context.Logger.LogInformation("The device request was successfully extracted: {Request}.", notification.Request);
@ -346,11 +342,7 @@ namespace OpenIddict.Server
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1032));
.Append("The device response was not correctly applied. To apply device responses, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ApplyDeviceResponseContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
} }
@ -391,7 +383,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The mandatory 'client_id' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.ClientId]);
return default; return default;
} }
@ -408,13 +400,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictScopeManager _scopeManager; private readonly IOpenIddictScopeManager _scopeManager;
public ValidateScopes() => throw new InvalidOperationException(new StringBuilder() public ValidateScopes() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateScopes([NotNull] IOpenIddictScopeManager scopeManager) public ValidateScopes([NotNull] IOpenIddictScopeManager scopeManager)
=> _scopeManager = scopeManager; => _scopeManager = scopeManager;
@ -465,7 +451,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidScope, error: Errors.InvalidScope,
description: "The specified 'scope' parameter is not valid."); description: context.Localizer[SR.ID3052, Parameters.Scope]);
return; return;
} }
@ -480,13 +466,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientId() => throw new InvalidOperationException(new StringBuilder() public ValidateClientId() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientId([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientId([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -527,7 +507,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The specified 'client_id' parameter is invalid."); description: context.Localizer[SR.ID3052]);
return; return;
} }
@ -543,13 +523,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientType() => throw new InvalidOperationException(new StringBuilder() public ValidateClientType() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientType([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientType([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -583,7 +557,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public)) if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public))
@ -596,7 +570,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The 'client_secret' parameter is not valid for this client application."); description: context.Localizer[SR.ID3053, Parameters.ClientSecret]);
return; return;
} }
@ -612,7 +586,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The 'client_secret' parameter required for this client application is missing."); description: context.Localizer[SR.ID3054, Parameters.ClientSecret]);
return; return;
} }
@ -627,13 +601,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientSecret() => throw new InvalidOperationException(new StringBuilder() public ValidateClientSecret() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientSecret([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientSecret([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -667,7 +635,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// If the application is not a public client, validate the client secret. // If the application is not a public client, validate the client secret.
@ -679,7 +647,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The specified client credentials are invalid."); description: context.Localizer[SR.ID3055]);
return; return;
} }
@ -695,13 +663,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateEndpointPermissions() => throw new InvalidOperationException(new StringBuilder() public ValidateEndpointPermissions() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateEndpointPermissions([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateEndpointPermissions([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -736,7 +698,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// Reject the request if the application is not allowed to use the device endpoint. // Reject the request if the application is not allowed to use the device endpoint.
@ -747,7 +709,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnauthorizedClient, error: Errors.UnauthorizedClient,
description: "This client application is not allowed to use the device endpoint."); description: context.Localizer[SR.ID3056]);
return; return;
} }
@ -763,13 +725,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateScopePermissions() => throw new InvalidOperationException(new StringBuilder() public ValidateScopePermissions() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateScopePermissions([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateScopePermissions([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -804,7 +760,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
foreach (var scope in context.Request.GetScopes()) foreach (var scope in context.Request.GetScopes())
@ -824,7 +780,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "This client application is not allowed to use the specified scope."); description: context.Localizer[SR.ID3051]);
return; return;
} }
@ -893,11 +849,7 @@ namespace OpenIddict.Server
if (notification.Request == null) if (notification.Request == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1033));
.Append("The verification request was not correctly extracted. To extract verification requests, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ExtractVerificationRequestContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
context.Logger.LogInformation("The verification request was successfully extracted: {Request}.", notification.Request); context.Logger.LogInformation("The verification request was successfully extracted: {Request}.", notification.Request);
@ -1058,14 +1010,7 @@ namespace OpenIddict.Server
} }
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1034));
.Append("The verification request was not handled. To handle verification requests in a controller, ")
.Append("create a custom controller action with the same route as the verification endpoint ")
.Append("and enable the pass-through mode in the server ASP.NET Core or OWIN options using ")
.AppendLine("'services.AddOpenIddict().AddServer().UseAspNetCore().EnableVerificationEndpointPassthrough()'.")
.Append("Alternatively, create a class implementing 'IOpenIddictServerHandler<HandleVerificationRequestContext>' ")
.Append("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
} }
@ -1119,11 +1064,7 @@ namespace OpenIddict.Server
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1035));
.Append("The verification response was not correctly applied. To apply verification responses, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ApplyVerificationResponseContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
} }

23
src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs

@ -21,6 +21,7 @@ using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.OpenIddictServerHandlerFilters; using static OpenIddict.Server.OpenIddictServerHandlerFilters;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -128,11 +129,7 @@ namespace OpenIddict.Server
if (notification.Request == null) if (notification.Request == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1036));
.Append("The configuration request was not correctly extracted. To extract configuration requests, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ExtractConfigurationRequestContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
context.Logger.LogInformation("The configuration request was successfully extracted: {Request}.", notification.Request); context.Logger.LogInformation("The configuration request was successfully extracted: {Request}.", notification.Request);
@ -427,7 +424,7 @@ namespace OpenIddict.Server
// At this stage, throw an exception if the issuer cannot be retrieved. // At this stage, throw an exception if the issuer cannot be retrieved.
if (issuer == null || !issuer.IsAbsoluteUri) if (issuer == null || !issuer.IsAbsoluteUri)
{ {
throw new InvalidOperationException("The issuer must be a non-null, non-empty absolute URL."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1022));
} }
// Ensure the issuer ends with a trailing slash, as it is necessary // Ensure the issuer ends with a trailing slash, as it is necessary
@ -919,11 +916,7 @@ namespace OpenIddict.Server
if (notification.Request == null) if (notification.Request == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1037));
.Append("The cryptography request was not correctly extracted. To extract configuration requests, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ExtractCryptographyRequestContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
context.Logger.LogInformation("The cryptography request was successfully extracted: {Request}.", notification.Request); context.Logger.LogInformation("The cryptography request was successfully extracted: {Request}.", notification.Request);
@ -1178,11 +1171,7 @@ namespace OpenIddict.Server
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1038));
.Append("The cryptography response was not correctly applied. To apply cryptography responses, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ApplyCryptographyResponseContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
} }
@ -1399,7 +1388,7 @@ namespace OpenIddict.Server
using var hash = CryptoConfig.CreateFromName(algorithm.Name) as HashAlgorithm; using var hash = CryptoConfig.CreateFromName(algorithm.Name) as HashAlgorithm;
if (hash == null || hash is KeyedHashAlgorithm) if (hash == null || hash is KeyedHashAlgorithm)
{ {
throw new InvalidOperationException("The specified hash algorithm is not valid."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1216));
} }
return hash.ComputeHash(certificate.RawData); return hash.ComputeHash(certificate.RawData);

182
src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs

@ -17,6 +17,7 @@ using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.OpenIddictServerHandlerFilters; using static OpenIddict.Server.OpenIddictServerHandlerFilters;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
#if !SUPPORTS_TIME_CONSTANT_COMPARISONS #if !SUPPORTS_TIME_CONSTANT_COMPARISONS
using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities;
@ -130,11 +131,7 @@ namespace OpenIddict.Server
if (notification.Request == null) if (notification.Request == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1039));
.Append("The token request was not correctly extracted. To extract token requests, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ExtractTokenRequestContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
context.Logger.LogInformation("The token request was successfully extracted: {Request}.", notification.Request); context.Logger.LogInformation("The token request was successfully extracted: {Request}.", notification.Request);
@ -299,14 +296,7 @@ namespace OpenIddict.Server
} }
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1040));
.Append("The token request was not handled. To handle token requests in a controller, ")
.Append("create a custom controller action with the same route as the token endpoint ")
.Append("and enable the pass-through mode in the server ASP.NET Core or OWIN options using ")
.AppendLine("'services.AddOpenIddict().AddServer().UseAspNetCore().EnableTokenEndpointPassthrough()'.")
.Append("Alternatively, create a class implementing 'IOpenIddictServerHandler<HandleTokenRequestContext>' ")
.Append("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
} }
@ -360,11 +350,7 @@ namespace OpenIddict.Server
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1041));
.Append("The token response was not correctly applied. To apply token responses, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ApplyTokenResponseContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
} }
@ -404,7 +390,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'grant_type' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.GrantType]);
return default; return default;
} }
@ -417,7 +403,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnsupportedGrantType, error: Errors.UnsupportedGrantType,
description: "The specified 'grant_type' parameter is not supported."); description: context.Localizer[SR.ID3032, Parameters.GrantType]);
return default; return default;
} }
@ -428,7 +414,7 @@ namespace OpenIddict.Server
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The 'offline_access' scope is not allowed."); description: context.Localizer[SR.ID3035, Scopes.OfflineAccess]);
return default; return default;
} }
@ -482,7 +468,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The mandatory 'client_id' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.ClientId]);
return default; return default;
} }
@ -529,7 +515,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'code' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.Code]);
return default; return default;
} }
@ -575,8 +561,7 @@ namespace OpenIddict.Server
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The 'client_id' and 'client_secret' parameters are " + description: context.Localizer[SR.ID3057, Parameters.ClientId, Parameters.ClientSecret]);
"required when using the client credentials grant.");
return default; return default;
} }
@ -621,7 +606,7 @@ namespace OpenIddict.Server
{ {
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The 'device_code' parameter is required when using the device code grant."); description: context.Localizer[SR.ID3058, Parameters.DeviceCode]);
return default; return default;
} }
@ -668,7 +653,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'refresh_token' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.RefreshToken]);
return default; return default;
} }
@ -716,7 +701,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'username' and/or 'password' parameters are missing."); description: context.Localizer[SR.ID3059, Parameters.Username, Parameters.Password]);
return default; return default;
} }
@ -733,13 +718,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictScopeManager _scopeManager; private readonly IOpenIddictScopeManager _scopeManager;
public ValidateScopes() => throw new InvalidOperationException(new StringBuilder() public ValidateScopes() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateScopes([NotNull] IOpenIddictScopeManager scopeManager) public ValidateScopes([NotNull] IOpenIddictScopeManager scopeManager)
=> _scopeManager = scopeManager; => _scopeManager = scopeManager;
@ -790,7 +769,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidScope, error: Errors.InvalidScope,
description: "The specified 'scope' parameter is not valid."); description: context.Localizer[SR.ID3052, Parameters.Scope]);
return; return;
} }
@ -805,13 +784,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientId() => throw new InvalidOperationException(new StringBuilder() public ValidateClientId() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientId([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientId([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -852,7 +825,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The specified 'client_id' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.ClientId]);
return; return;
} }
@ -868,13 +841,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientType() => throw new InvalidOperationException(new StringBuilder() public ValidateClientType() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientType([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientType([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -908,7 +875,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public)) if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public))
@ -921,7 +888,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnauthorizedClient, error: Errors.UnauthorizedClient,
description: "The specified 'grant_type' parameter is not valid for this client application."); description: context.Localizer[SR.ID3043, Parameters.GrantType]);
return; return;
} }
@ -934,7 +901,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The 'client_secret' parameter is not valid for this client application."); description: context.Localizer[SR.ID3061, Parameters.ClientSecret]);
return; return;
} }
@ -950,7 +917,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The 'client_secret' parameter required for this client application is missing."); description: context.Localizer[SR.ID3062, Parameters.ClientSecret]);
return; return;
} }
@ -965,13 +932,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientSecret() => throw new InvalidOperationException(new StringBuilder() public ValidateClientSecret() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientSecret([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientSecret([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -1005,7 +966,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// If the application is not a public client, validate the client secret. // If the application is not a public client, validate the client secret.
@ -1017,7 +978,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The specified client credentials are invalid."); description: context.Localizer[SR.ID3055]);
return; return;
} }
@ -1033,13 +994,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateEndpointPermissions() => throw new InvalidOperationException(new StringBuilder() public ValidateEndpointPermissions() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateEndpointPermissions([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateEndpointPermissions([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -1074,7 +1029,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// Reject the request if the application is not allowed to use the token endpoint. // Reject the request if the application is not allowed to use the token endpoint.
@ -1085,7 +1040,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnauthorizedClient, error: Errors.UnauthorizedClient,
description: "This client application is not allowed to use the token endpoint."); description: context.Localizer[SR.ID3063]);
return; return;
} }
@ -1101,13 +1056,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateGrantTypePermissions() => throw new InvalidOperationException(new StringBuilder() public ValidateGrantTypePermissions() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateGrantTypePermissions([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateGrantTypePermissions([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -1142,7 +1091,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// Reject the request if the application is not allowed to use the specified grant type. // Reject the request if the application is not allowed to use the specified grant type.
@ -1153,7 +1102,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnauthorizedClient, error: Errors.UnauthorizedClient,
description: "This client application is not allowed to use the specified grant type."); description: context.Localizer[SR.ID3064]);
return; return;
} }
@ -1168,7 +1117,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The client application is not allowed to use the 'offline_access' scope."); description: context.Localizer[SR.ID3065, Scopes.OfflineAccess]);
return; return;
} }
@ -1184,13 +1133,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateScopePermissions() => throw new InvalidOperationException(new StringBuilder() public ValidateScopePermissions() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateScopePermissions([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateScopePermissions([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -1225,7 +1168,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
foreach (var scope in context.Request.GetScopes()) foreach (var scope in context.Request.GetScopes())
@ -1245,7 +1188,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "This client application is not allowed to use the specified scope."); description: context.Localizer[SR.ID3051]);
return; return;
} }
@ -1262,13 +1205,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateProofKeyForCodeExchangeRequirement() => throw new InvalidOperationException(new StringBuilder() public ValidateProofKeyForCodeExchangeRequirement() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateProofKeyForCodeExchangeRequirement([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateProofKeyForCodeExchangeRequirement([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -1314,7 +1251,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
if (await _applicationManager.HasRequirementAsync(application, Requirements.Features.ProofKeyForCodeExchange)) if (await _applicationManager.HasRequirementAsync(application, Requirements.Features.ProofKeyForCodeExchange))
@ -1324,7 +1261,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'code_verifier' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.CodeVerifier]);
return; return;
} }
@ -1450,12 +1387,12 @@ namespace OpenIddict.Server
// was issued to a public client but cannot be null for an authorization or device code grant request. // was issued to a public client but cannot be null for an authorization or device code grant request.
if (context.Request.IsAuthorizationCodeGrantType()) if (context.Request.IsAuthorizationCodeGrantType())
{ {
throw new InvalidOperationException("The presenters list cannot be extracted from the authorization code."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1042));
} }
if (context.Request.IsDeviceCodeGrantType()) if (context.Request.IsDeviceCodeGrantType())
{ {
throw new InvalidOperationException("The presenters list cannot be extracted from the device code."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1043));
} }
return default; return default;
@ -1471,12 +1408,9 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidGrant, error: Errors.InvalidGrant,
description: description: context.Request.IsAuthorizationCodeGrantType() ? context.Localizer[SR.ID3066] :
context.Request.IsAuthorizationCodeGrantType() ? context.Request.IsDeviceCodeGrantType() ? context.Localizer[SR.ID3067] :
"The specified authorization code cannot be used without specifying a client identifier." : context.Localizer[SR.ID3068]);
context.Request.IsDeviceCodeGrantType() ?
"The specified device code cannot be used without specifying a client identifier." :
"The specified refresh token cannot be used without specifying a client identifier.");
return default; return default;
} }
@ -1492,12 +1426,9 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidGrant, error: Errors.InvalidGrant,
description: description: context.Request.IsAuthorizationCodeGrantType() ? context.Localizer[SR.ID3069] :
context.Request.IsAuthorizationCodeGrantType() ? context.Request.IsDeviceCodeGrantType() ? context.Localizer[SR.ID3070] :
"The specified authorization code cannot be used by this client application." : context.Localizer[SR.ID3071]);
context.Request.IsDeviceCodeGrantType() ?
"The specified device code cannot be used by this client application." :
"The specified refresh token cannot be used by this client application.");
return default; return default;
} }
@ -1560,7 +1491,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'redirect_uri' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.RedirectUri]);
return default; return default;
} }
@ -1572,8 +1503,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidGrant, error: Errors.InvalidGrant,
description: "The specified 'redirect_uri' parameter doesn't match the client " + description: context.Localizer[SR.ID3072, Parameters.RedirectUri]);
"redirection endpoint the authorization code was initially sent to.");
return default; return default;
} }
@ -1635,7 +1565,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The 'code_verifier' parameter is uncalled for in this request."); description: context.Localizer[SR.ID3073, Parameters.CodeVerifier]);
return default; return default;
} }
@ -1651,7 +1581,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'code_verifier' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.CodeVerifier]);
return default; return default;
} }
@ -1660,7 +1590,7 @@ namespace OpenIddict.Server
var method = context.Principal.GetClaim(Claims.Private.CodeChallengeMethod); var method = context.Principal.GetClaim(Claims.Private.CodeChallengeMethod);
if (string.IsNullOrEmpty(method)) if (string.IsNullOrEmpty(method))
{ {
throw new InvalidOperationException("The code challenge method cannot be retrieved from the authorization code."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1267));
} }
// Note: when using the "plain" code challenge method, no hashing is actually performed. // Note: when using the "plain" code challenge method, no hashing is actually performed.
@ -1680,7 +1610,7 @@ namespace OpenIddict.Server
else else
{ {
throw new InvalidOperationException("The specified code challenge method is not supported."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1044));
} }
// Compare the verifier and the code challenge: if the two don't match, return an error. // Compare the verifier and the code challenge: if the two don't match, return an error.
@ -1695,7 +1625,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidGrant, error: Errors.InvalidGrant,
description: "The specified 'code_verifier' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.CodeVerifier]);
return default; return default;
} }
@ -1747,7 +1677,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidGrant, error: Errors.InvalidGrant,
description: "The 'scope' parameter is not valid in this context."); description: context.Localizer[SR.ID3074, Parameters.Scope]);
return default; return default;
} }
@ -1762,7 +1692,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidGrant, error: Errors.InvalidGrant,
description: "The specified 'scope' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.Scope]);
return default; return default;
} }
@ -1808,7 +1738,7 @@ namespace OpenIddict.Server
var notification = context.Transaction.GetProperty<ValidateTokenRequestContext>( var notification = context.Transaction.GetProperty<ValidateTokenRequestContext>(
typeof(ValidateTokenRequestContext).FullName) ?? typeof(ValidateTokenRequestContext).FullName) ??
throw new InvalidOperationException("The authentication context cannot be found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1006));
context.Principal ??= notification.Principal; context.Principal ??= notification.Principal;

90
src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs

@ -9,7 +9,6 @@ using System.Collections.Immutable;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -21,6 +20,7 @@ using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.OpenIddictServerHandlerFilters; using static OpenIddict.Server.OpenIddictServerHandlerFilters;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -124,11 +124,7 @@ namespace OpenIddict.Server
if (notification.Request == null) if (notification.Request == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1045));
.Append("The introspection request was not correctly extracted. To extract introspection requests, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ExtractIntrospectionRequestContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
context.Logger.LogInformation("The introspection request was successfully extracted: {Request}.", notification.Request); context.Logger.LogInformation("The introspection request was successfully extracted: {Request}.", notification.Request);
@ -361,11 +357,7 @@ namespace OpenIddict.Server
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1046));
.Append("The introspection response was not correctly applied. To apply introspection responses, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ApplyIntrospectionResponseContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
} }
@ -405,7 +397,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'token' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.Token]);
return default; return default;
} }
@ -450,7 +442,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The mandatory 'client_id' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.ClientId]);
return default; return default;
} }
@ -467,13 +459,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientId() => throw new InvalidOperationException(new StringBuilder() public ValidateClientId() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientId([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientId([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -514,7 +500,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The specified 'client_id' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.ClientId]);
return; return;
} }
@ -530,13 +516,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientType() => throw new InvalidOperationException(new StringBuilder() public ValidateClientType() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientType([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientType([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -570,7 +550,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public)) if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public))
@ -583,7 +563,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The 'client_secret' parameter is not valid for this client application."); description: context.Localizer[SR.ID3061, Parameters.ClientSecret]);
return; return;
} }
@ -599,7 +579,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The 'client_secret' parameter required for this client application is missing."); description: context.Localizer[SR.ID3062, Parameters.ClientSecret]);
return; return;
} }
@ -614,13 +594,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientSecret() => throw new InvalidOperationException(new StringBuilder() public ValidateClientSecret() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientSecret([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientSecret([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -654,7 +628,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// If the application is not a public client, validate the client secret. // If the application is not a public client, validate the client secret.
@ -666,7 +640,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The specified client credentials are invalid."); description: context.Localizer[SR.ID3055]);
return; return;
} }
@ -682,13 +656,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateEndpointPermissions() => throw new InvalidOperationException(new StringBuilder() public ValidateEndpointPermissions() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateEndpointPermissions([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateEndpointPermissions([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -723,7 +691,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// Reject the request if the application is not allowed to use the introspection endpoint. // Reject the request if the application is not allowed to use the introspection endpoint.
@ -734,7 +702,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnauthorizedClient, error: Errors.UnauthorizedClient,
description: "This client application is not allowed to use the introspection endpoint."); description: context.Localizer[SR.ID3075]);
return; return;
} }
@ -843,7 +811,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnsupportedTokenType, error: Errors.UnsupportedTokenType,
description: "The specified token cannot be introspected."); description: context.Localizer[SR.ID3076]);
return default; return default;
} }
@ -892,7 +860,7 @@ namespace OpenIddict.Server
{ {
if (!context.Principal.HasPresenter()) if (!context.Principal.HasPresenter())
{ {
throw new InvalidOperationException("The presenters list cannot be extracted from the authorization code."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1042));
} }
if (!context.Principal.HasPresenter(context.ClientId)) if (!context.Principal.HasPresenter(context.ClientId))
@ -902,7 +870,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidToken, error: Errors.InvalidToken,
description: "The client application is not allowed to introspect the specified token."); description: context.Localizer[SR.ID3077]);
return default; return default;
} }
@ -923,7 +891,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidToken, error: Errors.InvalidToken,
description: "The client application is not allowed to introspect the specified token."); description: context.Localizer[SR.ID3077]);
return default; return default;
} }
@ -940,7 +908,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidToken, error: Errors.InvalidToken,
description: "The client application is not allowed to introspect the specified token."); description: context.Localizer[SR.ID3077]);
return default; return default;
} }
@ -957,7 +925,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidToken, error: Errors.InvalidToken,
description: "The client application is not allowed to introspect the specified token."); description: context.Localizer[SR.ID3077]);
return default; return default;
} }
@ -998,7 +966,7 @@ namespace OpenIddict.Server
var notification = context.Transaction.GetProperty<ValidateIntrospectionRequestContext>( var notification = context.Transaction.GetProperty<ValidateIntrospectionRequestContext>(
typeof(ValidateIntrospectionRequestContext).FullName) ?? typeof(ValidateIntrospectionRequestContext).FullName) ??
throw new InvalidOperationException("The authentication context cannot be found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1006));
context.Principal ??= notification.Principal; context.Principal ??= notification.Principal;
@ -1068,13 +1036,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public AttachApplicationClaims() => throw new InvalidOperationException(new StringBuilder() public AttachApplicationClaims() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public AttachApplicationClaims([NotNull] IOpenIddictApplicationManager applicationManager) public AttachApplicationClaims([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -1122,7 +1084,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.Request.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.Request.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// Public clients are not allowed to access sensitive claims as authentication cannot be enforced. // Public clients are not allowed to access sensitive claims as authentication cannot be enforced.

94
src/OpenIddict.Server/OpenIddictServerHandlers.Revocation.cs

@ -6,7 +6,6 @@
using System; using System;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -14,6 +13,7 @@ using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.OpenIddictServerHandlerFilters; using static OpenIddict.Server.OpenIddictServerHandlerFilters;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -116,11 +116,7 @@ namespace OpenIddict.Server
if (notification.Request == null) if (notification.Request == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1047));
.Append("The revocation request was not correctly extracted. To extract revocation requests, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ExtractRevocationRequestContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
context.Logger.LogInformation("The revocation request was successfully extracted: {Request}.", notification.Request); context.Logger.LogInformation("The revocation request was successfully extracted: {Request}.", notification.Request);
@ -307,11 +303,7 @@ namespace OpenIddict.Server
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1048));
.Append("The revocation response was not correctly applied. To apply revocation responses, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ApplyRevocationResponseContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
} }
@ -351,7 +343,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The mandatory 'token' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.Token]);
return default; return default;
} }
@ -396,7 +388,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The mandatory 'client_id' parameter is missing."); description: context.Localizer[SR.ID3029, Parameters.ClientId]);
return default; return default;
} }
@ -413,13 +405,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientId() => throw new InvalidOperationException(new StringBuilder() public ValidateClientId() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientId([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientId([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -460,7 +446,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The specified 'client_id' parameter is invalid."); description: context.Localizer[SR.ID3052, Parameters.ClientId]);
return; return;
} }
@ -476,13 +462,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientType() => throw new InvalidOperationException(new StringBuilder() public ValidateClientType() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientType([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientType([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -516,7 +496,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public)) if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public))
@ -529,7 +509,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The 'client_secret' parameter is not valid for this client application."); description: context.Localizer[SR.ID3061, Parameters.ClientSecret]);
return; return;
} }
@ -545,7 +525,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The 'client_secret' parameter required for this client application is missing."); description: context.Localizer[SR.ID3062, Parameters.ClientSecret]);
return; return;
} }
@ -560,13 +540,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientSecret() => throw new InvalidOperationException(new StringBuilder() public ValidateClientSecret() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientSecret([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientSecret([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -600,7 +574,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// If the application is not a public client, validate the client secret. // If the application is not a public client, validate the client secret.
@ -612,7 +586,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidClient, error: Errors.InvalidClient,
description: "The specified client credentials are invalid."); description: context.Localizer[SR.ID3055]);
return; return;
} }
@ -628,13 +602,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateEndpointPermissions() => throw new InvalidOperationException(new StringBuilder() public ValidateEndpointPermissions() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateEndpointPermissions([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateEndpointPermissions([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -669,7 +637,7 @@ namespace OpenIddict.Server
var application = await _applicationManager.FindByClientIdAsync(context.ClientId); var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null) if (application == null)
{ {
throw new InvalidOperationException("The client application details cannot be found in the database."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1031));
} }
// Reject the request if the application is not allowed to use the revocation endpoint. // Reject the request if the application is not allowed to use the revocation endpoint.
@ -680,7 +648,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnauthorizedClient, error: Errors.UnauthorizedClient,
description: "This client application is not allowed to use the revocation endpoint."); description: context.Localizer[SR.ID3078]);
return; return;
} }
@ -788,7 +756,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnsupportedTokenType, error: Errors.UnsupportedTokenType,
description: "This token cannot be revoked."); description: context.Localizer[SR.ID3079]);
return default; return default;
} }
@ -837,7 +805,7 @@ namespace OpenIddict.Server
{ {
if (!context.Principal.HasPresenter()) if (!context.Principal.HasPresenter())
{ {
throw new InvalidOperationException("The presenters list cannot be extracted from the authorization code."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1042));
} }
if (!context.Principal.HasPresenter(context.ClientId)) if (!context.Principal.HasPresenter(context.ClientId))
@ -847,7 +815,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidToken, error: Errors.InvalidToken,
description: "The client application is not allowed to revoke the specified token."); description: context.Localizer[SR.ID3080]);
return default; return default;
} }
@ -868,7 +836,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidToken, error: Errors.InvalidToken,
description: "The client application is not allowed to revoke the specified token."); description: context.Localizer[SR.ID3080]);
return default; return default;
} }
@ -885,7 +853,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidToken, error: Errors.InvalidToken,
description: "The client application is not allowed to revoke the specified token."); description: context.Localizer[SR.ID3080]);
return default; return default;
} }
@ -902,7 +870,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidToken, error: Errors.InvalidToken,
description: "The client application is not allowed to revoke the specified token."); description: context.Localizer[SR.ID3080]);
return default; return default;
} }
@ -943,7 +911,7 @@ namespace OpenIddict.Server
var notification = context.Transaction.GetProperty<ValidateRevocationRequestContext>( var notification = context.Transaction.GetProperty<ValidateRevocationRequestContext>(
typeof(ValidateRevocationRequestContext).FullName) ?? typeof(ValidateRevocationRequestContext).FullName) ??
throw new InvalidOperationException("The authentication context cannot be found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1006));
context.Principal ??= notification.Principal; context.Principal ??= notification.Principal;
@ -959,13 +927,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictTokenManager _tokenManager; private readonly IOpenIddictTokenManager _tokenManager;
public RevokeToken() => throw new InvalidOperationException(new StringBuilder() public RevokeToken() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public RevokeToken([NotNull] IOpenIddictTokenManager tokenManager) public RevokeToken([NotNull] IOpenIddictTokenManager tokenManager)
=> _tokenManager = tokenManager; => _tokenManager = tokenManager;
@ -1003,7 +965,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.UnsupportedTokenType, error: Errors.UnsupportedTokenType,
description: "The specified token cannot be revoked."); description: context.Localizer[SR.ID3079]);
return; return;
} }
@ -1015,7 +977,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidToken, error: Errors.InvalidToken,
description: "The specified token is invalid."); description: context.Localizer[SR.ID3004]);
return; return;
} }
@ -1025,7 +987,7 @@ namespace OpenIddict.Server
{ {
context.Reject( context.Reject(
error: Errors.UnsupportedTokenType, error: Errors.UnsupportedTokenType,
description: "The specified token cannot be revoked."); description: context.Localizer[SR.ID3079]);
return; return;
} }

37
src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs

@ -6,7 +6,6 @@
using System; using System;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -14,6 +13,7 @@ using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.OpenIddictServerHandlerFilters; using static OpenIddict.Server.OpenIddictServerHandlerFilters;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -105,11 +105,7 @@ namespace OpenIddict.Server
if (notification.Request == null) if (notification.Request == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1049));
.Append("The logout request was not correctly extracted. To extract logout requests, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ExtractLogoutRequestContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
context.Logger.LogInformation("The logout request was successfully extracted: {Request}.", notification.Request); context.Logger.LogInformation("The logout request was successfully extracted: {Request}.", notification.Request);
@ -273,14 +269,7 @@ namespace OpenIddict.Server
} }
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1050));
.Append("The logout request was not handled. To handle logout requests in a controller, ")
.Append("create a custom controller action with the same route as the logout endpoint ")
.Append("and enable the pass-through mode in the server ASP.NET Core or OWIN options using ")
.AppendLine("'services.AddOpenIddict().AddServer().UseAspNetCore().EnableLogoutEndpointPassthrough()'.")
.Append("Alternatively, create a class implementing 'IOpenIddictServerHandler<HandleLogoutRequestContext>' ")
.Append("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
} }
@ -334,11 +323,7 @@ namespace OpenIddict.Server
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1051));
.Append("The revocation response was not correctly applied. To apply revocation responses, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ApplyRevocationResponseContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
} }
@ -384,7 +369,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The 'post_logout_redirect_uri' parameter must be a valid absolute URL."); description: context.Localizer[SR.ID3030, Parameters.PostLogoutRedirectUri]);
return default; return default;
} }
@ -396,7 +381,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The 'post_logout_redirect_uri' parameter must not include a fragment."); description: context.Localizer[SR.ID3031, Parameters.PostLogoutRedirectUri]);
return default; return default;
} }
@ -413,13 +398,7 @@ namespace OpenIddict.Server
{ {
private readonly IOpenIddictApplicationManager _applicationManager; private readonly IOpenIddictApplicationManager _applicationManager;
public ValidateClientPostLogoutRedirectUri() => throw new InvalidOperationException(new StringBuilder() public ValidateClientPostLogoutRedirectUri() => throw new InvalidOperationException(SR.GetResourceString(SR.ID1015));
.AppendLine("The core services must be registered when enabling the OpenIddict server feature.")
.Append("To register the OpenIddict core services, reference the 'OpenIddict.Core' package ")
.AppendLine("and call 'services.AddOpenIddict().AddCore()' from 'ConfigureServices'.")
.Append("Alternatively, you can disable the built-in database-based server features by enabling ")
.Append("the degraded mode with 'services.AddOpenIddict().AddServer().EnableDegradedMode()'.")
.ToString());
public ValidateClientPostLogoutRedirectUri([NotNull] IOpenIddictApplicationManager applicationManager) public ValidateClientPostLogoutRedirectUri([NotNull] IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager; => _applicationManager = applicationManager;
@ -457,7 +436,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.InvalidRequest, error: Errors.InvalidRequest,
description: "The specified 'post_logout_redirect_uri' parameter is not valid."); description: context.Localizer[SR.ID3052, Parameters.PostLogoutRedirectUri]);
return; return;
} }

18
src/OpenIddict.Server/OpenIddictServerHandlers.Userinfo.cs

@ -7,7 +7,6 @@
using System; using System;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -15,6 +14,7 @@ using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Server.OpenIddictServerEvents; using static OpenIddict.Server.OpenIddictServerEvents;
using static OpenIddict.Server.OpenIddictServerHandlerFilters; using static OpenIddict.Server.OpenIddictServerHandlerFilters;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -107,11 +107,7 @@ namespace OpenIddict.Server
if (notification.Request == null) if (notification.Request == null)
{ {
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1052));
.Append("The userinfo request was not correctly extracted. To extract userinfo requests, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ExtractUserinfoRequestContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
context.Logger.LogInformation("The userinfo request was successfully extracted: {Request}.", notification.Request); context.Logger.LogInformation("The userinfo request was successfully extracted: {Request}.", notification.Request);
@ -333,11 +329,7 @@ namespace OpenIddict.Server
return; return;
} }
throw new InvalidOperationException(new StringBuilder() throw new InvalidOperationException(SR.GetResourceString(SR.ID1053));
.Append("The userinfo response was not correctly applied. To apply userinfo responses, ")
.Append("create a class implementing 'IOpenIddictServerHandler<ApplyUserinfoResponseContext>' ")
.AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.")
.ToString());
} }
} }
@ -376,7 +368,7 @@ namespace OpenIddict.Server
context.Reject( context.Reject(
error: Errors.MissingToken, error: Errors.MissingToken,
description: "The mandatory access token is missing."); description: context.Localizer[SR.ID3029, Parameters.AccessToken]);
return default; return default;
} }
@ -480,7 +472,7 @@ namespace OpenIddict.Server
var notification = context.Transaction.GetProperty<ValidateUserinfoRequestContext>( var notification = context.Transaction.GetProperty<ValidateUserinfoRequestContext>(
typeof(ValidateUserinfoRequestContext).FullName) ?? typeof(ValidateUserinfoRequestContext).FullName) ??
throw new InvalidOperationException("The authentication context cannot be found."); throw new InvalidOperationException(SR.GetResourceString(SR.ID1006));
context.Principal ??= notification.Principal; context.Principal ??= notification.Principal;

466
src/OpenIddict.Server/OpenIddictServerHandlers.cs

File diff suppressed because it is too large

5
src/OpenIddict.Server/OpenIddictServerHelpers.cs

@ -6,6 +6,7 @@
using System; using System;
using JetBrains.Annotations; using JetBrains.Annotations;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -31,7 +32,7 @@ namespace OpenIddict.Server
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The property name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1105), nameof(name));
} }
if (transaction.Properties.TryGetValue(name, out var property) && property is TProperty result) if (transaction.Properties.TryGetValue(name, out var property) && property is TProperty result)
@ -61,7 +62,7 @@ namespace OpenIddict.Server
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
{ {
throw new ArgumentException("The property name cannot be null or empty.", nameof(name)); throw new ArgumentException(SR.GetResourceString(SR.ID1105), nameof(name));
} }
if (value == null) if (value == null)

7
src/OpenIddict.Server/OpenIddictServerOptions.cs

@ -12,6 +12,7 @@ using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants; using static OpenIddict.Abstractions.OpenIddictConstants;
using SR = OpenIddict.Abstractions.Resources.OpenIddictResources;
namespace OpenIddict.Server namespace OpenIddict.Server
{ {
@ -146,7 +147,7 @@ namespace OpenIddict.Server
TokenTypeHints.AccessToken => JsonWebTokenTypes.AccessToken, TokenTypeHints.AccessToken => JsonWebTokenTypes.AccessToken,
TokenTypeHints.IdToken => JsonWebTokenTypes.IdentityToken, TokenTypeHints.IdToken => JsonWebTokenTypes.IdentityToken,
_ => throw new NotSupportedException("The token usage of the JWT token is not supported.") _ => throw new NotSupportedException(SR.GetResourceString(SR.ID1268))
}; };
} }
@ -154,14 +155,14 @@ namespace OpenIddict.Server
// (provided via the type delegate parameter) or inferred from the token_usage claim. // (provided via the type delegate parameter) or inferred from the token_usage claim.
if (string.IsNullOrEmpty(type)) if (string.IsNullOrEmpty(type))
{ {
throw new SecurityTokenInvalidTypeException("The type of the JWT token cannot be resolved or inferred."); throw new SecurityTokenInvalidTypeException(SR.GetResourceString(SR.ID1269));
} }
// Note: unlike IdentityModel, this custom validator deliberately uses case-insensitive comparisons. // Note: unlike IdentityModel, this custom validator deliberately uses case-insensitive comparisons.
if (parameters.ValidTypes != null && parameters.ValidTypes.Any() && if (parameters.ValidTypes != null && parameters.ValidTypes.Any() &&
!parameters.ValidTypes.Contains(type, StringComparer.OrdinalIgnoreCase)) !parameters.ValidTypes.Contains(type, StringComparer.OrdinalIgnoreCase))
{ {
throw new SecurityTokenInvalidTypeException("The type of the JWT token doesn't match the expected type.") throw new SecurityTokenInvalidTypeException(SR.GetResourceString(SR.ID1270))
{ {
InvalidType = type InvalidType = type
}; };

6
src/OpenIddict.Server/OpenIddictServerTransaction.cs

@ -6,6 +6,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;
@ -26,6 +27,11 @@ namespace OpenIddict.Server
/// </summary> /// </summary>
public Uri Issuer { get; set; } public Uri Issuer { get; set; }
/// <summary>
/// Gets or sets the localizer associated with the current request.
/// </summary>
public IStringLocalizer Localizer { get; set; }
/// <summary> /// <summary>
/// Gets or sets the logger associated with the current request. /// Gets or sets the logger associated with the current request.
/// </summary> /// </summary>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save