Browse Source

Port the sign-out integration tests and add validation to prevent sign-out from being triggered from unsupported endpoints

pull/889/head
Kévin Chalet 6 years ago
parent
commit
3cbe3936bd
  1. 45
      src/OpenIddict.Server/OpenIddictServerHandlers.cs
  2. 129
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs

45
src/OpenIddict.Server/OpenIddictServerHandlers.cs

@ -98,7 +98,12 @@ namespace OpenIddict.Server
BeautifyUserCode.Descriptor,
AttachAccessTokenProperties.Descriptor,
AttachDeviceCodeProperties.Descriptor)
AttachDeviceCodeProperties.Descriptor,
/*
* Sign-out processing:
*/
ValidateSignOutDemand.Descriptor)
.AddRange(Authentication.DefaultHandlers)
.AddRange(Device.DefaultHandlers)
@ -4052,5 +4057,43 @@ namespace OpenIddict.Server
return default;
}
}
/// <summary>
/// Contains the logic responsible of ensuring that the sign-out demand
/// is compatible with the type of the endpoint that handled the request.
/// </summary>
public class ValidateSignOutDemand : IOpenIddictServerHandler<ProcessSignOutContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignOutContext>()
.UseSingletonHandler<ValidateSignOutDemand>()
.SetOrder(int.MinValue + 100_000)
.Build();
/// <summary>
/// Processes the event.
/// </summary>
/// <param name="context">The context associated with the event to process.</param>
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public ValueTask HandleAsync([NotNull] ProcessSignOutContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.EndpointType != OpenIddictServerEndpointType.Logout)
{
throw new InvalidOperationException("An OpenID Connect response cannot be returned from this endpoint.");
}
return default;
}
}
}
}

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

@ -1646,7 +1646,7 @@ namespace OpenIddict.Server.FunctionalTests
[InlineData(null, "custom_description", "custom_uri")]
[InlineData(null, null, "custom_uri")]
[InlineData(null, null, null)]
public async Task ProcessSignIn_AllowsRejectingAuthorizationRequest(string error, string description, string uri)
public async Task ProcessSignIn_AllowsRejectingRequest(string error, string description, string uri)
{
// Arrange
var client = CreateClient(options =>
@ -1677,44 +1677,6 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(uri, response.ErrorUri);
}
[Theory]
[InlineData("custom_error", null, null)]
[InlineData("custom_error", "custom_description", null)]
[InlineData("custom_error", "custom_description", "custom_uri")]
[InlineData(null, "custom_description", null)]
[InlineData(null, "custom_description", "custom_uri")]
[InlineData(null, null, "custom_uri")]
[InlineData(null, null, null)]
public async Task ProcessSignIn_AllowsRejectingTokenRequest(string error, string description, string uri)
{
// Arrange
var client = CreateClient(options =>
{
options.EnableDegradedMode();
options.AddEventHandler<ProcessSignInContext>(builder =>
builder.UseInlineHandler(context =>
{
context.Reject(error, description, uri);
return default;
}));
});
// Act
var response = await client.PostAsync("/connect/token", new OpenIddictRequest
{
GrantType = GrantTypes.Password,
Username = "johndoe",
Password = "A3ddj3w"
});
// Assert
Assert.Equal(error ?? Errors.InvalidRequest, response.Error);
Assert.Equal(description, response.ErrorDescription);
Assert.Equal(uri, response.ErrorUri);
}
[Fact]
public async Task ProcessSignIn_AllowsHandlingResponse()
{
@ -2834,6 +2796,95 @@ namespace OpenIddict.Server.FunctionalTests
Mock.Get(manager).Verify(manager => manager.CreateAsync(It.IsAny<OpenIddictAuthorizationDescriptor>(), It.IsAny<CancellationToken>()), Times.Never());
}
[Fact]
public async Task ProcessSignOut_InvalidEndpointCausesAnException()
{
// Arrange
var client = CreateClient(options =>
{
options.EnableDegradedMode();
options.SetConfigurationEndpointUris("/signout");
options.AddEventHandler<HandleConfigurationRequestContext>(builder =>
builder.UseInlineHandler(context =>
{
context.SkipRequest();
return default;
}));
});
// Act and assert
var exception = await Assert.ThrowsAsync<InvalidOperationException>(delegate
{
return client.GetAsync("/signout");
});
Assert.Equal("An OpenID Connect response cannot be returned from this endpoint.", exception.Message);
}
[Theory]
[InlineData("custom_error", null, null)]
[InlineData("custom_error", "custom_description", null)]
[InlineData("custom_error", "custom_description", "custom_uri")]
[InlineData(null, "custom_description", null)]
[InlineData(null, "custom_description", "custom_uri")]
[InlineData(null, null, "custom_uri")]
[InlineData(null, null, null)]
public async Task ProcessSignOut_AllowsRejectingRequest(string error, string description, string uri)
{
// Arrange
var client = CreateClient(options =>
{
options.EnableDegradedMode();
options.AddEventHandler<ProcessSignOutContext>(builder =>
builder.UseInlineHandler(context =>
{
context.Reject(error, description, uri);
return default;
}));
});
// Act
var response = await client.PostAsync("/connect/logout", new OpenIddictRequest());
// Assert
Assert.Equal(error ?? Errors.InvalidRequest, response.Error);
Assert.Equal(description, response.ErrorDescription);
Assert.Equal(uri, response.ErrorUri);
}
[Fact]
public async Task ProcessSignOut_AllowsHandlingResponse()
{
// Arrange
var client = CreateClient(options =>
{
options.EnableDegradedMode();
options.AddEventHandler<ProcessSignOutContext>(builder =>
builder.UseInlineHandler(context =>
{
context.Transaction.SetProperty("custom_response", new
{
name = "Bob le Bricoleur"
});
context.HandleRequest();
return default;
}));
});
// Act
var response = await client.PostAsync("/connect/logout", new OpenIddictRequest());
// Assert
Assert.Equal("Bob le Bricoleur", (string) response["name"]);
}
protected virtual void ConfigureServices(IServiceCollection services)
{
services.AddOpenIddict()

Loading…
Cancel
Save