Browse Source

Add log messages to inform users when application claims are not included in introspection responses

pull/1186/head
Kévin Chalet 5 years ago
parent
commit
6cf1f72844
  1. 78
      src/OpenIddict.Abstractions/OpenIddictResources.resx
  2. 6
      src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
  3. 18
      src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
  4. 2
      src/OpenIddict.Server/OpenIddictServerConfiguration.cs
  5. 2
      src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs
  6. 8
      src/OpenIddict.Server/OpenIddictServerHandlers.Device.cs
  7. 2
      src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs
  8. 8
      src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs
  9. 4
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Device.cs

78
src/OpenIddict.Abstractions/OpenIddictResources.resx

@ -406,6 +406,9 @@ To enable DI support, call 'services.AddQuartz(options => options.UseMicrosof
<data name="ID0083" xml:space="preserve">
<value>Reference tokens cannot be used when disabling token storage.</value>
</data>
<data name="ID0084" xml:space="preserve">
<value>The device grant must be allowed when enabling the device endpoint.</value>
</data>
<data name="ID0085" xml:space="preserve">
<value>At least one encryption key must be registered in the OpenIddict server options.
Consider registering a certificate using 'services.AddOpenIddict().AddServer().AddEncryptionCertificate()' or 'services.AddOpenIddict().AddServer().AddDevelopmentEncryptionCertificate()' or call 'services.AddOpenIddict().AddServer().AddEphemeralEncryptionKey()' to use an ephemeral key.</value>
@ -1116,9 +1119,6 @@ To register the OpenIddict core services, reference the 'OpenIddict.Core' packag
<data name="ID0286" xml:space="preserve">
<value>The specified principal doesn't contain a valid claims-based identity.</value>
</data>
<data name="ID0287" xml:space="preserve">
<value>The device grant must be allowed when enabling the device endpoint.</value>
</data>
<data name="ID2000" xml:space="preserve">
<value>The security token is missing.</value>
</data>
@ -1200,6 +1200,9 @@ To register the OpenIddict core services, reference the 'OpenIddict.Core' packag
<data name="ID2026" xml:space="preserve">
<value>The specified user code is no longer valid.</value>
</data>
<data name="ID2027" xml:space="preserve">
<value>The client application is not allowed to use the device code flow.</value>
</data>
<data name="ID2028" xml:space="preserve">
<value>The '{0}' parameter is not supported.</value>
</data>
@ -1266,6 +1269,9 @@ To register the OpenIddict core services, reference the 'OpenIddict.Core' packag
<data name="ID2049" xml:space="preserve">
<value>The client application is not allowed to use the hybrid flow.</value>
</data>
<data name="ID2050" xml:space="preserve">
<value>The client type cannot be null or empty.</value>
</data>
<data name="ID2051" xml:space="preserve">
<value>This client application is not allowed to use the specified scope.</value>
</data>
@ -1296,6 +1302,12 @@ To register the OpenIddict core services, reference the 'OpenIddict.Core' packag
<data name="ID2060" xml:space="preserve">
<value>A scope with the same name already exists.</value>
</data>
<data name="ID2061" xml:space="preserve">
<value>Callback URLs cannot be null or empty.</value>
</data>
<data name="ID2062" xml:space="preserve">
<value>Callback URLs must be valid absolute URLs.</value>
</data>
<data name="ID2063" xml:space="preserve">
<value>This client application is not allowed to use the token endpoint.</value>
</data>
@ -1461,18 +1473,6 @@ To register the OpenIddict core services, reference the 'OpenIddict.Core' packag
<data name="ID2117" xml:space="preserve">
<value>The specified authorization type is not supported by the default token manager.</value>
</data>
<data name="ID2118" xml:space="preserve">
<value>The client type cannot be null or empty.</value>
</data>
<data name="ID2119" xml:space="preserve">
<value>Callback URLs cannot be null or empty.</value>
</data>
<data name="ID2120" xml:space="preserve">
<value>Callback URLs must be valid absolute URLs.</value>
</data>
<data name="ID2121" xml:space="preserve">
<value>The client application is not allowed to use the device code flow.</value>
</data>
<data name="ID4000" xml:space="preserve">
<value>The '{0}' parameter shouldn't be null or empty at this point.</value>
</data>
@ -1833,9 +1833,15 @@ The principal used to create the token contained the following claims: {Claims}.
<data name="ID6104" xml:space="preserve">
<value>The introspection request was rejected because the received token was of an unsupported type.</value>
</data>
<data name="ID6105" xml:space="preserve">
<value>Potentially sensitive application claims were excluded from the introspection response as the client '{ClientId}' was not explicitly listed as an audience.</value>
</data>
<data name="ID6106" xml:space="preserve">
<value>The introspection request was rejected because the access token was issued to a different client or for another resource server.</value>
</data>
<data name="ID6107" xml:space="preserve">
<value>Potentially sensitive application claims were excluded from the introspection response as the client '{ClientId}' is a public application.</value>
</data>
<data name="ID6108" xml:space="preserve">
<value>The introspection request was rejected because the refresh token was issued to a different client.</value>
</data>
@ -1866,9 +1872,15 @@ The principal used to create the token contained the following claims: {Claims}.
<data name="ID6117" xml:space="preserve">
<value>The revocation request was rejected because the received token was of an unsupported type.</value>
</data>
<data name="ID6118" xml:space="preserve">
<value>The device request was rejected because the application '{ClientId}' was not allowed to use the device code flow.</value>
</data>
<data name="ID6119" xml:space="preserve">
<value>The revocation request was rejected because the access token was issued to a different client or for another resource server.</value>
</data>
<data name="ID6120" xml:space="preserve">
<value>The device request was rejected because the application '{ClientId}' was not allowed to request the '{Scope}' scope.</value>
</data>
<data name="ID6121" xml:space="preserve">
<value>The revocation request was rejected because the refresh token was issued to a different client.</value>
</data>
@ -1987,10 +1999,10 @@ The principal used to create the token contained the following claims: {Claims}.
<value>Client authentication cannot be enforced for public applications.</value>
</data>
<data name="ID6160" xml:space="preserve">
<value>Client authentication failed for {Client} because no client secret was associated with the application.</value>
<value>Client authentication failed for {ClientId} because no client secret was associated with the application.</value>
</data>
<data name="ID6161" xml:space="preserve">
<value>Client authentication failed for {Client}.</value>
<value>Client authentication failed for {ClientId}.</value>
</data>
<data name="ID6162" xml:space="preserve">
<value>Client validation failed because '{RedirectUri}' was not a valid redirect_uri for {Client}.</value>
@ -2008,45 +2020,39 @@ This may indicate that the hashed entry is corrupted or malformed.</value>
<data name="ID6166" xml:space="preserve">
<value>An exception occurred while trying to revoke the authorization '{Identifier}'.</value>
</data>
<data name="ID6171" xml:space="preserve">
<data name="ID6167" xml:space="preserve">
<value>A signing key of type '{Type}' was ignored because its EC curve couldn't be inferred.</value>
</data>
<data name="ID6168" xml:space="preserve">
<value>The token '{Identifier}' was successfully marked as redeemed.</value>
</data>
<data name="ID6172" xml:space="preserve">
<data name="ID6169" xml:space="preserve">
<value>A concurrency exception occurred while trying to redeem the token '{Identifier}'.</value>
</data>
<data name="ID6173" xml:space="preserve">
<data name="ID6170" xml:space="preserve">
<value>An exception occurred while trying to redeem the token '{Identifier}'.</value>
</data>
<data name="ID6174" xml:space="preserve">
<data name="ID6171" xml:space="preserve">
<value>The token '{Identifier}' was successfully marked as rejected.</value>
</data>
<data name="ID6175" xml:space="preserve">
<data name="ID6172" xml:space="preserve">
<value>A concurrency exception occurred while trying to reject the token '{Identifier}'.</value>
</data>
<data name="ID6176" xml:space="preserve">
<data name="ID6173" xml:space="preserve">
<value>An exception occurred while trying to reject the token '{Identifier}'.</value>
</data>
<data name="ID6177" xml:space="preserve">
<data name="ID6174" xml:space="preserve">
<value>The token '{Identifier}' was successfully revoked.</value>
</data>
<data name="ID6178" xml:space="preserve">
<data name="ID6175" xml:space="preserve">
<value>A concurrency exception occurred while trying to revoke the token '{Identifier}'.</value>
</data>
<data name="ID6179" xml:space="preserve">
<data name="ID6176" xml:space="preserve">
<value>An exception occurred while trying to revoke the token '{Identifier}'.</value>
</data>
<data name="ID6180" xml:space="preserve">
<value>A signing key of type '{Type}' was ignored because its EC curve couldn't be inferred.</value>
</data>
<data name="ID6181" xml:space="preserve">
<data name="ID6177" xml:space="preserve">
<value>The authorization request was rejected because the application '{ClientId}' was not allowed to use the '{ResponseType}' response type.</value>
</data>
<data name="ID6182" xml:space="preserve">
<value>The device request was rejected because the application '{ClientId}' was not allowed to use the device code flow.</value>
</data>
<data name="ID6183" xml:space="preserve">
<value>The device request was rejected because the application '{ClientId}' was not allowed to request the '{Scope}' scope.</value>
</data>
<data name="ID8000" xml:space="preserve">
<value>https://documentation.openiddict.com/errors/{0}</value>
</data>

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

@ -1179,7 +1179,7 @@ namespace OpenIddict.Core
var type = await Store.GetClientTypeAsync(application, cancellationToken);
if (string.IsNullOrEmpty(type))
{
yield return new ValidationResult(SR.GetResourceString(SR.ID2118));
yield return new ValidationResult(SR.GetResourceString(SR.ID2050));
}
else
@ -1214,7 +1214,7 @@ namespace OpenIddict.Core
// Ensure the address is not null or empty.
if (string.IsNullOrEmpty(address))
{
yield return new ValidationResult(SR.GetResourceString(SR.ID2119));
yield return new ValidationResult(SR.GetResourceString(SR.ID2061));
break;
}
@ -1222,7 +1222,7 @@ namespace OpenIddict.Core
// Ensure the address is a valid absolute URL.
if (!Uri.TryCreate(address, UriKind.Absolute, out Uri? uri) || !uri.IsWellFormedOriginalString())
{
yield return new ValidationResult(SR.GetResourceString(SR.ID2120));
yield return new ValidationResult(SR.GetResourceString(SR.ID2062));
break;
}

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

@ -1061,21 +1061,21 @@ namespace OpenIddict.Core
{
await UpdateAsync(token, cancellationToken);
Logger.LogInformation(SR.GetResourceString(SR.ID6171), await Store.GetIdAsync(token, cancellationToken));
Logger.LogInformation(SR.GetResourceString(SR.ID6168), await Store.GetIdAsync(token, cancellationToken));
return true;
}
catch (ConcurrencyException exception)
{
Logger.LogDebug(exception, SR.GetResourceString(SR.ID6172), await Store.GetIdAsync(token, cancellationToken));
Logger.LogDebug(exception, SR.GetResourceString(SR.ID6169), await Store.GetIdAsync(token, cancellationToken));
return false;
}
catch (Exception exception)
{
Logger.LogWarning(exception, SR.GetResourceString(SR.ID6173), await Store.GetIdAsync(token, cancellationToken));
Logger.LogWarning(exception, SR.GetResourceString(SR.ID6170), await Store.GetIdAsync(token, cancellationToken));
return false;
}
@ -1100,21 +1100,21 @@ namespace OpenIddict.Core
{
await UpdateAsync(token, cancellationToken);
Logger.LogInformation(SR.GetResourceString(SR.ID6174), await Store.GetIdAsync(token, cancellationToken));
Logger.LogInformation(SR.GetResourceString(SR.ID6171), await Store.GetIdAsync(token, cancellationToken));
return true;
}
catch (ConcurrencyException exception)
{
Logger.LogDebug(exception, SR.GetResourceString(SR.ID6175), await Store.GetIdAsync(token, cancellationToken));
Logger.LogDebug(exception, SR.GetResourceString(SR.ID6172), await Store.GetIdAsync(token, cancellationToken));
return false;
}
catch (Exception exception)
{
Logger.LogWarning(exception, SR.GetResourceString(SR.ID6176), await Store.GetIdAsync(token, cancellationToken));
Logger.LogWarning(exception, SR.GetResourceString(SR.ID6173), await Store.GetIdAsync(token, cancellationToken));
return false;
}
@ -1139,21 +1139,21 @@ namespace OpenIddict.Core
{
await UpdateAsync(token, cancellationToken);
Logger.LogInformation(SR.GetResourceString(SR.ID6177), await Store.GetIdAsync(token, cancellationToken));
Logger.LogInformation(SR.GetResourceString(SR.ID6174), await Store.GetIdAsync(token, cancellationToken));
return true;
}
catch (ConcurrencyException exception)
{
Logger.LogDebug(exception, SR.GetResourceString(SR.ID6178), await Store.GetIdAsync(token, cancellationToken));
Logger.LogDebug(exception, SR.GetResourceString(SR.ID6175), await Store.GetIdAsync(token, cancellationToken));
return false;
}
catch (Exception exception)
{
Logger.LogWarning(exception, SR.GetResourceString(SR.ID6179), await Store.GetIdAsync(token, cancellationToken));
Logger.LogWarning(exception, SR.GetResourceString(SR.ID6176), await Store.GetIdAsync(token, cancellationToken));
return false;
}

2
src/OpenIddict.Server/OpenIddictServerConfiguration.cs

@ -113,7 +113,7 @@ namespace OpenIddict.Server
// Ensure the device grant is allowed when the device endpoint is enabled.
if (options.DeviceEndpointUris.Count > 0 && !options.GrantTypes.Contains(GrantTypes.DeviceCode))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0287));
throw new InvalidOperationException(SR.GetResourceString(SR.ID0084));
}
// Ensure the grant types/response types configuration is consistent.

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

@ -1448,7 +1448,7 @@ namespace OpenIddict.Server
// Reject requests that specify a response_type for which no permission was granted.
if (!await HasPermissionAsync(context.Request.GetResponseTypes()))
{
context.Logger.LogError(SR.GetResourceString(SR.ID6181), context.ClientId, context.Request.ResponseType);
context.Logger.LogError(SR.GetResourceString(SR.ID6177), context.ClientId, context.Request.ResponseType);
context.Reject(
error: Errors.UnauthorizedClient,

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

@ -776,12 +776,12 @@ namespace OpenIddict.Server
// Reject the request if the application is not allowed to use the device code grant.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.DeviceCode))
{
context.Logger.LogError(SR.GetResourceString(SR.ID6182), context.ClientId);
context.Logger.LogError(SR.GetResourceString(SR.ID6118), context.ClientId);
context.Reject(
error: Errors.UnauthorizedClient,
description: SR.GetResourceString(SR.ID2121),
uri: SR.FormatID8000(SR.ID2121));
description: SR.GetResourceString(SR.ID2027),
uri: SR.FormatID8000(SR.ID2027));
return;
}
@ -791,7 +791,7 @@ namespace OpenIddict.Server
if (context.Request.HasScope(Scopes.OfflineAccess) &&
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.RefreshToken))
{
context.Logger.LogError(SR.GetResourceString(SR.ID6183), context.ClientId, Scopes.OfflineAccess);
context.Logger.LogError(SR.GetResourceString(SR.ID6120), context.ClientId, Scopes.OfflineAccess);
context.Reject(
error: Errors.InvalidRequest,

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

@ -1199,7 +1199,7 @@ namespace OpenIddict.Server
if (string.IsNullOrEmpty(curve))
{
context.Logger.LogWarning(SR.GetResourceString(SR.ID6180), credentials.Key.GetType().Name);
context.Logger.LogWarning(SR.GetResourceString(SR.ID6167), credentials.Key.GetType().Name);
continue;
}

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

@ -968,6 +968,8 @@ namespace OpenIddict.Server
// application-specific claims contained in the introspected access/identity token.
if (!context.Principal.HasAudience(context.Request.ClientId))
{
context.Logger.LogInformation(SR.GetResourceString(SR.ID6105), context.Request.ClientId);
return;
}
@ -980,6 +982,8 @@ namespace OpenIddict.Server
// Public clients are not allowed to access sensitive claims as authentication cannot be enforced.
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public))
{
context.Logger.LogInformation(SR.GetResourceString(SR.ID6107), context.Request.ClientId);
return;
}
@ -992,8 +996,8 @@ namespace OpenIddict.Server
// Make sure to always update this list when adding new built-in claim properties.
var type = group.Key;
if (type is Claims.Audience or Claims.ExpiresAt or Claims.IssuedAt or
Claims.Issuer or Claims.NotBefore or Claims.Scope or
Claims.Subject or Claims.TokenType or Claims.TokenUsage)
Claims.Issuer or Claims.NotBefore or Claims.Scope or
Claims.Subject or Claims.TokenType or Claims.TokenUsage)
{
continue;
}

4
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Device.cs

@ -572,8 +572,8 @@ namespace OpenIddict.Server.IntegrationTests
// Assert
Assert.Equal(Errors.UnauthorizedClient, response.Error);
Assert.Equal(SR.GetResourceString(SR.ID2121), response.ErrorDescription);
Assert.Equal(SR.FormatID8000(SR.ID2121), response.ErrorUri);
Assert.Equal(SR.GetResourceString(SR.ID2027), response.ErrorDescription);
Assert.Equal(SR.FormatID8000(SR.ID2027), response.ErrorUri);
Mock.Get(manager).Verify(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.HasPermissionAsync(application,

Loading…
Cancel
Save