aspnetcore/test/Microsoft.AspNetCore.Authen.../Controllers/AccountControllerTests.cs

389 lines
15 KiB
C#

// 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 Microsoft.AspNetCore.Authorization;
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Authentication.AzureADB2C.UI.AzureADB2C.Controllers.Internal
{
public class AccountControllerTests
{
[Fact]
public void SignInNoScheme_ChallengesAADAzureADB2CDefaultScheme()
{
// Arrange
var controller = new AccountController(
new OptionsMonitor(AzureADB2CDefaults.AuthenticationScheme, new AzureADB2COptions()
{
OpenIdConnectSchemeName = AzureADB2CDefaults.OpenIdScheme,
CookieSchemeName = AzureADB2CDefaults.CookieScheme
}))
{
Url = new TestUrlHelper("~/", "https://localhost/")
};
// Act
var result = controller.SignIn(null);
// Assert
var challenge = Assert.IsAssignableFrom<ChallengeResult>(result);
var challengedScheme = Assert.Single(challenge.AuthenticationSchemes);
Assert.Equal(AzureADB2CDefaults.AuthenticationScheme, challengedScheme);
Assert.NotNull(challenge.Properties.RedirectUri);
Assert.Equal("https://localhost/", challenge.Properties.RedirectUri);
}
[Fact]
public void SignInProvidedScheme_ChallengesCustomScheme()
{
// Arrange
var controller = new AccountController(new OptionsMonitor("Custom", new AzureADB2COptions()));
controller.Url = new TestUrlHelper("~/", "https://localhost/");
// Act
var result = controller.SignIn("Custom");
// Assert
var challenge = Assert.IsAssignableFrom<ChallengeResult>(result);
var challengedScheme = Assert.Single(challenge.AuthenticationSchemes);
Assert.Equal("Custom", challengedScheme);
}
[Fact]
public void ResetPasswordNoScheme_ChallengesAADAzureADB2CDefaultSchemeWithResetPassworPolicyAsync()
{
// Arrange
var controller = new AccountController(
new OptionsMonitor(
AzureADB2CDefaults.AuthenticationScheme,
new AzureADB2COptions() { ResetPasswordPolicyId = "Reset" }))
{
Url = new TestUrlHelper("~/", "https://localhost/")
};
controller.ControllerContext = CreateControllerContext(
CreateAuthenticatedPrincipal(AzureADB2CDefaults.AuthenticationScheme));
// Act
var result = controller.ResetPassword(null);
// Assert
var challenge = Assert.IsAssignableFrom<ChallengeResult>(result);
var challengedScheme = Assert.Single(challenge.AuthenticationSchemes);
Assert.Equal(AzureADB2CDefaults.AuthenticationScheme, challengedScheme);
Assert.NotNull(challenge.Properties.RedirectUri);
Assert.Equal("https://localhost/", challenge.Properties.RedirectUri);
Assert.NotNull(challenge.Properties.Items[AzureADB2CDefaults.PolicyKey]);
Assert.Equal("Reset", challenge.Properties.Items[AzureADB2CDefaults.PolicyKey]);
}
[Fact]
public void ResetPasswordCustomScheme_ChallengesAADAzureADB2CDefaultSchemeWithResetPassworPolicyFromCustomSchemeAsync()
{
// Arrange
var controller = new AccountController(
new OptionsMonitor(
"Custom",
new AzureADB2COptions() { ResetPasswordPolicyId = "CustomReset" }))
{
Url = new TestUrlHelper("~/", "https://localhost/")
};
controller.ControllerContext = CreateControllerContext(
CreateAuthenticatedPrincipal("Custom"));
// Act
var result = controller.ResetPassword("Custom");
// Assert
var challenge = Assert.IsAssignableFrom<ChallengeResult>(result);
var challengedScheme = Assert.Single(challenge.AuthenticationSchemes);
Assert.Equal("Custom", challengedScheme);
Assert.NotNull(challenge.Properties.RedirectUri);
Assert.Equal("https://localhost/", challenge.Properties.RedirectUri);
Assert.NotNull(challenge.Properties.Items[AzureADB2CDefaults.PolicyKey]);
Assert.Equal("CustomReset", challenge.Properties.Items[AzureADB2CDefaults.PolicyKey]);
}
[Fact]
public async Task EditProfileNoScheme_ChallengesAADAzureADB2CCustomSchemeWithEditProfilePolicyAsync()
{
// Arrange
var controller = new AccountController(
new OptionsMonitor(
AzureADB2CDefaults.AuthenticationScheme,
new AzureADB2COptions() { EditProfilePolicyId = "EditProfile" }))
{
Url = new TestUrlHelper("~/", "https://localhost/")
};
controller.ControllerContext = CreateControllerContext(
CreateAuthenticatedPrincipal(AzureADB2CDefaults.AuthenticationScheme));
// Act
var result = await controller.EditProfile(null);
// Assert
var challenge = Assert.IsAssignableFrom<ChallengeResult>(result);
var challengedScheme = Assert.Single(challenge.AuthenticationSchemes);
Assert.Equal(AzureADB2CDefaults.AuthenticationScheme, challengedScheme);
Assert.NotNull(challenge.Properties.RedirectUri);
Assert.Equal("https://localhost/", challenge.Properties.RedirectUri);
Assert.NotNull(challenge.Properties.Items[AzureADB2CDefaults.PolicyKey]);
Assert.Equal("EditProfile", challenge.Properties.Items[AzureADB2CDefaults.PolicyKey]);
}
private ClaimsPrincipal CreateAuthenticatedPrincipal(string scheme) =>
new ClaimsPrincipal(new ClaimsIdentity(scheme));
private static ControllerContext CreateControllerContext(ClaimsPrincipal principal = null)
{
principal = principal ?? new ClaimsPrincipal(new ClaimsIdentity());
var mock = new Mock<IAuthenticationService>();
mock.Setup(authS => authS.AuthenticateAsync(It.IsAny<HttpContext>(), It.IsAny<string>()))
.ReturnsAsync<HttpContext, string, IAuthenticationService, AuthenticateResult>(
(ctx, scheme) =>
{
if (principal.Identity.IsAuthenticated)
{
return AuthenticateResult.Success(new AuthenticationTicket(principal, scheme));
}
else
{
return AuthenticateResult.NoResult();
}
});
return new ControllerContext()
{
HttpContext = new DefaultHttpContext()
{
RequestServices = new ServiceCollection()
.AddSingleton(mock.Object)
.BuildServiceProvider()
}
};
}
[Fact]
public async Task EditProfileCustomScheme_ChallengesAADAzureADB2CCustomSchemeWithEditProfilePolicyFromCustomSchemeAsync()
{
// Arrange
var controller = new AccountController(
new OptionsMonitor(
"Custom",
new AzureADB2COptions() { EditProfilePolicyId = "CustomEditProfile" }))
{
Url = new TestUrlHelper("~/", "https://localhost/")
};
controller.ControllerContext = CreateControllerContext(
CreateAuthenticatedPrincipal("Custom"));
// Act
var result = await controller.EditProfile("Custom");
// Assert
var challenge = Assert.IsAssignableFrom<ChallengeResult>(result);
var challengedScheme = Assert.Single(challenge.AuthenticationSchemes);
Assert.Equal("Custom", challengedScheme);
Assert.NotNull(challenge.Properties.RedirectUri);
Assert.Equal("https://localhost/", challenge.Properties.RedirectUri);
Assert.NotNull(challenge.Properties.Items[AzureADB2CDefaults.PolicyKey]);
Assert.Equal("CustomEditProfile", challenge.Properties.Items[AzureADB2CDefaults.PolicyKey]);
}
[Fact]
public async Task SignOutNoScheme_SignsOutDefaultCookiesAndDefaultOpenIDConnectAADAzureADB2CSchemesAsync()
{
// Arrange
var options = new AzureADB2COptions()
{
CookieSchemeName = AzureADB2CDefaults.CookieScheme,
OpenIdConnectSchemeName = AzureADB2CDefaults.OpenIdScheme
};
var controllerContext = CreateControllerContext(
CreateAuthenticatedPrincipal(AzureADB2CDefaults.AuthenticationScheme));
var descriptor = new PageActionDescriptor()
{
AttributeRouteInfo = new AttributeRouteInfo()
{
Template = "/Account/SignedOut"
}
};
var controller = new AccountController(new OptionsMonitor(AzureADB2CDefaults.AuthenticationScheme, options))
{
Url = new TestUrlHelper(
controllerContext.HttpContext,
new RouteData(),
descriptor,
"/Account/SignedOut",
"https://localhost/Account/SignedOut"),
ControllerContext = new ControllerContext()
{
HttpContext = controllerContext.HttpContext
}
};
controller.Request.Scheme = "https";
// Act
var result = await controller.SignOut(null);
// Assert
var signOut = Assert.IsAssignableFrom<SignOutResult>(result);
Assert.Equal(new[] { AzureADB2CDefaults.CookieScheme, AzureADB2CDefaults.OpenIdScheme }, signOut.AuthenticationSchemes);
Assert.NotNull(signOut.Properties.RedirectUri);
Assert.Equal("https://localhost/Account/SignedOut", signOut.Properties.RedirectUri);
}
[Fact]
public async Task SignOutProvidedScheme_SignsOutCustomCookiesAndCustomOpenIDConnectAADAzureADB2CSchemesAsync()
{
// Arrange
var options = new AzureADB2COptions()
{
CookieSchemeName = "Cookie",
OpenIdConnectSchemeName = "OpenID"
};
var controllerContext = CreateControllerContext(
CreateAuthenticatedPrincipal(AzureADB2CDefaults.AuthenticationScheme));
var descriptor = new PageActionDescriptor()
{
AttributeRouteInfo = new AttributeRouteInfo()
{
Template = "/Account/SignedOut"
}
};
var controller = new AccountController(new OptionsMonitor("Custom", options))
{
Url = new TestUrlHelper(
controllerContext.HttpContext,
new RouteData(),
descriptor,
"/Account/SignedOut",
"https://localhost/Account/SignedOut"),
ControllerContext = new ControllerContext()
{
HttpContext = controllerContext.HttpContext
}
};
controller.Request.Scheme = "https";
// Act
var result = await controller.SignOut("Custom");
// Assert
var signOut = Assert.IsAssignableFrom<SignOutResult>(result);
Assert.Equal(new[] { "Cookie", "OpenID" }, signOut.AuthenticationSchemes);
}
private class OptionsMonitor : IOptionsMonitor<AzureADB2COptions>
{
public OptionsMonitor(string scheme, AzureADB2COptions options)
{
Scheme = scheme;
Options = options;
}
public AzureADB2COptions CurrentValue => throw new NotImplementedException();
public string Scheme { get; }
public AzureADB2COptions Options { get; }
public AzureADB2COptions Get(string name)
{
if (name == Scheme)
{
return Options;
}
return null;
}
public IDisposable OnChange(Action<AzureADB2COptions, string> listener)
{
throw new NotImplementedException();
}
}
private class TestUrlHelper : IUrlHelper
{
public TestUrlHelper(string contentPath, string url)
{
ContentPath = contentPath;
Url = url;
}
public TestUrlHelper(
HttpContext context,
RouteData routeData,
ActionDescriptor descriptor,
string contentPath,
string url)
{
HttpContext = context;
RouteData = routeData;
ActionDescriptor = descriptor;
ContentPath = contentPath;
Url = url;
}
public ActionContext ActionContext =>
new ActionContext(HttpContext, RouteData, ActionDescriptor);
public string ContentPath { get; }
public string Url { get; }
public HttpContext HttpContext { get; }
public RouteData RouteData { get; }
public ActionDescriptor ActionDescriptor { get; }
public string Action(UrlActionContext actionContext)
{
throw new NotImplementedException();
}
public string Content(string contentPath)
{
if (ContentPath == contentPath)
{
return Url;
}
return "";
}
public bool IsLocalUrl(string url)
{
throw new NotImplementedException();
}
public string Link(string routeName, object values)
{
throw new NotImplementedException();
}
public string RouteUrl(UrlRouteContext routeContext)
{
if (routeContext.Values is RouteValueDictionary dicionary &&
dicionary.TryGetValue("page", out var page) &&
page is string pagePath &&
ContentPath == pagePath)
{
return Url;
}
return null;
}
}
}
}