using System.Linq; using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Net; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Tests.Common; using Umbraco.Cms.Web.Common.Security; namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Common.Security; [TestFixture] public class MemberSignInManagerTests { private Mock>> _mockLogger; private readonly Mock _memberManager = MockMemberManager(); public UserClaimsPrincipalFactory CreateClaimsFactory(MemberManager userMgr) => new(userMgr, Options.Create(new IdentityOptions())); public MemberSignInManager CreateSut() { // This all needs to be setup because internally aspnet resolves a bunch // of services from the HttpContext.RequestServices. var serviceProviderFactory = new DefaultServiceProviderFactory(); var serviceCollection = new ServiceCollection(); serviceCollection .AddLogging() .AddAuthentication() .AddCookie(IdentityConstants.ApplicationScheme) .AddCookie(IdentityConstants.ExternalScheme, o => { o.Cookie.Name = IdentityConstants.ExternalScheme; o.ExpireTimeSpan = TimeSpan.FromMinutes(5); }) .AddCookie(IdentityConstants.TwoFactorUserIdScheme, o => { o.Cookie.Name = IdentityConstants.TwoFactorUserIdScheme; o.ExpireTimeSpan = TimeSpan.FromMinutes(5); }) .AddCookie(IdentityConstants.TwoFactorRememberMeScheme, o => { o.Cookie.Name = IdentityConstants.TwoFactorRememberMeScheme; o.ExpireTimeSpan = TimeSpan.FromMinutes(5); }); var serviceProvider = serviceProviderFactory.CreateServiceProvider(serviceCollection); var httpContextFactory = new DefaultHttpContextFactory(serviceProvider); var features = new DefaultHttpContext().Features; features.Set(new HttpConnectionFeature { LocalIpAddress = IPAddress.Parse("127.0.0.1") }); var httpContext = httpContextFactory.Create(features); _mockLogger = new Mock>>(); return new MemberSignInManager( _memberManager.Object, Mock.Of(x => x.HttpContext == httpContext), CreateClaimsFactory(_memberManager.Object), Mock.Of>(), _mockLogger.Object, Mock.Of(), Mock.Of>(), Mock.Of(), Mock.Of(), Mock.Of>(x => x.Value == new SecuritySettings())); } private static Mock MockMemberManager() => new( Mock.Of(), Mock.Of(), Options.Create(new IdentityOptions()), Mock.Of>(), Enumerable.Empty>(), Enumerable.Empty>(), new MembersErrorDescriber(Mock.Of()), Mock.Of(), Mock.Of>>(), new TestOptionsSnapshot(new MemberPasswordConfigurationSettings()), Mock.Of(), Mock.Of()); [Test] public async Task WhenPasswordSignInAsyncIsCalled_AndEverythingIsSetup_ThenASignInResultSucceededShouldBeReturnedAsync() { // arrange var userId = "bo8w3d32q9b98"; var sut = CreateSut(); var fakeUser = new MemberIdentityUser(777) { UserName = "TestUser" }; var password = "testPassword"; var lockoutOnFailure = false; var isPersistent = true; _memberManager.Setup(x => x.GetUserIdAsync(It.IsAny())).ReturnsAsync(userId); _memberManager.Setup(x => x.GetUserNameAsync(It.IsAny())).ReturnsAsync(fakeUser.UserName); _memberManager.Setup(x => x.FindByNameAsync(It.IsAny())).ReturnsAsync(fakeUser); _memberManager.Setup(x => x.CheckPasswordAsync(fakeUser, password)).ReturnsAsync(true); _memberManager.Setup(x => x.IsEmailConfirmedAsync(fakeUser)).ReturnsAsync(true); _memberManager.Setup(x => x.IsLockedOutAsync(fakeUser)).ReturnsAsync(false); // act var actual = await sut.PasswordSignInAsync(fakeUser, password, isPersistent, lockoutOnFailure); // assert Assert.IsTrue(actual.Succeeded); } [Test] public async Task WhenPasswordSignInAsyncIsCalled_AndTheResultFails_ThenASignInFailedResultShouldBeReturnedAsync() { // arrange var sut = CreateSut(); var fakeUser = new MemberIdentityUser(777) { UserName = "TestUser" }; var password = "testPassword"; var lockoutOnFailure = false; var isPersistent = true; // act var actual = await sut.PasswordSignInAsync(fakeUser, password, isPersistent, lockoutOnFailure); // assert Assert.IsFalse(actual.Succeeded); } }