Skip to content

Commit 6e1bf58

Browse files
committed
Fixup tests
1 parent aac2d4d commit 6e1bf58

File tree

5 files changed

+146
-80
lines changed

5 files changed

+146
-80
lines changed

src/Http/Routing/src/EndpointMiddleware.cs

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5-
using System.Runtime.CompilerServices;
65
using System.Threading.Tasks;
76
using Microsoft.AspNetCore.Authorization;
87
using Microsoft.AspNetCore.Cors.Infrastructure;
98
using Microsoft.AspNetCore.Http;
109
using Microsoft.AspNetCore.Http.Features;
1110
using Microsoft.Extensions.Logging;
11+
using Microsoft.Extensions.Options;
1212

1313
namespace Microsoft.AspNetCore.Routing
1414
{
@@ -19,29 +19,40 @@ internal sealed class EndpointMiddleware
1919

2020
private readonly ILogger _logger;
2121
private readonly RequestDelegate _next;
22+
private readonly RouteOptions _routeOptions;
2223

23-
public EndpointMiddleware(ILogger<EndpointMiddleware> logger, RequestDelegate next)
24+
public EndpointMiddleware(
25+
ILogger<EndpointMiddleware> logger,
26+
RequestDelegate next,
27+
IOptions<RouteOptions> routeOptions)
2428
{
25-
if (logger == null)
26-
{
27-
throw new ArgumentNullException(nameof(logger));
28-
}
29-
30-
if (next == null)
31-
{
32-
throw new ArgumentNullException(nameof(next));
33-
}
34-
35-
_logger = logger;
36-
_next = next;
29+
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
30+
_next = next ?? throw new ArgumentNullException(nameof(next));
31+
_routeOptions = routeOptions?.Value ?? throw new ArgumentNullException(nameof(routeOptions));
3732
}
3833

3934
public async Task Invoke(HttpContext httpContext)
4035
{
4136
var endpoint = httpContext.Features.Get<IEndpointFeature>()?.Endpoint;
4237
if (endpoint?.RequestDelegate != null)
4338
{
44-
EnsureRequisiteMiddlewares(httpContext, endpoint);
39+
if (_routeOptions.SuppressCheckForUnevaluatedEndpointMetadata)
40+
{
41+
// User opted out of this check.
42+
return;
43+
}
44+
45+
if (endpoint.Metadata.GetMetadata<IAuthorizeData>() != null &&
46+
!httpContext.Items.ContainsKey(AuthorizationMiddlewareInvokedKey))
47+
{
48+
ThrowMissingAuthMiddlewareException(endpoint);
49+
}
50+
51+
if (endpoint.Metadata.GetMetadata<ICorsMetadata>() != null &&
52+
!httpContext.Items.ContainsKey(CorsMiddlewareInvokedKey))
53+
{
54+
ThrowMissingCorsMiddlewareException(endpoint);
55+
}
4556

4657
Log.ExecutingEndpoint(_logger, endpoint);
4758

@@ -60,32 +71,20 @@ public async Task Invoke(HttpContext httpContext)
6071
await _next(httpContext);
6172
}
6273

63-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
64-
private static void EnsureRequisiteMiddlewares(HttpContext httpContext, Endpoint endpoint)
65-
{
66-
if (endpoint.Metadata.GetMetadata<IAuthorizeData>() != null &&
67-
!httpContext.Items.ContainsKey(AuthorizationMiddlewareInvokedKey))
68-
{
69-
ThrowMissingAuthMiddlewareException(endpoint);
70-
}
71-
72-
if (endpoint.Metadata.GetMetadata<ICorsMetadata>() != null &&
73-
!httpContext.Items.ContainsKey(CorsMiddlewareInvokedKey))
74-
{
75-
ThrowMissingCorsMiddlewareException(endpoint);
76-
}
77-
}
78-
7974
private static void ThrowMissingAuthMiddlewareException(Endpoint endpoint)
8075
{
8176
throw new InvalidOperationException($"Endpoint {endpoint.DisplayName} contains authorization metadata, " +
82-
"but a middleware was not found that supports authorization.");
77+
"but a middleware was not found that supports authorization." +
78+
Environment.NewLine +
79+
"Configure your application startup by adding app.UseAuthorization() inside the call to Configure(..) in the application startup code.");
8380
}
8481

8582
private static void ThrowMissingCorsMiddlewareException(Endpoint endpoint)
8683
{
8784
throw new InvalidOperationException($"Endpoint {endpoint.DisplayName} contains CORS metadata, " +
88-
"but a middleware was not found that supports CORS.");
85+
"but a middleware was not found that supports CORS." +
86+
Environment.NewLine +
87+
"Configure your application startup by adding app.UseCors() inside the call to Configure(..) in the application startup code.");
8988
}
9089

9190
private static class Log

src/Http/Routing/src/RouteOptions.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,22 @@ public class RouteOptions
2828
/// </summary>
2929
public bool AppendTrailingSlash { get; set; }
3030

31+
/// <summary>
32+
/// Gets or sets a value that indicates if the check for unevaluated endpoint metadata is suppressed.
33+
/// <para>
34+
/// Endpoints can be associated with metadata such as authorization, or CORS, that needs to be
35+
/// evaluated by a specific middleware to be actionable. If the middleware is not configured, such
36+
/// metadata will go unevaluated.
37+
/// </para>
38+
/// <para>
39+
/// When <see langword="false"/>, prior to the execution of the endpoint, routing will verify that
40+
/// all unevaluated metadata has been accounted for. Setting this property to <see langword="true"/>
41+
/// suppresses this check.
42+
/// </para>
43+
/// </summary>
44+
/// <value>Defaults to <see langword="true"/>.</value>
45+
public bool SuppressCheckForUnevaluatedEndpointMetadata { get; set; }
46+
3147
private IDictionary<string, Type> _constraintTypeMap = GetDefaultConstraintMap();
3248

3349
public IDictionary<string, Type> ConstraintMap

src/Http/Routing/test/UnitTests/EndpointMiddlewareTest.cs

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88
using Microsoft.AspNetCore.Http;
99
using Microsoft.AspNetCore.Http.Features;
1010
using Microsoft.Extensions.Logging.Abstractions;
11+
using Microsoft.Extensions.Options;
1112
using Moq;
1213
using Xunit;
1314

1415
namespace Microsoft.AspNetCore.Routing
1516
{
1617
public class EndpointMiddlewareTest
1718
{
19+
private readonly IOptions<RouteOptions> RouteOptions = Options.Create(new RouteOptions());
20+
1821
[Fact]
1922
public async Task Invoke_NoFeature_NoOps()
2023
{
@@ -27,7 +30,7 @@ public async Task Invoke_NoFeature_NoOps()
2730
return Task.CompletedTask;
2831
};
2932

30-
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, next);
33+
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, next, RouteOptions);
3134

3235
// Act
3336
await middleware.Invoke(httpContext);
@@ -52,7 +55,7 @@ public async Task Invoke_NoEndpoint_NoOps()
5255
return Task.CompletedTask;
5356
};
5457

55-
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, next);
58+
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, next, RouteOptions);
5659

5760
// Act
5861
await middleware.Invoke(httpContext);
@@ -84,7 +87,7 @@ public async Task Invoke_WithEndpoint_InvokesDelegate()
8487
return Task.CompletedTask;
8588
};
8689

87-
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, next);
90+
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, next, RouteOptions);
8891

8992
// Act
9093
await middleware.Invoke(httpContext);
@@ -97,6 +100,9 @@ public async Task Invoke_WithEndpoint_InvokesDelegate()
97100
public async Task Invoke_WithEndpoint_ThrowsIfAuthAttributesWereFound_ButAuthMiddlewareNotInvoked()
98101
{
99102
// Arrange
103+
var expected = "Endpoint Test contains authorization metadata, but a middleware was not found that supports authorization." +
104+
Environment.NewLine +
105+
"Configure your application startup by adding app.UseAuthorization() inside the call to Configure(..) in the application startup code.";
100106
var httpContext = new DefaultHttpContext
101107
{
102108
RequestServices = new ServiceProvider()
@@ -107,13 +113,13 @@ public async Task Invoke_WithEndpoint_ThrowsIfAuthAttributesWereFound_ButAuthMid
107113
Endpoint = new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<IAuthorizeData>()), "Test"),
108114
});
109115

110-
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask);
116+
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, RouteOptions);
111117

112118
// Act & Assert
113119
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => middleware.Invoke(httpContext));
114120

115121
// Assert
116-
Assert.Equal("Endpoint Test contains authorization metadata, but a middleware was not found that supports authorization.", ex.Message);
122+
Assert.Equal(expected, ex.Message);
117123
}
118124

119125
[Fact]
@@ -132,18 +138,41 @@ public async Task Invoke_WithEndpoint_WorksIfAuthAttributesWereFound_AndAuthMidd
132138

133139
httpContext.Items[EndpointMiddleware.AuthorizationMiddlewareInvokedKey] = true;
134140

135-
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask);
141+
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, RouteOptions);
136142

137143
// Act & Assert
138144
await middleware.Invoke(httpContext);
139145

140146
// If we got this far, we can sound the everything's OK alarm.
141147
}
142148

149+
[Fact]
150+
public async Task Invoke_WithEndpoint_DoesNotThrowIfUnevaluatedAuthAttributesWereFound_ButSuppressedViaOptions()
151+
{
152+
// Arrange
153+
var httpContext = new DefaultHttpContext
154+
{
155+
RequestServices = new ServiceProvider()
156+
};
157+
158+
httpContext.Features.Set<IEndpointFeature>(new EndpointSelectorContext()
159+
{
160+
Endpoint = new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<IAuthorizeData>()), "Test"),
161+
});
162+
var routeOptions = Options.Create(new RouteOptions { SuppressCheckForUnevaluatedEndpointMetadata = true });
163+
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, routeOptions);
164+
165+
// Act & Assert
166+
await middleware.Invoke(httpContext);
167+
}
168+
143169
[Fact]
144170
public async Task Invoke_WithEndpoint_ThrowsIfCorsMetadataWasFound_ButCorsMiddlewareNotInvoked()
145171
{
146172
// Arrange
173+
var expected = "Endpoint Test contains CORS metadata, but a middleware was not found that supports CORS." +
174+
Environment.NewLine +
175+
"Configure your application startup by adding app.UseCors() inside the call to Configure(..) in the application startup code.";
147176
var httpContext = new DefaultHttpContext
148177
{
149178
RequestServices = new ServiceProvider()
@@ -154,13 +183,13 @@ public async Task Invoke_WithEndpoint_ThrowsIfCorsMetadataWasFound_ButCorsMiddle
154183
Endpoint = new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<ICorsMetadata>()), "Test"),
155184
});
156185

157-
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask);
186+
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, RouteOptions);
158187

159188
// Act & Assert
160189
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => middleware.Invoke(httpContext));
161190

162191
// Assert
163-
Assert.Equal("Endpoint Test contains CORS metadata, but a middleware was not found that supports CORS.", ex.Message);
192+
Assert.Equal(expected, ex.Message);
164193
}
165194

166195
[Fact]
@@ -179,14 +208,34 @@ public async Task Invoke_WithEndpoint_WorksIfCorsMetadataWasFound_AndCorsMiddlew
179208

180209
httpContext.Items[EndpointMiddleware.CorsMiddlewareInvokedKey] = true;
181210

182-
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask);
211+
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, RouteOptions);
183212

184213
// Act & Assert
185214
await middleware.Invoke(httpContext);
186215

187216
// If we got this far, we can sound the everything's OK alarm.
188217
}
189218

219+
[Fact]
220+
public async Task Invoke_WithEndpoint_DoesNotThrowIfUnevaluatedCorsAttributesWereFound_ButSuppressedViaOptions()
221+
{
222+
// Arrange
223+
var httpContext = new DefaultHttpContext
224+
{
225+
RequestServices = new ServiceProvider()
226+
};
227+
228+
httpContext.Features.Set<IEndpointFeature>(new EndpointSelectorContext()
229+
{
230+
Endpoint = new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<IAuthorizeData>()), "Test"),
231+
});
232+
var routeOptions = Options.Create(new RouteOptions { SuppressCheckForUnevaluatedEndpointMetadata = true });
233+
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, routeOptions);
234+
235+
// Act & Assert
236+
await middleware.Invoke(httpContext);
237+
}
238+
190239
private class ServiceProvider : IServiceProvider
191240
{
192241
public object GetService(Type serviceType)

src/SignalR/clients/ts/FunctionalTests/FunctionalTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
<ItemGroup>
2828
<Reference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
29+
<Reference Include="Microsoft.AspNetCore.Cors" />
2930
<Reference Include="Microsoft.AspNetCore.Diagnostics" />
3031
<Reference Include="Microsoft.AspNetCore.Server.IISIntegration" />
3132
<Reference Include="Microsoft.AspNetCore.Server.Kestrel" />

0 commit comments

Comments
 (0)