Browse Source

Port the token endpoint integration tests

pull/875/head
Kévin Chalet 6 years ago
parent
commit
eb35cbefb7
  1. 2
      eng/Versions.props
  2. 9
      src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs
  3. 9
      src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs
  4. 18
      src/OpenIddict.Server/OpenIddictServerHandlers.Device.cs
  5. 23
      src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs
  6. 9
      src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs
  7. 45
      src/OpenIddict.Server/OpenIddictServerHandlers.cs
  8. 28
      test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs
  9. 57
      test/OpenIddict.Server.AspNetCore.IntegrationTests/OpenIddictServerAspNetCoreIntegrationTests.Exchange.cs
  10. 108
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs
  11. 3019
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs
  12. 16
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs
  13. 56
      test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.Exchange.cs

2
eng/Versions.props

@ -40,7 +40,7 @@
<ImmutableCollectionsVersion>1.5.0</ImmutableCollectionsVersion>
<LinqAsyncVersion>4.0.0</LinqAsyncVersion>
<MongoDbVersion>2.9.0</MongoDbVersion>
<MoqVersion>4.7.63</MoqVersion>
<MoqVersion>4.13.1</MoqVersion>
<NHibernateVersion>5.2.2</NHibernateVersion>
<OwinVersion>4.0.0</OwinVersion>
<SystemTextJsonVersion>4.6.0</SystemTextJsonVersion>

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

@ -1886,6 +1886,15 @@ namespace OpenIddict.Abstractions
public static ClaimsPrincipal SetInternalTokenId([NotNull] this ClaimsPrincipal principal, string identifier)
=> principal.SetClaim(Claims.Private.TokenId, identifier);
/// <summary>
/// Sets the token usage associated with the claims principal.
/// </summary>
/// <param name="principal">The claims principal.</param>
/// <param name="usage">The token usage to store.</param>
/// <returns>The claims principal.</returns>
public static ClaimsPrincipal SetTokenUsage([NotNull] this ClaimsPrincipal principal, string usage)
=> principal.SetClaim(Claims.Private.TokenUsage, usage);
private static IEnumerable<string> GetValues(string source, char[] separators)
{
Debug.Assert(!string.IsNullOrEmpty(source), "The source string shouldn't be null or empty.");

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

@ -297,6 +297,15 @@ namespace OpenIddict.Server
context.SkipRequest();
return;
}
else if (@event.IsRejected)
{
context.Reject(
error: @event.Error ?? Errors.InvalidGrant,
description: @event.ErrorDescription,
uri: @event.ErrorUri);
return;
}
}
throw new InvalidOperationException(new StringBuilder()

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

@ -294,6 +294,15 @@ namespace OpenIddict.Server
return;
}
else if (@event.IsRejected)
{
context.Reject(
error: @event.Error ?? Errors.InvalidGrant,
description: @event.ErrorDescription,
uri: @event.ErrorUri);
return;
}
throw new InvalidOperationException(new StringBuilder()
.Append("The device request was not handled. To handle device requests, ")
.Append("create a class implementing 'IOpenIddictServerHandler<HandleDeviceRequestContext>' ")
@ -1059,6 +1068,15 @@ namespace OpenIddict.Server
context.SkipRequest();
return;
}
else if (@event.IsRejected)
{
context.Reject(
error: @event.Error ?? Errors.InvalidGrant,
description: @event.ErrorDescription,
uri: @event.ErrorUri);
return;
}
}
throw new InvalidOperationException(new StringBuilder()

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

@ -268,7 +268,7 @@ namespace OpenIddict.Server
else if (notification.IsRejected)
{
context.Reject(
error: notification.Error ?? Errors.InvalidRequest,
error: notification.Error ?? Errors.InvalidGrant,
description: notification.ErrorDescription,
uri: notification.ErrorUri);
return;
@ -295,6 +295,15 @@ namespace OpenIddict.Server
context.SkipRequest();
return;
}
else if (@event.IsRejected)
{
context.Reject(
error: @event.Error ?? Errors.InvalidGrant,
description: @event.ErrorDescription,
uri: @event.ErrorUri);
return;
}
}
throw new InvalidOperationException(new StringBuilder()
@ -1641,7 +1650,8 @@ namespace OpenIddict.Server
else if (string.Equals(method, CodeChallengeMethods.Sha256, StringComparison.Ordinal))
{
using var algorithm = SHA256.Create();
data = algorithm.ComputeHash(Encoding.ASCII.GetBytes(context.Request.CodeVerifier));
data = Encoding.ASCII.GetBytes(Base64UrlEncoder.Encode(
algorithm.ComputeHash(Encoding.ASCII.GetBytes(context.Request.CodeVerifier))));
}
else
@ -1657,7 +1667,7 @@ namespace OpenIddict.Server
// Compare the verifier and the code challenge: if the two don't match, return an error.
// Note: to prevent timing attacks, a time-constant comparer is always used.
if (!FixedTimeEquals(data, Base64UrlEncoder.DecodeBytes(challenge)))
if (!FixedTimeEquals(data, Encoding.UTF8.GetBytes(challenge)))
{
context.Logger.LogError("The token request was rejected because the 'code_verifier' was invalid.");
@ -1721,7 +1731,12 @@ namespace OpenIddict.Server
throw new ArgumentNullException(nameof(context));
}
if (!context.Request.IsAuthorizationCodeGrantType() || string.IsNullOrEmpty(context.Request.Scope))
if (string.IsNullOrEmpty(context.Request.Scope))
{
return default;
}
if (!context.Request.IsAuthorizationCodeGrantType() && !context.Request.IsRefreshTokenGrantType())
{
return default;
}

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

@ -270,6 +270,15 @@ namespace OpenIddict.Server
return;
}
else if (@event.IsRejected)
{
context.Reject(
error: @event.Error ?? Errors.InvalidRequest,
description: @event.ErrorDescription,
uri: @event.ErrorUri);
return;
}
throw new InvalidOperationException(new StringBuilder()
.Append("The logout request was not handled. To handle logout requests, ")
.Append("create a class implementing 'IOpenIddictServerHandler<HandleLogoutRequestContext>' ")

45
src/OpenIddict.Server/OpenIddictServerHandlers.cs

@ -349,13 +349,13 @@ namespace OpenIddict.Server
description: context.EndpointType switch
{
OpenIddictServerEndpointType.Token when context.Request.IsAuthorizationCodeGrantType()
=> "The specified authorization code is not valid.",
=> "The specified authorization code is invalid.",
OpenIddictServerEndpointType.Token when context.Request.IsDeviceCodeGrantType()
=> "The specified device code is not valid.",
=> "The specified device code is invalid.",
OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType()
=> "The specified refresh token is not valid.",
=> "The specified refresh token is invalid.",
_ => "The specified token is not valid."
_ => "The specified token is invalid."
});
return;
@ -592,17 +592,17 @@ namespace OpenIddict.Server
},
description: context.EndpointType switch
{
OpenIddictServerEndpointType.Authorization => "The specified identity token hint is not valid.",
OpenIddictServerEndpointType.Logout => "The specified identity token hint is not valid.",
OpenIddictServerEndpointType.Authorization => "The specified identity token hint is invalid.",
OpenIddictServerEndpointType.Logout => "The specified identity token hint is invalid.",
OpenIddictServerEndpointType.Token when context.Request.IsAuthorizationCodeGrantType()
=> "The specified authorization code is not valid.",
=> "The specified authorization code is invalid.",
OpenIddictServerEndpointType.Token when context.Request.IsDeviceCodeGrantType()
=> "The specified device code is not valid.",
=> "The specified device code is invalid.",
OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType()
=> "The specified refresh token is not valid.",
=> "The specified refresh token is invalid.",
_ => "The specified token is not valid."
_ => "The specified token is invalid."
});
@ -679,13 +679,13 @@ namespace OpenIddict.Server
description: context.EndpointType switch
{
OpenIddictServerEndpointType.Token when context.Request.IsAuthorizationCodeGrantType()
=> "The specified authorization code is not valid.",
=> "The specified authorization code is invalid.",
OpenIddictServerEndpointType.Token when context.Request.IsDeviceCodeGrantType()
=> "The specified device code is not valid.",
=> "The specified device code is invalid.",
OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType()
=> "The specified refresh token is not valid.",
=> "The specified refresh token is invalid.",
_ => "The specified token is not valid."
_ => "The specified token is invalid."
});
return;
@ -701,7 +701,11 @@ namespace OpenIddict.Server
// See https://tools.ietf.org/html/rfc6749#section-10.5 for more information.
if (await _tokenManager.HasStatusAsync(token, Statuses.Redeemed))
{
await TryRevokeAuthorizationChainAsync(token);
// First, mark the redeemed token submitted by the client as revoked.
await _tokenManager.TryRevokeAsync(token);
// Then, try to revoke the authorization and the associated token entries.
await TryRevokeAuthorizationChainAsync(context.Principal.GetInternalAuthorizationId());
context.Logger.LogError("The token '{Identifier}' has already been redeemed.", identifier);
@ -786,12 +790,8 @@ namespace OpenIddict.Server
.SetInternalTokenId(await _tokenManager.GetIdAsync(token))
.SetClaim(Claims.Private.TokenUsage, await _tokenManager.GetTypeAsync(token));
async ValueTask TryRevokeAuthorizationChainAsync(object token)
async ValueTask TryRevokeAuthorizationChainAsync(string identifier)
{
// First, mark the redeemed token submitted by the client as revoked.
await _tokenManager.TryRevokeAsync(token);
var identifier = context.Principal.GetInternalAuthorizationId();
if (context.Options.DisableAuthorizationStorage || string.IsNullOrEmpty(identifier))
{
return;
@ -805,12 +805,11 @@ namespace OpenIddict.Server
await _authorizationManager.TryRevokeAsync(authorization);
}
await using var enumerator = _tokenManager.FindByAuthorizationIdAsync(identifier).GetAsyncEnumerator();
while (await enumerator.MoveNextAsync())
await foreach (var token in _tokenManager.FindByAuthorizationIdAsync(identifier))
{
// Don't change the status of the token used in the token request.
if (string.Equals(context.Principal.GetInternalTokenId(),
await _tokenManager.GetIdAsync(enumerator.Current), StringComparison.Ordinal))
await _tokenManager.GetIdAsync(token), StringComparison.Ordinal))
{
continue;
}

28
test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs

@ -2972,6 +2972,34 @@ namespace OpenIddict.Abstractions.Tests.Primitives
Assert.Equal(identifier, principal.GetClaim(Claims.Private.TokenId));
}
[Fact]
public void SetTokenUsage_ThrowsAnExceptionForNullPrincipal()
{
// Arrange
var principal = (ClaimsPrincipal) null;
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => principal.SetTokenUsage(null));
Assert.Equal("principal", exception.ParamName);
}
[Theory]
[InlineData(null)]
[InlineData("access_token")]
public void SetTokenUsage_AddsUsage(string usage)
{
// Arrange
var identity = new ClaimsIdentity();
var principal = new ClaimsPrincipal(identity);
// Act
principal.SetTokenUsage(usage);
// Assert
Assert.Equal(usage, principal.GetClaim(Claims.Private.TokenUsage));
}
private TimeSpan? ParseLifeTime(string lifetime)
{
var lifeT = lifetime != null

57
test/OpenIddict.Server.AspNetCore.IntegrationTests/OpenIddictServerAspNetCoreIntegrationTests.Exchange.cs

@ -0,0 +1,57 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.Net.Http.Headers;
using OpenIddict.Abstractions;
using OpenIddict.Server.FunctionalTests;
using Xunit;
using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Server.OpenIddictServerEvents;
namespace OpenIddict.Server.AspNetCore.FunctionalTests
{
public partial class OpenIddictServerAspNetCoreIntegrationTests : OpenIddictServerIntegrationTests
{
[Fact]
public async Task ExtractTokenRequest_MultipleClientCredentialsCauseAnError()
{
// Arrange
var client = CreateClient(options =>
{
options.EnableDegradedMode();
options.AddEventHandler<ExtractTokenRequestContext>(builder =>
{
builder.UseInlineHandler(context =>
{
var request = context.Transaction.GetHttpRequest();
request.Headers[HeaderNames.Authorization] = "Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW";
return default;
});
builder.SetOrder(int.MinValue);
});
});
// Act
var response = await client.PostAsync("/connect/token", new OpenIddictRequest
{
ClientId = "Fabrikam",
ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw",
GrantType = GrantTypes.Password,
Username = "johndoe",
Password = "A3ddj3w"
});
// Assert
Assert.Equal(Errors.InvalidRequest, response.Error);
Assert.Equal("Multiple client credentials cannot be specified.", response.ErrorDescription);
}
}
}

108
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs

@ -131,7 +131,7 @@ namespace OpenIddict.Server.FunctionalTests
{
context.Transaction.SetProperty("custom_response", new
{
name = "Bob le Magnifique"
name = "Bob le Bricoleur"
});
context.HandleRequest();
@ -144,7 +144,7 @@ namespace OpenIddict.Server.FunctionalTests
var response = await client.GetAsync("/connect/authorize");
// Assert
Assert.Equal("Bob le Magnifique", (string) response["name"]);
Assert.Equal("Bob le Bricoleur", (string) response["name"]);
}
[Fact]
@ -538,13 +538,13 @@ namespace OpenIddict.Server.FunctionalTests
var application = new OpenIddictApplication();
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<OpenIddictApplication>(application));
.ReturnsAsync(application);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(true));
.ReturnsAsync(true);
mock.Setup(manager => manager.GetClientTypeAsync(application, It.IsAny<CancellationToken>()))
.Returns(new ValueTask<string>(ClientTypes.Public));
.ReturnsAsync(ClientTypes.Public);
}));
options.Services.AddSingleton(CreateScopeManager(mock =>
@ -581,13 +581,13 @@ namespace OpenIddict.Server.FunctionalTests
var application = new OpenIddictApplication();
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<OpenIddictApplication>(application));
.ReturnsAsync(application);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(true));
.ReturnsAsync(true);
mock.Setup(manager => manager.GetClientTypeAsync(application, It.IsAny<CancellationToken>()))
.Returns(new ValueTask<string>(ClientTypes.Public));
.ReturnsAsync(ClientTypes.Public);
}));
options.Services.AddSingleton(CreateApplicationManager(mock =>
@ -595,13 +595,13 @@ namespace OpenIddict.Server.FunctionalTests
var application = new OpenIddictApplication();
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<OpenIddictApplication>(application));
.ReturnsAsync(application);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(true));
.ReturnsAsync(true);
mock.Setup(manager => manager.GetClientTypeAsync(application, It.IsAny<CancellationToken>()))
.Returns(new ValueTask<string>(ClientTypes.Public));
.ReturnsAsync(ClientTypes.Public);
}));
options.RegisterScopes("registered_scope");
@ -637,13 +637,13 @@ namespace OpenIddict.Server.FunctionalTests
var application = new OpenIddictApplication();
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<OpenIddictApplication>(application));
.ReturnsAsync(application);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(true));
.ReturnsAsync(true);
mock.Setup(manager => manager.GetClientTypeAsync(application, It.IsAny<CancellationToken>()))
.Returns(new ValueTask<string>(ClientTypes.Public));
.ReturnsAsync(ClientTypes.Public);
}));
options.Services.AddSingleton(CreateScopeManager(mock =>
@ -654,7 +654,7 @@ namespace OpenIddict.Server.FunctionalTests
.Returns(new[] { scope }.ToAsyncEnumerable());
mock.Setup(manager => manager.GetNameAsync(scope, It.IsAny<CancellationToken>()))
.Returns(new ValueTask<string>("scope_registered_in_database"));
.ReturnsAsync("scope_registered_in_database");
}));
options.RegisterScopes("scope_registered_in_options");
@ -859,7 +859,7 @@ namespace OpenIddict.Server.FunctionalTests
{
context.Transaction.SetProperty("custom_response", new
{
name = "Bob le Magnifique"
name = "Bob le Bricoleur"
});
context.HandleRequest();
@ -878,7 +878,7 @@ namespace OpenIddict.Server.FunctionalTests
});
// Assert
Assert.Equal("Bob le Magnifique", (string) response["name"]);
Assert.Equal("Bob le Bricoleur", (string) response["name"]);
}
[Fact]
@ -972,7 +972,7 @@ namespace OpenIddict.Server.FunctionalTests
var manager = CreateApplicationManager(mock =>
{
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<OpenIddictApplication>(result: null));
.ReturnsAsync(value: null);
});
var client = CreateClient(options =>
@ -1008,10 +1008,10 @@ namespace OpenIddict.Server.FunctionalTests
var manager = CreateApplicationManager(mock =>
{
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<OpenIddictApplication>(application));
.ReturnsAsync(application);
mock.Setup(manager => manager.GetClientTypeAsync(application, It.IsAny<CancellationToken>()))
.Returns(new ValueTask<string>(ClientTypes.Confidential));
.ReturnsAsync(ClientTypes.Confidential);
});
var client = CreateClient(options =>
@ -1034,7 +1034,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal("The specified 'response_type' parameter is not valid for this client application.", response.ErrorDescription);
Mock.Get(manager).Verify(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.GetClientTypeAsync(application, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.GetClientTypeAsync(application, It.IsAny<CancellationToken>()), Times.Once());
}
[Fact]
@ -1046,14 +1046,14 @@ namespace OpenIddict.Server.FunctionalTests
var manager = CreateApplicationManager(mock =>
{
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<OpenIddictApplication>(application));
.ReturnsAsync(application);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(true));
.ReturnsAsync(true);
mock.Setup(manager => manager.HasPermissionAsync(application,
Permissions.Endpoints.Authorization, It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(false));
.ReturnsAsync(false);
});
var client = CreateClient(options =>
@ -1077,7 +1077,7 @@ namespace OpenIddict.Server.FunctionalTests
Mock.Get(manager).Verify(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.HasPermissionAsync(application,
Permissions.Endpoints.Authorization, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Permissions.Endpoints.Authorization, It.IsAny<CancellationToken>()), Times.Once());
}
[Theory]
@ -1118,15 +1118,15 @@ namespace OpenIddict.Server.FunctionalTests
var manager = CreateApplicationManager(mock =>
{
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<OpenIddictApplication>(application));
.ReturnsAsync(application);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(true));
.ReturnsAsync(true);
foreach (var permission in permissions)
{
mock.Setup(manager => manager.HasPermissionAsync(application, permission, It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(false));
.ReturnsAsync(false);
}
});
@ -1152,7 +1152,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(description, response.ErrorDescription);
Mock.Get(manager).Verify(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.HasPermissionAsync(application, permissions[0], It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.HasPermissionAsync(application, permissions[0], It.IsAny<CancellationToken>()), Times.Once());
}
[Fact]
@ -1164,18 +1164,18 @@ namespace OpenIddict.Server.FunctionalTests
var manager = CreateApplicationManager(mock =>
{
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<OpenIddictApplication>(application));
.ReturnsAsync(application);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(true));
.ReturnsAsync(true);
mock.Setup(manager => manager.HasPermissionAsync(application,
Permissions.GrantTypes.AuthorizationCode, It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(true));
.ReturnsAsync(true);
mock.Setup(manager => manager.HasPermissionAsync(application,
Permissions.GrantTypes.RefreshToken, It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(false));
.ReturnsAsync(false);
});
var client = CreateClient(options =>
@ -1199,7 +1199,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal("The client application is not allowed to use the 'offline_access' scope.", response.ErrorDescription);
Mock.Get(manager).Verify(manager => manager.HasPermissionAsync(application,
Permissions.GrantTypes.RefreshToken, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Permissions.GrantTypes.RefreshToken, It.IsAny<CancellationToken>()), Times.Once());
}
[Fact]
@ -1211,10 +1211,10 @@ namespace OpenIddict.Server.FunctionalTests
var manager = CreateApplicationManager(mock =>
{
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<OpenIddictApplication>(application));
.ReturnsAsync(application);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(false));
.ReturnsAsync(false);
});
var client = CreateClient(options =>
@ -1235,7 +1235,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal("The specified 'redirect_uri' parameter is not valid for this client application.", response.ErrorDescription);
Mock.Get(manager).Verify(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Mock.Get(manager).Verify(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()), Times.Once());
}
[Fact]
@ -1247,20 +1247,18 @@ namespace OpenIddict.Server.FunctionalTests
var manager = CreateApplicationManager(mock =>
{
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<OpenIddictApplication>(application));
.ReturnsAsync(application);
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(true));
.ReturnsAsync(true);
mock.Setup(manager => manager.HasPermissionAsync(application,
Permissions.Prefixes.Scope +
Scopes.Profile, It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(true));
Permissions.Prefixes.Scope + Scopes.Profile, It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mock.Setup(manager => manager.HasPermissionAsync(application,
Permissions.Prefixes.Scope +
Scopes.Email, It.IsAny<CancellationToken>()))
.Returns(new ValueTask<bool>(false));
Permissions.Prefixes.Scope + Scopes.Email, It.IsAny<CancellationToken>()))
.ReturnsAsync(false);
});
var client = CreateClient(options =>
@ -1284,17 +1282,13 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal("This client application is not allowed to use the specified scope.", response.ErrorDescription);
Mock.Get(manager).Verify(manager => manager.HasPermissionAsync(application,
Permissions.Prefixes.Scope +
Scopes.OpenId, It.IsAny<CancellationToken>()), Times.Never());
Permissions.Prefixes.Scope + Scopes.OpenId, It.IsAny<CancellationToken>()), Times.Never());
Mock.Get(manager).Verify(manager => manager.HasPermissionAsync(application,
Permissions.Prefixes.Scope +
Scopes.OfflineAccess, It.IsAny<CancellationToken>()), Times.Never());
Permissions.Prefixes.Scope + Scopes.OfflineAccess, It.IsAny<CancellationToken>()), Times.Never());
Mock.Get(manager).Verify(manager => manager.HasPermissionAsync(application,
Permissions.Prefixes.Scope +
Scopes.Profile, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Permissions.Prefixes.Scope + Scopes.Profile, It.IsAny<CancellationToken>()), Times.Once());
Mock.Get(manager).Verify(manager => manager.HasPermissionAsync(application,
Permissions.Prefixes.Scope +
Scopes.Email, It.IsAny<CancellationToken>()), Times.AtLeastOnce());
Permissions.Prefixes.Scope + Scopes.Email, It.IsAny<CancellationToken>()), Times.Once());
}
[Theory]
@ -1349,7 +1343,7 @@ namespace OpenIddict.Server.FunctionalTests
{
context.Transaction.SetProperty("custom_response", new
{
name = "Bob le Magnifique"
name = "Bob le Bricoleur"
});
context.HandleRequest();
@ -1368,7 +1362,7 @@ namespace OpenIddict.Server.FunctionalTests
});
// Assert
Assert.Equal("Bob le Magnifique", (string) response["name"]);
Assert.Equal("Bob le Bricoleur", (string) response["name"]);
}
[Fact]
@ -1452,7 +1446,7 @@ namespace OpenIddict.Server.FunctionalTests
{
context.Transaction.SetProperty("custom_response", new
{
name = "Bob le Magnifique"
name = "Bob le Bricoleur"
});
context.HandleRequest();
@ -1471,7 +1465,7 @@ namespace OpenIddict.Server.FunctionalTests
});
// Assert
Assert.Equal("Bob le Magnifique", (string) response["name"]);
Assert.Equal("Bob le Bricoleur", (string) response["name"]);
}
[Fact]

3019
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs

File diff suppressed because it is too large

16
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs

@ -101,6 +101,22 @@ namespace OpenIddict.Server.FunctionalTests
builder.SetOrder(int.MaxValue);
});
options.AddEventHandler<HandleTokenRequestContext>(builder =>
{
builder.UseInlineHandler(context =>
{
var identity = new ClaimsIdentity("Bearer");
identity.AddClaim(Claims.Subject, "Bob le Magnifique");
context.Principal = new ClaimsPrincipal(identity);
context.HandleAuthentication();
return default;
});
builder.SetOrder(int.MaxValue);
});
});
}

56
test/OpenIddict.Server.Owin.IntegrationTests/OpenIddictServerOwinIntegrationTests.Exchange.cs

@ -0,0 +1,56 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System.Threading.Tasks;
using OpenIddict.Abstractions;
using OpenIddict.Server.FunctionalTests;
using Owin;
using Xunit;
using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Server.OpenIddictServerEvents;
namespace OpenIddict.Server.Owin.FunctionalTests
{
public partial class OpenIddictServerOwinIntegrationTests : OpenIddictServerIntegrationTests
{
[Fact]
public async Task ExtractTokenRequest_MultipleClientCredentialsCauseAnError()
{
// Arrange
var client = CreateClient(options =>
{
options.EnableDegradedMode();
options.AddEventHandler<ExtractTokenRequestContext>(builder =>
{
builder.UseInlineHandler(context =>
{
var request = context.Transaction.GetOwinRequest();
request.Headers["Authorization"] = "Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW";
return default;
});
builder.SetOrder(int.MinValue);
});
});
// Act
var response = await client.PostAsync("/connect/token", new OpenIddictRequest
{
ClientId = "Fabrikam",
ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw",
GrantType = GrantTypes.Password,
Username = "johndoe",
Password = "A3ddj3w"
});
// Assert
Assert.Equal(Errors.InvalidRequest, response.Error);
Assert.Equal("Multiple client credentials cannot be specified.", response.ErrorDescription);
}
}
}
Loading…
Cancel
Save