diff --git a/src/Mvc/Mvc.Core/src/ChallengeResult.cs b/src/Mvc/Mvc.Core/src/ChallengeResult.cs index b2e2b48dc76c..9add46ad3828 100644 --- a/src/Mvc/Mvc.Core/src/ChallengeResult.cs +++ b/src/Mvc/Mvc.Core/src/ChallengeResult.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -13,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc /// /// An that on execution invokes . /// - public class ChallengeResult : ActionResult + public class ChallengeResult : ActionResult, IResult { /// /// Initializes a new instance of . @@ -90,14 +91,25 @@ public ChallengeResult(IList authenticationSchemes, AuthenticationProper public AuthenticationProperties? Properties { get; set; } /// - public override async Task ExecuteResultAsync(ActionContext context) + public override Task ExecuteResultAsync(ActionContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } - var loggerFactory = context.HttpContext.RequestServices.GetRequiredService(); + return ExecuteAsync(context.HttpContext); + } + + /// + Task IResult.ExecuteAsync(HttpContext httpContext) + { + return ExecuteAsync(httpContext); + } + + private async Task ExecuteAsync(HttpContext httpContext) + { + var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger(); logger.ChallengeResultExecuting(AuthenticationSchemes); @@ -106,12 +118,12 @@ public override async Task ExecuteResultAsync(ActionContext context) { foreach (var scheme in AuthenticationSchemes) { - await context.HttpContext.ChallengeAsync(scheme, Properties); + await httpContext.ChallengeAsync(scheme, Properties); } } else { - await context.HttpContext.ChallengeAsync(Properties); + await httpContext.ChallengeAsync(Properties); } } } diff --git a/src/Mvc/Mvc.Core/src/ForbidResult.cs b/src/Mvc/Mvc.Core/src/ForbidResult.cs index 785ffd752949..de269350ff37 100644 --- a/src/Mvc/Mvc.Core/src/ForbidResult.cs +++ b/src/Mvc/Mvc.Core/src/ForbidResult.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -13,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc /// /// An that on execution invokes . /// - public class ForbidResult : ActionResult + public class ForbidResult : ActionResult, IResult { /// /// Initializes a new instance of . @@ -90,14 +91,25 @@ public ForbidResult(IList authenticationSchemes, AuthenticationPropertie public AuthenticationProperties? Properties { get; set; } /// - public override async Task ExecuteResultAsync(ActionContext context) + public override Task ExecuteResultAsync(ActionContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } - var loggerFactory = context.HttpContext.RequestServices.GetRequiredService(); + return ExecuteAsync(context.HttpContext); + } + + /// + Task IResult.ExecuteAsync(HttpContext httpContext) + { + return ExecuteAsync(httpContext); + } + + private async Task ExecuteAsync(HttpContext httpContext) + { + var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger(); logger.ForbidResultExecuting(AuthenticationSchemes); @@ -106,12 +118,12 @@ public override async Task ExecuteResultAsync(ActionContext context) { for (var i = 0; i < AuthenticationSchemes.Count; i++) { - await context.HttpContext.ForbidAsync(AuthenticationSchemes[i], Properties); + await httpContext.ForbidAsync(AuthenticationSchemes[i], Properties); } } else { - await context.HttpContext.ForbidAsync(Properties); + await httpContext.ForbidAsync(Properties); } } } diff --git a/src/Mvc/Mvc.Core/src/SignInResult.cs b/src/Mvc/Mvc.Core/src/SignInResult.cs index 994dc976689b..d890868a1dfd 100644 --- a/src/Mvc/Mvc.Core/src/SignInResult.cs +++ b/src/Mvc/Mvc.Core/src/SignInResult.cs @@ -5,6 +5,7 @@ using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Core; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -14,7 +15,7 @@ namespace Microsoft.AspNetCore.Mvc /// /// An that on execution invokes . /// - public class SignInResult : ActionResult + public class SignInResult : ActionResult, IResult { /// /// Initializes a new instance of with the @@ -78,19 +79,30 @@ public SignInResult(string? authenticationScheme, ClaimsPrincipal principal, Aut public AuthenticationProperties? Properties { get; set; } /// - public override async Task ExecuteResultAsync(ActionContext context) + public override Task ExecuteResultAsync(ActionContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } - var loggerFactory = context.HttpContext.RequestServices.GetRequiredService(); + return ExecuteAsync(context.HttpContext); + } + + /// + Task IResult.ExecuteAsync(HttpContext httpContext) + { + return ExecuteAsync(httpContext); + } + + private Task ExecuteAsync(HttpContext httpContext) + { + var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger(); logger.SignInResultExecuting(AuthenticationScheme, Principal); - await context.HttpContext.SignInAsync(AuthenticationScheme, Principal, Properties); + return httpContext.SignInAsync(AuthenticationScheme, Principal, Properties); } } } diff --git a/src/Mvc/Mvc.Core/src/SignOutResult.cs b/src/Mvc/Mvc.Core/src/SignOutResult.cs index d81604d733ba..15090b424bed 100644 --- a/src/Mvc/Mvc.Core/src/SignOutResult.cs +++ b/src/Mvc/Mvc.Core/src/SignOutResult.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Core; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -14,7 +15,7 @@ namespace Microsoft.AspNetCore.Mvc /// /// An that on execution invokes . /// - public class SignOutResult : ActionResult + public class SignOutResult : ActionResult, IResult { /// /// Initializes a new instance of with the default sign out scheme. @@ -88,13 +89,24 @@ public SignOutResult(IList authenticationSchemes, AuthenticationProperti public AuthenticationProperties? Properties { get; set; } /// - public override async Task ExecuteResultAsync(ActionContext context) + public override Task ExecuteResultAsync(ActionContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } + return ExecuteAsync(context.HttpContext); + } + + /// + Task IResult.ExecuteAsync(HttpContext httpContext) + { + return ExecuteAsync(httpContext); + } + + private async Task ExecuteAsync(HttpContext httpContext) + { if (AuthenticationSchemes == null) { throw new InvalidOperationException( @@ -103,20 +115,20 @@ public override async Task ExecuteResultAsync(ActionContext context) /* type: */ nameof(SignOutResult))); } - var loggerFactory = context.HttpContext.RequestServices.GetRequiredService(); + var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger(); logger.SignOutResultExecuting(AuthenticationSchemes); if (AuthenticationSchemes.Count == 0) { - await context.HttpContext.SignOutAsync(Properties); + await httpContext.SignOutAsync(Properties); } else { for (var i = 0; i < AuthenticationSchemes.Count; i++) { - await context.HttpContext.SignOutAsync(AuthenticationSchemes[i], Properties); + await httpContext.SignOutAsync(AuthenticationSchemes[i], Properties); } } } diff --git a/src/Mvc/Mvc.Core/test/ChallengeResultTest.cs b/src/Mvc/Mvc.Core/test/ChallengeResultTest.cs index b1ec100e5f4f..d36fdef0cb4f 100644 --- a/src/Mvc/Mvc.Core/test/ChallengeResultTest.cs +++ b/src/Mvc/Mvc.Core/test/ChallengeResultTest.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc public class ChallengeResultTest { [Fact] - public async Task ChallengeResult_Execute() + public async Task ChallengeResult_ExecuteResultAsync() { // Arrange var result = new ChallengeResult("", null); @@ -43,7 +43,7 @@ public async Task ChallengeResult_Execute() } [Fact] - public async Task ChallengeResult_ExecuteNoSchemes() + public async Task ChallengeResult_ExecuteResultAsync_NoSchemes() { // Arrange var result = new ChallengeResult(new string[] { }, null); @@ -67,6 +67,43 @@ public async Task ChallengeResult_ExecuteNoSchemes() auth.Verify(c => c.ChallengeAsync(httpContext.Object, null, null), Times.Exactly(1)); } + [Fact] + public async Task ChallengeResult_ExecuteAsync() + { + // Arrange + var result = new ChallengeResult("", null); + + var auth = new Mock(); + + var httpContext = new Mock(); + httpContext.SetupGet(c => c.RequestServices) + .Returns(CreateServices().AddSingleton(auth.Object).BuildServiceProvider()); + + // Act + await ((IResult)result).ExecuteAsync(httpContext.Object); + + // Assert + auth.Verify(c => c.ChallengeAsync(httpContext.Object, "", null), Times.Exactly(1)); + } + + [Fact] + public async Task ChallengeResult_ExecuteAsync_NoSchemes() + { + // Arrange + var result = new ChallengeResult(new string[] { }, null); + + var auth = new Mock(); + var httpContext = new Mock(); + httpContext.SetupGet(c => c.RequestServices) + .Returns(CreateServices().AddSingleton(auth.Object).BuildServiceProvider()); + + // Act + await ((IResult)result).ExecuteAsync(httpContext.Object); + + // Assert + auth.Verify(c => c.ChallengeAsync(httpContext.Object, null, null), Times.Exactly(1)); + } + private static IServiceCollection CreateServices() { var services = new ServiceCollection(); @@ -75,4 +112,4 @@ private static IServiceCollection CreateServices() return services; } } -} \ No newline at end of file +} diff --git a/src/Mvc/Mvc.Core/test/SignInResultTest.cs b/src/Mvc/Mvc.Core/test/SignInResultTest.cs index 15f895bd5b5a..b4a75abd9005 100644 --- a/src/Mvc/Mvc.Core/test/SignInResultTest.cs +++ b/src/Mvc/Mvc.Core/test/SignInResultTest.cs @@ -100,6 +100,70 @@ public async Task ExecuteResultAsync_InvokesSignInAsyncOnConfiguredScheme() auth.Verify(); } + [Fact] + public async Task ExecuteAsync_InvokesSignInAsyncOnAuthenticationManager() + { + // Arrange + var principal = new ClaimsPrincipal(); + var httpContext = new Mock(); + var auth = new Mock(); + auth + .Setup(c => c.SignInAsync(httpContext.Object, "", principal, null)) + .Returns(Task.CompletedTask) + .Verifiable(); + httpContext.Setup(c => c.RequestServices).Returns(CreateServices(auth.Object)); + var result = new SignInResult("", principal, null); + + // Act + await ((IResult)result).ExecuteAsync(httpContext.Object); + + // Assert + auth.Verify(); + } + + [Fact] + public async Task ExecuteAsync_InvokesSignInAsyncOnAuthenticationManagerWithDefaultScheme() + { + // Arrange + var principal = new ClaimsPrincipal(); + var httpContext = new Mock(); + var auth = new Mock(); + auth + .Setup(c => c.SignInAsync(httpContext.Object, null, principal, null)) + .Returns(Task.CompletedTask) + .Verifiable(); + httpContext.Setup(c => c.RequestServices).Returns(CreateServices(auth.Object)); + var result = new SignInResult(principal); + + // Act + await ((IResult)result).ExecuteAsync(httpContext.Object); + + // Assert + auth.Verify(); + } + + [Fact] + public async Task ExecuteAsync_InvokesSignInAsyncOnConfiguredScheme() + { + // Arrange + var principal = new ClaimsPrincipal(); + var authProperties = new AuthenticationProperties(); + var httpContext = new Mock(); + var auth = new Mock(); + auth + .Setup(c => c.SignInAsync(httpContext.Object, "Scheme1", principal, authProperties)) + .Returns(Task.CompletedTask) + .Verifiable(); + httpContext.Setup(c => c.RequestServices).Returns(CreateServices(auth.Object)); + var result = new SignInResult("Scheme1", principal, authProperties); + + // Act + await ((IResult)result).ExecuteAsync(httpContext.Object); + + // Assert + auth.Verify(); + } + private static IServiceProvider CreateServices(IAuthenticationService auth) { return new ServiceCollection() diff --git a/src/Mvc/Mvc.Core/test/SignOutResultTest.cs b/src/Mvc/Mvc.Core/test/SignOutResultTest.cs index fe690c6ef496..9abec7a1b0ad 100644 --- a/src/Mvc/Mvc.Core/test/SignOutResultTest.cs +++ b/src/Mvc/Mvc.Core/test/SignOutResultTest.cs @@ -100,6 +100,71 @@ public async Task ExecuteResultAsync_InvokesSignOutAsyncOnAllConfiguredSchemes() auth.Verify(); } + [Fact] + public async Task ExecuteAsync_NoArgsInvokesDefaultSignOut() + { + // Arrange + var httpContext = new Mock(); + var auth = new Mock(); + auth + .Setup(c => c.SignOutAsync(httpContext.Object, null, null)) + .Returns(Task.CompletedTask) + .Verifiable(); + httpContext.Setup(c => c.RequestServices).Returns(CreateServices(auth.Object)); + var result = new SignOutResult(); + + // Act + await ((IResult)result).ExecuteAsync(httpContext.Object); + + // Assert + auth.Verify(); + } + + [Fact] + public async Task ExecuteAsync_InvokesSignOutAsyncOnAuthenticationManager() + { + // Arrange + var httpContext = new Mock(); + var auth = new Mock(); + auth + .Setup(c => c.SignOutAsync(httpContext.Object, "", null)) + .Returns(Task.CompletedTask) + .Verifiable(); + httpContext.Setup(c => c.RequestServices).Returns(CreateServices(auth.Object)); + var result = new SignOutResult("", null); + + // Act + await ((IResult)result).ExecuteAsync(httpContext.Object); + + // Assert + auth.Verify(); + } + + [Fact] + public async Task ExecuteAsync_InvokesSignOutAsyncOnAllConfiguredSchemes() + { + // Arrange + var authProperties = new AuthenticationProperties(); + var httpContext = new Mock(); + var auth = new Mock(); + auth + .Setup(c => c.SignOutAsync(httpContext.Object, "Scheme1", authProperties)) + .Returns(Task.CompletedTask) + .Verifiable(); + auth + .Setup(c => c.SignOutAsync(httpContext.Object, "Scheme2", authProperties)) + .Returns(Task.CompletedTask) + .Verifiable(); + httpContext.Setup(c => c.RequestServices).Returns(CreateServices(auth.Object)); + var result = new SignOutResult(new[] { "Scheme1", "Scheme2" }, authProperties); + + // Act + await ((IResult)result).ExecuteAsync(httpContext.Object); + + // Assert + auth.Verify(); + } + private static IServiceProvider CreateServices(IAuthenticationService auth) { return new ServiceCollection() @@ -108,4 +173,4 @@ private static IServiceProvider CreateServices(IAuthenticationService auth) .BuildServiceProvider(); } } -} \ No newline at end of file +}