diff --git a/src/Microsoft.AspNetCore.Authorization.Policy/IPolicyEvaluator.cs b/src/Microsoft.AspNetCore.Authorization.Policy/IPolicyEvaluator.cs index 1717a0ae0a..dd5e6fc038 100644 --- a/src/Microsoft.AspNetCore.Authorization.Policy/IPolicyEvaluator.cs +++ b/src/Microsoft.AspNetCore.Authorization.Policy/IPolicyEvaluator.cs @@ -28,9 +28,13 @@ namespace Microsoft.AspNetCore.Authorization.Policy /// The . /// The result of a call to . /// The . + /// + /// An optional resource the policy should be checked with. + /// If a resource is not required for policy evaluation you may pass null as the value. + /// /// Returns if authorization succeeds. /// Otherwise returns if , otherwise /// returns - Task AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context); + Task AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object resource); } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authorization.Policy/PolicyEvaluator.cs b/src/Microsoft.AspNetCore.Authorization.Policy/PolicyEvaluator.cs index f93c2d92a3..3100ff4d3e 100644 --- a/src/Microsoft.AspNetCore.Authorization.Policy/PolicyEvaluator.cs +++ b/src/Microsoft.AspNetCore.Authorization.Policy/PolicyEvaluator.cs @@ -67,17 +67,21 @@ namespace Microsoft.AspNetCore.Authorization.Policy /// The . /// The result of a call to . /// The . + /// + /// An optional resource the policy should be checked with. + /// If a resource is not required for policy evaluation you may pass null as the value. + /// /// Returns if authorization succeeds. /// Otherwise returns if , otherwise /// returns - public virtual async Task AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context) + public virtual async Task AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object resource) { if (policy == null) { throw new ArgumentNullException(nameof(policy)); } - var result = await _authorization.AuthorizeAsync(context.User, context, policy); + var result = await _authorization.AuthorizeAsync(context.User, resource, policy); if (result.Succeeded) { return PolicyAuthorizationResult.Success(); diff --git a/test/Microsoft.AspNetCore.Authorization.Test/PolicyEvaluatorTests.cs b/test/Microsoft.AspNetCore.Authorization.Test/PolicyEvaluatorTests.cs index 216fc1440e..2384e6db5f 100644 --- a/test/Microsoft.AspNetCore.Authorization.Test/PolicyEvaluatorTests.cs +++ b/test/Microsoft.AspNetCore.Authorization.Test/PolicyEvaluatorTests.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; @@ -18,7 +19,7 @@ namespace Microsoft.AspNetCore.Authorization.Policy.Test public async Task AuthenticateFailsIfNoPrincipalReturned() { // Arrange - var evaluator = new PolicyEvaluator(new HappyAuthorization()); + var evaluator = BuildEvaluator(); var context = new DefaultHttpContext(); var services = new ServiceCollection().AddSingleton(); context.RequestServices = services.BuildServiceProvider(); @@ -35,7 +36,7 @@ namespace Microsoft.AspNetCore.Authorization.Policy.Test public async Task AuthenticateMergeSchemes() { // Arrange - var evaluator = new PolicyEvaluator(new HappyAuthorization()); + var evaluator = BuildEvaluator(); var context = new DefaultHttpContext(); var services = new ServiceCollection().AddSingleton(); context.RequestServices = services.BuildServiceProvider(); @@ -54,12 +55,12 @@ namespace Microsoft.AspNetCore.Authorization.Policy.Test public async Task AuthorizeSucceedsEvenIfAuthenticationFails() { // Arrange - var evaluator = new PolicyEvaluator(new HappyAuthorization()); + var evaluator = BuildEvaluator(); var context = new DefaultHttpContext(); var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build(); // Act - var result = await evaluator.AuthorizeAsync(policy, AuthenticateResult.Fail("Nooo"), context); + var result = await evaluator.AuthorizeAsync(policy, AuthenticateResult.Fail("Nooo"), context, resource: null); // Assert Assert.True(result.Succeeded); @@ -67,16 +68,34 @@ namespace Microsoft.AspNetCore.Authorization.Policy.Test Assert.False(result.Forbidden); } + [Fact] + public async Task AuthorizeSucceedsOnlyIfResourceSpecified() + { + // Arrange + var evaluator = BuildEvaluator(); + var context = new DefaultHttpContext(); + var policy = new AuthorizationPolicyBuilder().RequireAssertion(c => c.Resource != null).Build(); + var success = AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(), "whatever")); + + // Act + var result = await evaluator.AuthorizeAsync(policy, success, context, resource: null); + var result2 = await evaluator.AuthorizeAsync(policy, success, context, resource: new object()); + + // Assert + Assert.False(result.Succeeded); + Assert.True(result2.Succeeded); + } + [Fact] public async Task AuthorizeChallengesIfAuthenticationFails() { // Arrange - var evaluator = new PolicyEvaluator(new SadAuthorization()); + var evaluator = BuildEvaluator(); var context = new DefaultHttpContext(); - var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build(); + var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => false).Build(); // Act - var result = await evaluator.AuthorizeAsync(policy, AuthenticateResult.Fail("Nooo"), context); + var result = await evaluator.AuthorizeAsync(policy, AuthenticateResult.Fail("Nooo"), context, resource: null); // Assert Assert.False(result.Succeeded); @@ -88,12 +107,12 @@ namespace Microsoft.AspNetCore.Authorization.Policy.Test public async Task AuthorizeForbidsIfAuthenticationSuceeds() { // Arrange - var evaluator = new PolicyEvaluator(new SadAuthorization()); + var evaluator = BuildEvaluator(); var context = new DefaultHttpContext(); - var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build(); + var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => false).Build(); // Act - var result = await evaluator.AuthorizeAsync(policy, AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(), "scheme")), context); + var result = await evaluator.AuthorizeAsync(policy, AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(), "scheme")), context, resource: null); // Assert Assert.False(result.Succeeded); @@ -101,6 +120,17 @@ namespace Microsoft.AspNetCore.Authorization.Policy.Test Assert.True(result.Forbidden); } + private IPolicyEvaluator BuildEvaluator(Action setupServices = null) + { + var services = new ServiceCollection() + .AddAuthorization() + .AddAuthorizationPolicyEvaluator() + .AddLogging() + .AddOptions(); + setupServices?.Invoke(services); + return services.BuildServiceProvider().GetRequiredService(); + } + public class HappyAuthorization : IAuthorizationService { public Task AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable requirements)