Пример #1
0
        public async Task WhenPasswordSignInAsyncIsCalled_AndEverythingIsSetup_ThenASignInResultSucceededShouldBeReturnedAsync()
        {
            //arrange
            var userId = "bo8w3d32q9b98";
            MemberSignInManager sut = CreateSut();
            var fakeUser            = new MemberIdentityUser(777)
            {
                UserName = "******",
            };
            var password         = "******";
            var lockoutOnFailure = false;
            var isPersistent     = true;

            _memberManager.Setup(x => x.GetUserIdAsync(It.IsAny <MemberIdentityUser>())).ReturnsAsync(userId);
            _memberManager.Setup(x => x.GetUserNameAsync(It.IsAny <MemberIdentityUser>())).ReturnsAsync(fakeUser.UserName);
            _memberManager.Setup(x => x.FindByNameAsync(It.IsAny <string>())).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
            SignInResult actual = await sut.PasswordSignInAsync(fakeUser, password, isPersistent, lockoutOnFailure);

            //assert
            Assert.IsTrue(actual.Succeeded);
        }
Пример #2
0
    public async Task PostSaveMember_SaveExisting_WhenAllIsSetupCorrectly_ExpectSuccessResponse(
        [Frozen] IMemberManager umbracoMembersUserManager,
        IMemberService memberService,
        IMemberTypeService memberTypeService,
        IMemberGroupService memberGroupService,
        IDataTypeService dataTypeService,
        IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
        IBackOfficeSecurity backOfficeSecurity,
        IPasswordChanger <MemberIdentityUser> passwordChanger,
        IOptions <GlobalSettings> globalSettings,
        IUser user)
    {
        // arrange
        var member = SetupMemberTestData(out var fakeMemberData, out var memberDisplay, ContentSaveAction.Save);
        var membersIdentityUser = new MemberIdentityUser(123);

        Mock.Get(umbracoMembersUserManager)
        .Setup(x => x.FindByIdAsync(It.IsAny <string>()))
        .ReturnsAsync(() => membersIdentityUser);
        Mock.Get(umbracoMembersUserManager)
        .Setup(x => x.ValidatePasswordAsync(It.IsAny <string>()))
        .ReturnsAsync(() => IdentityResult.Success);

        Mock.Get(umbracoMembersUserManager)
        .Setup(x => x.UpdateAsync(It.IsAny <MemberIdentityUser>()))
        .ReturnsAsync(() => IdentityResult.Success);
        Mock.Get(umbracoMembersUserManager)
        .Setup(x => x.GetRolesAsync(It.IsAny <MemberIdentityUser>()))
        .ReturnsAsync(() => Array.Empty <string>());
        Mock.Get(memberTypeService).Setup(x => x.GetDefault()).Returns("fakeAlias");
        Mock.Get(globalSettings);

        SetupUserAccess(backOfficeSecurityAccessor, backOfficeSecurity, user);
        SetupPasswordSuccess(umbracoMembersUserManager, passwordChanger);

        Mock.Get(memberService).Setup(x => x.GetByUsername(It.IsAny <string>())).Returns(() => member);
        Mock.Get(memberService).Setup(x => x.GetById(It.IsAny <int>())).Returns(() => member);
        Mock.Get(memberService).SetupSequence(
            x => x.GetByEmail(It.IsAny <string>()))
        .Returns(() => null)
        .Returns(() => member);

        var sut = CreateSut(
            memberService,
            memberTypeService,
            memberGroupService,
            umbracoMembersUserManager,
            dataTypeService,
            backOfficeSecurityAccessor,
            passwordChanger,
            globalSettings);

        // act
        var result = await sut.PostSave(fakeMemberData);

        // assert
        Assert.IsNull(result.Result);
        Assert.IsNotNull(result.Value);
        AssertMemberDisplayPropertiesAreEqual(memberDisplay, result.Value);
    }
Пример #3
0
    public async Task GivenICreateANewUser_AndTheUserIsPopulatedCorrectly_ThenIShouldGetASuccessResultAsync()
    {
        // arrange
        var sut      = CreateSut();
        var fakeUser = new MemberIdentityUser();

        IMemberType fakeMemberType = new MemberType(new MockShortStringHelper(), 77);
        var         mockMember     = Mock.Of <IMember>(m =>
                                                       m.Name == "fakeName" &&
                                                       m.Email == "*****@*****.**" &&
                                                       m.Username == "fakeUsername" &&
                                                       m.RawPasswordValue == "fakePassword" &&
                                                       m.Comments == "hello" &&
                                                       m.ContentTypeAlias == fakeMemberType.Alias &&
                                                       m.HasIdentity == true);

        _mockMemberService
        .Setup(x => x.CreateMember(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>()))
        .Returns(mockMember);
        _mockMemberService.Setup(x => x.Save(mockMember));

        // act
        var identityResult = await sut.CreateAsync(fakeUser, CancellationToken.None);

        // assert
        Assert.IsTrue(identityResult.Succeeded);
        Assert.IsTrue(!identityResult.Errors.Any());
        _mockMemberService.Verify(x =>
                                  x.CreateMember(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>()));
        _mockMemberService.Verify(x => x.Save(mockMember));
    }
Пример #4
0
    public async Task GivenIDeleteUser_AndTheUserIsDeletedCorrectly_ThenIShouldGetASuccessResultAsync()
    {
        // arrange
        var sut      = CreateSut();
        var fakeUser = new MemberIdentityUser(777);
        var fakeCancellationToken = CancellationToken.None;

        IMemberType fakeMemberType = new MemberType(new MockShortStringHelper(), 77);
        IMember     mockMember     = new Member(fakeMemberType)
        {
            Id               = 777,
            Name             = "fakeName",
            Email            = "*****@*****.**",
            Username         = "******",
            RawPasswordValue = "fakePassword",
        };

        _mockMemberService.Setup(x => x.GetById(mockMember.Id)).Returns(mockMember);
        _mockMemberService.Setup(x => x.Delete(mockMember));

        // act
        var identityResult = await sut.DeleteAsync(fakeUser, fakeCancellationToken);

        // assert
        Assert.IsTrue(identityResult.Succeeded);
        Assert.IsTrue(!identityResult.Errors.Any());
        _mockMemberService.Verify(x => x.GetById(mockMember.Id));
        _mockMemberService.Verify(x => x.Delete(mockMember));
        _mockMemberService.VerifyNoOtherCalls();
    }
Пример #5
0
    public async Task GivenICreateUser_AndTheUserDoesNotHaveIdentity_ThenIShouldGetAFailedResultAsync()
    {
        // arrange
        var sut      = CreateSut();
        var fakeUser = new MemberIdentityUser();

        IMemberType fakeMemberType = new MemberType(new MockShortStringHelper(), 77);
        var         mockMember     = Mock.Of <IMember>(m =>
                                                       m.Name == "fakeName" &&
                                                       m.Email == "*****@*****.**" &&
                                                       m.Username == "fakeUsername" &&
                                                       m.RawPasswordValue == "fakePassword" &&
                                                       m.ContentTypeAlias == fakeMemberType.Alias &&
                                                       m.HasIdentity == false);

        _mockMemberService
        .Setup(x => x.CreateMember(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>()))
        .Returns(mockMember);
        _mockMemberService.Setup(x => x.Save(mockMember));

        // act
        var actual = await sut.CreateAsync(null);

        // assert
        Assert.IsFalse(actual.Succeeded);
        Assert.IsTrue(actual.Errors.Any(x =>
                                        x.Code == "IdentityErrorUserStore" && x.Description == "Value cannot be null. (Parameter 'user')"));
        _mockMemberService.VerifyNoOtherCalls();
    }
Пример #6
0
    public void DefineMaps(IUmbracoMapper mapper)
    {
        mapper.Define <IUser, BackOfficeIdentityUser>(
            (source, context) =>
        {
            var target = new BackOfficeIdentityUser(_globalSettings, source.Id, source.Groups);
            target.DisableChangeTracking();
            return(target);
        },
            (source, target, context) =>
        {
            Map(source, target);
            target.ResetDirtyProperties(true);
            target.EnableChangeTracking();
        });

        mapper.Define <IMember, MemberIdentityUser>(
            (source, context) =>
        {
            var target = new MemberIdentityUser(source.Id);
            target.DisableChangeTracking();
            return(target);
        },
            (source, target, context) =>
        {
            Map(source, target);
            target.ResetDirtyProperties(true);
            target.EnableChangeTracking();
        });
    }
Пример #7
0
        public async Task <ProfileModel> BuildForCurrentMemberAsync()
        {
            IMemberManager memberManager = _httpContextAccessor.HttpContext?.RequestServices.GetRequiredService <IMemberManager>();

            if (memberManager == null)
            {
                return(null);
            }

            MemberIdentityUser member = await memberManager.GetUserAsync(_httpContextAccessor.HttpContext.User);

            if (member == null)
            {
                return(null);
            }

            var model = new ProfileModel
            {
                Name                    = member.Name,
                Email                   = member.Email,
                UserName                = member.UserName,
                Comments                = member.Comments,
                IsApproved              = member.IsApproved,
                IsLockedOut             = member.IsLockedOut,
                LastLockoutDate         = member.LastLockoutDateUtc?.ToLocalTime(),
                CreatedDate             = member.CreatedDateUtc.ToLocalTime(),
                LastLoginDate           = member.LastLoginDateUtc?.ToLocalTime(),
                LastPasswordChangedDate = member.LastPasswordChangeDateUtc?.ToLocalTime(),
                RedirectUrl             = _redirectUrl,
                Key = member.Key
            };

            IMemberType memberType = MemberTypeService.Get(member.MemberTypeAlias);

            if (memberType == null)
            {
                throw new InvalidOperationException($"Could not find a member type with alias: {member.MemberTypeAlias}.");
            }

            // TODO: This wouldn't be required if we support exposing custom member properties on the MemberIdentityUser at the ASP.NET Identity level.
            IMember persistedMember = _memberService.GetByKey(member.Key);

            if (persistedMember == null)
            {
                // should never happen
                throw new InvalidOperationException($"Could not find a member with key: {member.Key}.");
            }

            if (_lookupProperties)
            {
                model.MemberProperties = GetMemberPropertiesViewModel(memberType, persistedMember);
            }

            return(model);
        }
Пример #8
0
        private static IMember CreateMember(MemberIdentityUser fakeUser)
        {
            var        builder    = new MemberTypeBuilder();
            MemberType memberType = builder.BuildSimpleMemberType();

            return(new Member(memberType)
            {
                Id = 777,
                Username = fakeUser.UserName,
            });
        }
Пример #9
0
    public async Task GivenICreateUser_AndTheIdentityResultFailed_ThenIShouldGetAFailedResultAsync()
    {
        // arrange
        var sut      = CreateSut();
        var fakeUser = new MemberIdentityUser {
            PasswordConfig = "testConfig"
        };

        // act
        var identityResult = await sut.CreateAsync(fakeUser);

        // assert
        Assert.IsFalse(identityResult.Succeeded);
        Assert.IsFalse(!identityResult.Errors.Any());
    }
Пример #10
0
    public async Task GivenISetNormalizedUserName_ThenIShouldGetASuccessResult()
    {
        // arrange
        var sut      = CreateSut();
        var fakeUser = new MemberIdentityUser {
            UserName = "******"
        };

        // act
        await sut.SetNormalizedUserNameAsync(fakeUser, "NewName", CancellationToken.None);

        // assert
        Assert.AreEqual("NewName", fakeUser.UserName);
        Assert.AreEqual("NewName", await sut.GetNormalizedUserNameAsync(fakeUser, CancellationToken.None));
    }
Пример #11
0
    public PasswordVerificationResult VerifyHashedPassword(string password, string encryptedPassword, string decryptionKey)
    {
        var member = new MemberIdentityUser {
            PasswordConfig = null
        };

        var sut = new MemberPasswordHasher(
            new LegacyPasswordSecurity(),
            new JsonNetSerializer(),
            Options.Create(new LegacyPasswordMigrationSettings {
            MachineKeyDecryptionKey = decryptionKey
        }),
            NullLoggerFactory.Instance.CreateLogger <MemberPasswordHasher>());

        return(sut.VerifyHashedPassword(member, encryptedPassword, password));
    }
        /// <summary>
        /// Registers a new member.
        /// </summary>
        /// <param name="model">Register member model.</param>
        /// <param name="logMemberIn">Flag for whether to log the member in upon successful registration.</param>
        /// <returns>Result of registration operation.</returns>
        private async Task <IdentityResult> RegisterMemberAsync(RegisterModel model, bool logMemberIn = true)
        {
            using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);

            // U4-10762 Server error with "Register Member" snippet (Cannot save member with empty name)
            // If name field is empty, add the email address instead.
            if (string.IsNullOrEmpty(model.Name) && string.IsNullOrEmpty(model.Email) == false)
            {
                model.Name = model.Email;
            }

            model.Username = (model.UsernameIsEmail || model.Username == null) ? model.Email : model.Username;

            var            identityUser   = MemberIdentityUser.CreateNew(model.Username, model.Email, model.MemberTypeAlias, true, model.Name);
            IdentityResult identityResult = await _memberManager.CreateAsync(
                identityUser,
                model.Password);

            if (identityResult.Succeeded)
            {
                // Update the custom properties
                // TODO: See TODO in MembersIdentityUser, Should we support custom member properties for persistence/retrieval?
                IMember?member = _memberService.GetByKey(identityUser.Key);
                if (member == null)
                {
                    // should never happen
                    throw new InvalidOperationException($"Could not find a member with key: {member?.Key}.");
                }

                if (model.MemberProperties != null)
                {
                    foreach (MemberPropertyModel property in model.MemberProperties.Where(p => p.Value != null)
                             .Where(property => member.Properties.Contains(property.Alias)))
                    {
                        member.Properties[property.Alias]?.SetValue(property.Value);
                    }
                }
                _memberService.Save(member);

                if (logMemberIn)
                {
                    await _memberSignInManager.SignInAsync(identityUser, false);
                }
            }

            return(identityResult);
        }
Пример #13
0
        public async Task GivenICreateANewUser_AndTheUserIsPopulatedCorrectly_ThenIShouldGetASuccessResultAsync()
        {
            //arrange
            MemberManager      sut      = CreateSut();
            MemberIdentityUser fakeUser = CreateValidUser();

            IMember fakeMember = CreateMember(fakeUser);

            MockMemberServiceForCreateMember(fakeMember);

            //act
            IdentityResult identityResult = await sut.CreateAsync(fakeUser);

            //assert
            Assert.IsTrue(identityResult.Succeeded);
            Assert.IsTrue(!identityResult.Errors.Any());
        }
Пример #14
0
        private async Task <IdentityResult> UpdateMemberAsync(ProfileModel model, MemberIdentityUser currentMember)
        {
            using IScope scope = _scopeProvider.CreateScope(autoComplete: true);

            currentMember.Email    = model.Email;
            currentMember.Name     = model.Name;
            currentMember.UserName = model.UserName;
            currentMember.Comments = model.Comments;

            IdentityResult saveResult = await _memberManager.UpdateAsync(currentMember);

            if (!saveResult.Succeeded)
            {
                return(saveResult);
            }

            // now we can update the custom properties
            // TODO: Ideally we could do this all through our MemberIdentityUser

            IMember member = _memberService.GetByKey(currentMember.Key);

            if (member == null)
            {
                // should never happen
                throw new InvalidOperationException($"Could not find a member with key: {member.Key}.");
            }

            IMemberType memberType = _memberTypeService.Get(member.ContentTypeId);

            if (model.MemberProperties != null)
            {
                foreach (MemberPropertyModel property in model.MemberProperties
                         //ensure the property they are posting exists
                         .Where(p => memberType.PropertyTypeExists(p.Alias))
                         .Where(property => member.Properties.Contains(property.Alias))
                         //needs to be editable
                         .Where(p => memberType.MemberCanEditProperty(p.Alias)))
                {
                    member.Properties[property.Alias].SetValue(property.Value);
                }
            }

            _memberService.Save(member);

            return(saveResult);
        }
Пример #15
0
        public async Task WhenPasswordSignInAsyncIsCalled_AndTheResultFails_ThenASignInFailedResultShouldBeReturnedAsync()
        {
            //arrange
            MemberSignInManager sut = CreateSut();
            var fakeUser            = new MemberIdentityUser(777)
            {
                UserName = "******",
            };
            var password         = "******";
            var lockoutOnFailure = false;
            var isPersistent     = true;

            //act
            SignInResult actual = await sut.PasswordSignInAsync(fakeUser, password, isPersistent, lockoutOnFailure);

            //assert
            Assert.IsFalse(actual.Succeeded);
        }
Пример #16
0
        public async Task GivenAUserExists_AndIncorrectCredentialsAreProvided_ThenACheckOfCredentialsShouldFail()
        {
            //arrange
            var           password = "******";
            MemberManager sut      = CreateSut();

            MemberIdentityUser fakeUser = CreateValidUser();

            IMember fakeMember = CreateMember(fakeUser);

            MockMemberServiceForCreateMember(fakeMember);

            _mockMemberService.Setup(x => x.GetByUsername(It.Is <string>(y => y == fakeUser.UserName))).Returns(fakeMember);

            _mockPasswordHasher.Setup(x => x.VerifyHashedPassword(It.IsAny <MemberIdentityUser>(), It.IsAny <string>(), It.IsAny <string>())).Returns(PasswordVerificationResult.Failed);

            //act
            await sut.CreateAsync(fakeUser);

            var result = await sut.ValidateCredentialsAsync(fakeUser.UserName, password);

            //assert
            Assert.IsFalse(result);
        }
Пример #17
0
        public async Task <IActionResult> HandleUpdateProfile([Bind(Prefix = "profileModel")] ProfileModel model)
        {
            if (ModelState.IsValid == false)
            {
                return(CurrentUmbracoPage());
            }

            MergeRouteValuesToModel(model);

            MemberIdentityUser currentMember = await _memberManager.GetUserAsync(HttpContext.User);

            if (currentMember == null)
            {
                // this shouldn't happen, we also don't want to return an error so just redirect to where we came from
                return(RedirectToCurrentUmbracoPage());
            }

            IdentityResult result = await UpdateMemberAsync(model, currentMember);

            if (!result.Succeeded)
            {
                AddErrors(result);
                return(CurrentUmbracoPage());
            }

            TempData["FormSuccess"] = true;

            // If there is a specified path to redirect to then use it.
            if (model.RedirectUrl.IsNullOrWhiteSpace() == false)
            {
                return(Redirect(model.RedirectUrl));
            }

            // Redirect to current page by default.
            return(RedirectToCurrentUmbracoPage());
        }
Пример #18
0
        public async Task <PublicAccessStatus> HasMemberAccessToContentAsync(int publishedContentId)
        {
            HttpContext    httpContext   = _httpContextAccessor.GetRequiredHttpContext();
            IMemberManager memberManager = httpContext.RequestServices.GetRequiredService <IMemberManager>();

            if (httpContext.User.Identity == null || !httpContext.User.Identity.IsAuthenticated)
            {
                return(PublicAccessStatus.NotLoggedIn);
            }
            MemberIdentityUser currentMember = await memberManager.GetUserAsync(httpContext.User);

            if (currentMember == null)
            {
                return(PublicAccessStatus.NotLoggedIn);
            }

            var            username  = currentMember.UserName;
            IList <string> userRoles = await memberManager.GetRolesAsync(currentMember);

            if (!currentMember.IsApproved)
            {
                return(PublicAccessStatus.NotApproved);
            }

            if (currentMember.IsLockedOut)
            {
                return(PublicAccessStatus.LockedOut);
            }

            if (!_publicAccessService.HasAccess(publishedContentId, _contentService, username, userRoles))
            {
                return(PublicAccessStatus.AccessDenied);
            }

            return(PublicAccessStatus.AccessAccepted);
        }
Пример #19
0
    // Umbraco.Code.MapAll -Id -LockoutEnabled -PhoneNumber -PhoneNumberConfirmed -TwoFactorEnabled -ConcurrencyStamp -NormalizedEmail -NormalizedUserName -Roles
    private void Map(IMember source, MemberIdentityUser target)
    {
        target.Email    = source.Email;
        target.UserName = source.Username;
        target.LastPasswordChangeDateUtc = source.LastPasswordChangeDate?.ToUniversalTime();
        target.LastLoginDateUtc          = source.LastLoginDate?.ToUniversalTime();
        target.EmailConfirmed            = source.EmailConfirmedDate.HasValue;
        target.Name = source.Name;
        target.AccessFailedCount  = source.FailedPasswordAttempts;
        target.PasswordHash       = GetPasswordHash(source.RawPasswordValue);
        target.PasswordConfig     = source.PasswordConfiguration;
        target.IsApproved         = source.IsApproved;
        target.SecurityStamp      = source.SecurityStamp;
        target.LockoutEnd         = source.IsLockedOut ? DateTime.MaxValue.ToUniversalTime() : (DateTime?)null;
        target.Comments           = source.Comments;
        target.LastLockoutDateUtc = source.LastLockoutDate == DateTime.MinValue
            ? null
            : source.LastLockoutDate?.ToUniversalTime();
        target.CreatedDateUtc  = source.CreateDate.ToUniversalTime();
        target.Key             = source.Key;
        target.MemberTypeAlias = source.ContentTypeAlias;

        // NB: same comments re AutoMapper as per BackOfficeUser
    }
        /// <summary>
        /// Create a member from the supplied member content data
        ///
        /// All member password processing and creation is done via the identity manager
        /// </summary>
        /// <param name="contentItem">Member content data</param>
        /// <returns>The identity result of the created member</returns>
        private async Task <ActionResult <bool> > CreateMemberAsync(MemberSave contentItem)
        {
            IMemberType?memberType = _memberTypeService.Get(contentItem.ContentTypeAlias);

            if (memberType == null)
            {
                throw new InvalidOperationException($"No member type found with alias {contentItem.ContentTypeAlias}");
            }

            var identityMember = MemberIdentityUser.CreateNew(
                contentItem.Username,
                contentItem.Email,
                memberType.Alias,
                contentItem.IsApproved,
                contentItem.Name);

            IdentityResult created = await _memberManager.CreateAsync(identityMember, contentItem.Password?.NewPassword);

            if (created.Succeeded == false)
            {
                MemberDisplay?forDisplay = _umbracoMapper.Map <MemberDisplay>(contentItem.PersistedContent);
                foreach (IdentityError error in created.Errors)
                {
                    switch (error.Code)
                    {
                    case nameof(IdentityErrorDescriber.InvalidUserName):
                        ModelState.AddPropertyError(
                            new ValidationResult(error.Description, new[] { "value" }),
                            string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                        break;

                    case nameof(IdentityErrorDescriber.PasswordMismatch):
                    case nameof(IdentityErrorDescriber.PasswordRequiresDigit):
                    case nameof(IdentityErrorDescriber.PasswordRequiresLower):
                    case nameof(IdentityErrorDescriber.PasswordRequiresNonAlphanumeric):
                    case nameof(IdentityErrorDescriber.PasswordRequiresUniqueChars):
                    case nameof(IdentityErrorDescriber.PasswordRequiresUpper):
                    case nameof(IdentityErrorDescriber.PasswordTooShort):
                        ModelState.AddPropertyError(
                            new ValidationResult(error.Description, new[] { "value" }),
                            string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                        break;

                    case nameof(IdentityErrorDescriber.InvalidEmail):
                        ModelState.AddPropertyError(
                            new ValidationResult(error.Description, new[] { "value" }),
                            string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                        break;

                    case nameof(IdentityErrorDescriber.DuplicateUserName):
                        ModelState.AddPropertyError(
                            new ValidationResult(error.Description, new[] { "value" }),
                            string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                        break;

                    case nameof(IdentityErrorDescriber.DuplicateEmail):
                        ModelState.AddPropertyError(
                            new ValidationResult(error.Description, new[] { "value" }),
                            string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                        break;
                    }
                }
                return(ValidationProblem(forDisplay, ModelState));
            }

            // now re-look up the member, which will now exist
            IMember?member = _memberService.GetByEmail(contentItem.Email);

            if (member is null)
            {
                return(false);
            }

            // map the save info over onto the user
            member = _umbracoMapper.Map <MemberSave, IMember>(contentItem, member);

            int creatorId = _backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.Id ?? -1;

            member.CreatorId = creatorId;

            // assign the mapped property values that are not part of the identity properties
            string[] builtInAliases = ConventionsHelper.GetStandardPropertyTypeStubs(_shortStringHelper).Select(x => x.Key).ToArray();
            foreach (ContentPropertyBasic property in contentItem.Properties)
            {
                if (builtInAliases.Contains(property.Alias) == false)
                {
                    member.Properties[property.Alias]?.SetValue(property.Value);
                }
            }

            // now the member has been saved via identity, resave the member with mapped content properties
            _memberService.Save(member);
            contentItem.PersistedContent = member;

            ActionResult <bool> rolesChanged = await AddOrUpdateRoles(contentItem.Groups, identityMember);

            if (!rolesChanged.Value && rolesChanged.Result != null)
            {
                return(rolesChanged.Result);
            }

            return(true);
        }
Пример #21
0
    public async Task GivenIUpdateAUser_ThenIShouldGetASuccessResultAsync()
    {
        // arrange
        var sut      = CreateSut();
        var fakeUser = new MemberIdentityUser
        {
            Id                        = "123",
            Name                      = "fakeName",
            Email                     = "*****@*****.**",
            UserName                  = "******",
            Comments                  = "hello",
            LastLoginDateUtc          = DateTime.UtcNow,
            LastPasswordChangeDateUtc = DateTime.UtcNow,
            EmailConfirmed            = true,
            AccessFailedCount         = 3,
            LockoutEnd                = DateTime.UtcNow.AddDays(10),
            IsApproved                = true,
            PasswordHash              = "abcde",
            SecurityStamp             = "abc",
        };

        fakeUser.Roles.Add(new IdentityUserRole <string> {
            RoleId = "role1", UserId = "123"
        });
        fakeUser.Roles.Add(new IdentityUserRole <string> {
            RoleId = "role2", UserId = "123"
        });

        IMemberType fakeMemberType = new MemberType(new MockShortStringHelper(), 77);
        var         mockMember     = Mock.Of <IMember>(m =>
                                                       m.Id == 123 &&
                                                       m.Name == "a" &&
                                                       m.Email == "*****@*****.**" &&
                                                       m.Username == "c" &&
                                                       m.RawPasswordValue == "d" &&
                                                       m.Comments == "e" &&
                                                       m.ContentTypeAlias == fakeMemberType.Alias &&
                                                       m.HasIdentity == true &&
                                                       m.EmailConfirmedDate == DateTime.MinValue &&
                                                       m.FailedPasswordAttempts == 0 &&
                                                       m.LastLockoutDate == DateTime.MinValue &&
                                                       m.IsApproved == false &&
                                                       m.RawPasswordValue == "xyz" &&
                                                       m.SecurityStamp == "xyz");

        _mockMemberService.Setup(x => x.Save(mockMember));
        _mockMemberService.Setup(x => x.GetById(123)).Returns(mockMember);

        // act
        var identityResult = await sut.UpdateAsync(fakeUser, CancellationToken.None);

        // assert
        Assert.IsTrue(identityResult.Succeeded);
        Assert.IsTrue(!identityResult.Errors.Any());

        Assert.AreEqual(fakeUser.Name, mockMember.Name);
        Assert.AreEqual(fakeUser.Email, mockMember.Email);
        Assert.AreEqual(fakeUser.UserName, mockMember.Username);
        Assert.AreEqual(fakeUser.Comments, mockMember.Comments);
        Assert.AreEqual(fakeUser.LastPasswordChangeDateUtc.Value.ToLocalTime(), mockMember.LastPasswordChangeDate);
        Assert.AreEqual(fakeUser.LastLoginDateUtc.Value.ToLocalTime(), mockMember.LastLoginDate);
        Assert.AreEqual(fakeUser.AccessFailedCount, mockMember.FailedPasswordAttempts);
        Assert.AreEqual(fakeUser.IsLockedOut, mockMember.IsLockedOut);
        Assert.AreEqual(fakeUser.IsApproved, mockMember.IsApproved);
        Assert.AreEqual(fakeUser.PasswordHash, mockMember.RawPasswordValue);
        Assert.AreEqual(fakeUser.SecurityStamp, mockMember.SecurityStamp);
        Assert.AreNotEqual(DateTime.MinValue, mockMember.EmailConfirmedDate.Value);

        _mockMemberService.Verify(x => x.Save(mockMember));
        _mockMemberService.Verify(x => x.GetById(123));
        _mockMemberService.Verify(x => x.ReplaceRoles(new[] { 123 }, new[] { "role1", "role2" }));
    }
 private void MockGetUserAsync(IMemberManager memberManager, MemberIdentityUser memberIdentityUser)
 => Mock.Get(memberManager).Setup(x => x.GetUserAsync(It.IsAny <ClaimsPrincipal>())).Returns(Task.FromResult(memberIdentityUser));
        public async Task<IActionResult> ExternalLoginCallback(string returnUrl)
        {
            var errors = new List<string>();

            ExternalLoginInfo loginInfo = await _memberSignInManager.GetExternalLoginInfoAsync();
            if (loginInfo is null)
            {
                errors.Add("Invalid response from the login provider");
            }
            else
            {
                SignInResult result = await _memberSignInManager.ExternalLoginSignInAsync(loginInfo, false);

                if (result == SignInResult.Success)
                {
                    // Update any authentication tokens if succeeded
                    await _memberSignInManager.UpdateExternalAuthenticationTokensAsync(loginInfo);

                    return RedirectToLocal(returnUrl);
                }

                if (result == SignInResult.TwoFactorRequired)
                {
                    MemberIdentityUser attemptedUser =
                        await _memberManager.FindByLoginAsync(loginInfo.LoginProvider, loginInfo.ProviderKey);
                    if (attemptedUser == null)
                    {
                        return new ValidationErrorResult(
                            $"No local user found for the login provider {loginInfo.LoginProvider} - {loginInfo.ProviderKey}");
                    }

                    // create a with information to display a custom two factor send code view
                    var verifyResponse =
                        new ObjectResult(new { userId = attemptedUser.Id })
                        {
                            StatusCode = StatusCodes.Status402PaymentRequired
                        };

                    return verifyResponse;
                }

                if (result == SignInResult.LockedOut)
                {
                    errors.Add(
                        $"The local member {loginInfo.Principal.Identity.Name} for the external provider {loginInfo.ProviderDisplayName} is locked out.");
                }
                else if (result == SignInResult.NotAllowed)
                {
                    // This occurs when SignInManager.CanSignInAsync fails which is when RequireConfirmedEmail , RequireConfirmedPhoneNumber or RequireConfirmedAccount fails
                    // however since we don't enforce those rules (yet) this shouldn't happen.
                    errors.Add(
                        $"The member {loginInfo.Principal.Identity.Name} for the external provider {loginInfo.ProviderDisplayName} has not confirmed their details and cannot sign in.");
                }
                else if (result == SignInResult.Failed)
                {
                    // Failed only occurs when the user does not exist
                    errors.Add("The requested provider (" + loginInfo.LoginProvider +
                               ") has not been linked to an account, the provider must be linked before it can be used.");
                }
                else if (result == MemberSignInManager.ExternalLoginSignInResult.NotAllowed)
                {
                    // This occurs when the external provider has approved the login but custom logic in OnExternalLogin has denined it.
                    errors.Add(
                        $"The user {loginInfo.Principal.Identity.Name} for the external provider {loginInfo.ProviderDisplayName} has not been accepted and cannot sign in.");
                }
                else if (result == MemberSignInManager.AutoLinkSignInResult.FailedNotLinked)
                {
                    errors.Add("The requested provider (" + loginInfo.LoginProvider +
                               ") has not been linked to an account, the provider must be linked from the back office.");
                }
                else if (result == MemberSignInManager.AutoLinkSignInResult.FailedNoEmail)
                {
                    errors.Add(
                        $"The requested provider ({loginInfo.LoginProvider}) has not provided the email claim {ClaimTypes.Email}, the account cannot be linked.");
                }
                else if (result is MemberSignInManager.AutoLinkSignInResult autoLinkSignInResult &&
                         autoLinkSignInResult.Errors.Count > 0)
                {
                    errors.AddRange(autoLinkSignInResult.Errors);
                }
        /// <summary>
        /// Update existing member data
        /// </summary>
        /// <param name="contentItem">The member to save</param>
        /// <remarks>
        /// We need to use both IMemberService and ASP.NET Identity to do our updates because Identity is responsible for passwords/security.
        /// When this method is called, the IMember will already have updated/mapped values from the http POST.
        /// So then we do this in order:
        /// 1. Deal with sensitive property values on IMember
        /// 2. Use IMemberService to persist all changes
        /// 3. Use ASP.NET and MemberUserManager to deal with lockouts
        /// 4. Use ASP.NET, MemberUserManager and password changer to deal with passwords
        /// 5. Deal with groups/roles
        /// </remarks>
        private async Task <ActionResult <bool> > UpdateMemberAsync(MemberSave contentItem)
        {
            if (contentItem.PersistedContent is not null)
            {
                contentItem.PersistedContent.WriterId = _backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.Id ?? -1;
            }

            // If the user doesn't have access to sensitive values, then we need to check if any of the built in member property types
            // have been marked as sensitive. If that is the case we cannot change these persisted values no matter what value has been posted.
            // There's only 3 special ones we need to deal with that are part of the MemberSave instance: Comments, IsApproved, IsLockedOut
            // but we will take care of this in a generic way below so that it works for all props.
            if (!_backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.HasAccessToSensitiveData() ?? true)
            {
                IMemberType?memberType          = contentItem.PersistedContent is null ? null : _memberTypeService.Get(contentItem.PersistedContent.ContentTypeId);
                var         sensitiveProperties = memberType?
                                                  .PropertyTypes.Where(x => memberType.IsSensitiveProperty(x.Alias))
                                                  .ToList();

                if (sensitiveProperties is not null)
                {
                    foreach (IPropertyType sensitiveProperty in sensitiveProperties)
                    {
                        // TODO: This logic seems to deviate from the logic that is in v8 where we are explitly checking
                        // against 3 properties: Comments, IsApproved, IsLockedOut, is the v8 version incorrect?

                        ContentPropertyBasic?destProp = contentItem.Properties.FirstOrDefault(x => x.Alias == sensitiveProperty.Alias);
                        if (destProp != null)
                        {
                            // if found, change the value of the contentItem model to the persisted value so it remains unchanged
                            object?origValue = contentItem.PersistedContent?.GetValue(sensitiveProperty.Alias);
                            destProp.Value = origValue;
                        }
                    }
                }
            }

            if (contentItem.PersistedContent is not null)
            {
                // First save the IMember with mapped values before we start updating data with aspnet identity
                _memberService.Save(contentItem.PersistedContent);
            }

            bool needsResync = false;

            MemberIdentityUser identityMember = await _memberManager.FindByIdAsync(contentItem.Id?.ToString());

            if (identityMember == null)
            {
                return(ValidationProblem("Member was not found"));
            }

            // Handle unlocking with the member manager (takes care of other nuances)
            if (identityMember.IsLockedOut && contentItem.IsLockedOut == false)
            {
                IdentityResult unlockResult = await _memberManager.SetLockoutEndDateAsync(identityMember, DateTimeOffset.Now.AddMinutes(-1));

                if (unlockResult.Succeeded == false)
                {
                    return(ValidationProblem(
                               $"Could not unlock for member {contentItem.Id} - error {unlockResult.Errors.ToErrorMessage()}"));
                }
                needsResync = true;
            }
            else if (identityMember.IsLockedOut == false && contentItem.IsLockedOut)
            {
                // NOTE: This should not ever happen unless someone is mucking around with the request data.
                // An admin cannot simply lock a user, they get locked out by password attempts, but an admin can unlock them
                return(ValidationProblem("An admin cannot lock a member"));
            }

            // If we're changing the password...
            // Handle changing with the member manager & password changer (takes care of other nuances)
            if (contentItem.Password != null)
            {
                IdentityResult validatePassword = await _memberManager.ValidatePasswordAsync(contentItem.Password.NewPassword);

                if (validatePassword.Succeeded == false)
                {
                    return(ValidationProblem(validatePassword.Errors.ToErrorMessage()));
                }

                if (!int.TryParse(identityMember.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId))
                {
                    return(ValidationProblem("Member ID was not valid"));
                }

                var changingPasswordModel = new ChangingPasswordModel
                {
                    Id          = intId,
                    OldPassword = contentItem.Password.OldPassword,
                    NewPassword = contentItem.Password.NewPassword,
                };

                // Change and persist the password
                Attempt <PasswordChangedModel?> passwordChangeResult = await _passwordChanger.ChangePasswordWithIdentityAsync(changingPasswordModel, _memberManager);

                if (!passwordChangeResult.Success)
                {
                    foreach (string memberName in passwordChangeResult.Result?.ChangeError?.MemberNames ?? Enumerable.Empty <string>())
                    {
                        ModelState.AddModelError(memberName, passwordChangeResult.Result?.ChangeError?.ErrorMessage ?? string.Empty);
                    }
                    return(ValidationProblem(ModelState));
                }

                needsResync = true;
            }

            // Update the roles and check for changes
            ActionResult <bool> rolesChanged = await AddOrUpdateRoles(contentItem.Groups, identityMember);

            if (!rolesChanged.Value && rolesChanged.Result != null)
            {
                return(rolesChanged.Result);
            }
            else
            {
                needsResync = true;
            }

            // If there have been underlying changes made by ASP.NET Identity, then we need to resync the
            // IMember on the PersistedContent with what is stored since it will be mapped to display.
            if (needsResync && contentItem.PersistedContent is not null)
            {
                contentItem.PersistedContent = _memberService.GetById(contentItem.PersistedContent.Id) !;
            }

            return(true);
        }
Пример #25
0
        public async Task <IActionResult> ExternalLoginCallback(string returnUrl)
        {
            var errors = new List <string>();

            ExternalLoginInfo?loginInfo = await _memberSignInManager.GetExternalLoginInfoAsync();

            if (loginInfo is null)
            {
                errors.Add("Invalid response from the login provider");
            }
            else
            {
                SignInResult result = await _memberSignInManager.ExternalLoginSignInAsync(loginInfo, false, _securitySettings.Value.MemberBypassTwoFactorForExternalLogins);

                if (result == SignInResult.Success)
                {
                    // Update any authentication tokens if succeeded
                    await _memberSignInManager.UpdateExternalAuthenticationTokensAsync(loginInfo);

                    return(RedirectToLocal(returnUrl));
                }

                if (result == SignInResult.TwoFactorRequired)
                {
                    MemberIdentityUser attemptedUser =
                        await _memberManager.FindByLoginAsync(loginInfo.LoginProvider, loginInfo.ProviderKey);

                    if (attemptedUser == null)
                    {
                        return(new ValidationErrorResult(
                                   $"No local user found for the login provider {loginInfo.LoginProvider} - {loginInfo.ProviderKey}"));
                    }


                    var providerNames = await _twoFactorLoginService.GetEnabledTwoFactorProviderNamesAsync(attemptedUser.Key);

                    ViewData.SetTwoFactorProviderNames(providerNames);

                    return(CurrentUmbracoPage());
                }

                if (result == SignInResult.LockedOut)
                {
                    errors.Add(
                        $"The local member {loginInfo.Principal.Identity?.Name} for the external provider {loginInfo.ProviderDisplayName} is locked out.");
                }
                else if (result == SignInResult.NotAllowed)
                {
                    // This occurs when SignInManager.CanSignInAsync fails which is when RequireConfirmedEmail , RequireConfirmedPhoneNumber or RequireConfirmedAccount fails
                    // however since we don't enforce those rules (yet) this shouldn't happen.
                    errors.Add(
                        $"The member {loginInfo.Principal.Identity?.Name} for the external provider {loginInfo.ProviderDisplayName} has not confirmed their details and cannot sign in.");
                }
                else if (result == SignInResult.Failed)
                {
                    // Failed only occurs when the user does not exist
                    errors.Add("The requested provider (" + loginInfo.LoginProvider +
                               ") has not been linked to an account, the provider must be linked before it can be used.");
                }
                else if (result == MemberSignInManager.ExternalLoginSignInResult.NotAllowed)
                {
                    // This occurs when the external provider has approved the login but custom logic in OnExternalLogin has denined it.
                    errors.Add(
                        $"The user {loginInfo.Principal.Identity?.Name} for the external provider {loginInfo.ProviderDisplayName} has not been accepted and cannot sign in.");
                }
                else if (result == MemberSignInManager.AutoLinkSignInResult.FailedNotLinked)
                {
                    errors.Add("The requested provider (" + loginInfo.LoginProvider +
                               ") has not been linked to an account, the provider must be linked from the back office.");
                }
                else if (result == MemberSignInManager.AutoLinkSignInResult.FailedNoEmail)
                {
                    errors.Add(
                        $"The requested provider ({loginInfo.LoginProvider}) has not provided the email claim {ClaimTypes.Email}, the account cannot be linked.");
                }
                else if (result is MemberSignInManager.AutoLinkSignInResult autoLinkSignInResult &&
                         autoLinkSignInResult.Errors.Count > 0)
                {
                    errors.AddRange(autoLinkSignInResult.Errors);
                }
        /// <summary>
        /// Add or update the identity roles
        /// </summary>
        /// <param name="groups">The groups to updates</param>
        /// <param name="identityMember">The member as an identity user</param>
        private async Task <ActionResult <bool> > AddOrUpdateRoles(IEnumerable <string>?groups, MemberIdentityUser identityMember)
        {
            var hasChanges = false;

            // We're gonna look up the current roles now because the below code can cause
            // events to be raised and developers could be manually adding roles to members in
            // their handlers. If we don't look this up now there's a chance we'll just end up
            // removing the roles they've assigned.
            IEnumerable <string> currentRoles = await _memberManager.GetRolesAsync(identityMember);

            // find the ones to remove and remove them
            IEnumerable <string> roles = currentRoles.ToList();

            string[] rolesToRemove = roles.Except(groups ?? Enumerable.Empty <string>()).ToArray();

            // Now let's do the role provider stuff - now that we've saved the content item (that is important since
            // if we are changing the username, it must be persisted before looking up the member roles).
            if (rolesToRemove.Any())
            {
                IdentityResult identityResult = await _memberManager.RemoveFromRolesAsync(identityMember, rolesToRemove);

                if (!identityResult.Succeeded)
                {
                    return(ValidationProblem(identityResult.Errors.ToErrorMessage()));
                }
                hasChanges = true;
            }

            // find the ones to add and add them
            string[]? toAdd = groups?.Except(roles).ToArray();
            if (toAdd?.Any() ?? false)
            {
                // add the ones submitted
                IdentityResult identityResult = await _memberManager.AddToRolesAsync(identityMember, toAdd);

                if (!identityResult.Succeeded)
                {
                    return(ValidationProblem(identityResult.Errors.ToErrorMessage()));
                }
                hasChanges = true;
            }

            return(hasChanges);
        }
Пример #27
0
        public async Task PostSaveMember_SaveExistingMember_WithNoRoles_Add1Role_ExpectSuccessResponse(
            [Frozen] IMemberManager umbracoMembersUserManager,
            IMemberService memberService,
            IMemberTypeService memberTypeService,
            IMemberGroupService memberGroupService,
            IDataTypeService dataTypeService,
            IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
            IBackOfficeSecurity backOfficeSecurity,
            IPasswordChanger <MemberIdentityUser> passwordChanger,
            IOptions <GlobalSettings> globalSettings,
            IUser user)
        {
            // arrange
            var     roleName = "anyrole";
            IMember member   = SetupMemberTestData(out MemberSave fakeMemberData, out MemberDisplay memberDisplay, ContentSaveAction.Save);

            fakeMemberData.Groups = new List <string>()
            {
                roleName
            };
            var membersIdentityUser = new MemberIdentityUser(123);

            Mock.Get(umbracoMembersUserManager)
            .Setup(x => x.FindByIdAsync(It.IsAny <string>()))
            .ReturnsAsync(() => membersIdentityUser);
            Mock.Get(umbracoMembersUserManager)
            .Setup(x => x.ValidatePasswordAsync(It.IsAny <string>()))
            .ReturnsAsync(() => IdentityResult.Success);
            Mock.Get(umbracoMembersUserManager)
            .Setup(x => x.UpdateAsync(It.IsAny <MemberIdentityUser>()))
            .ReturnsAsync(() => IdentityResult.Success);
            Mock.Get(umbracoMembersUserManager)
            .Setup(x => x.AddToRolesAsync(It.IsAny <MemberIdentityUser>(), It.IsAny <IEnumerable <string> >()))
            .ReturnsAsync(() => IdentityResult.Success);
            Mock.Get(memberTypeService).Setup(x => x.GetDefault()).Returns("fakeAlias");
            Mock.Get(backOfficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(backOfficeSecurity);
            Mock.Get(memberService).Setup(x => x.GetByUsername(It.IsAny <string>())).Returns(() => member);
            Mock.Get(memberService).Setup(x => x.GetById(It.IsAny <int>())).Returns(() => member);

            SetupUserAccess(backOfficeSecurityAccessor, backOfficeSecurity, user);
            SetupPasswordSuccess(umbracoMembersUserManager, passwordChanger);

            Mock.Get(memberService).SetupSequence(
                x => x.GetByEmail(It.IsAny <string>()))
            .Returns(() => null)
            .Returns(() => member);
            MemberController sut = CreateSut(memberService, memberTypeService, memberGroupService, umbracoMembersUserManager, dataTypeService, backOfficeSecurityAccessor, passwordChanger, globalSettings, user);

            // act
            ActionResult <MemberDisplay> result = await sut.PostSave(fakeMemberData);

            // assert
            Assert.IsNull(result.Result);
            Assert.IsNotNull(result.Value);
            Mock.Get(umbracoMembersUserManager)
            .Verify(u => u.GetRolesAsync(membersIdentityUser));
            Mock.Get(umbracoMembersUserManager)
            .Verify(u => u.AddToRolesAsync(membersIdentityUser, new[] { roleName }));
            Mock.Get(memberService)
            .Verify(m => m.Save(It.IsAny <Member>()));
            AssertMemberDisplayPropertiesAreEqual(memberDisplay, result.Value);
        }
Пример #28
0
        public async Task <IActionResult> HandleLogin([Bind(Prefix = "loginModel")] LoginModel model)
        {
            if (ModelState.IsValid == false)
            {
                return(CurrentUmbracoPage());
            }

            MergeRouteValuesToModel(model);

            // Sign the user in with username/password, this also gives a chance for developers to
            // custom verify the credentials and auto-link user accounts with a custom IBackOfficePasswordChecker
            SignInResult result = await _signInManager.PasswordSignInAsync(
                model.Username, model.Password, isPersistent : model.RememberMe, lockoutOnFailure : true);

            if (result.Succeeded)
            {
                TempData["LoginSuccess"] = true;

                // If there is a specified path to redirect to then use it.
                if (model.RedirectUrl.IsNullOrWhiteSpace() == false)
                {
                    // Validate the redirect URL.
                    // If it's not a local URL we'll redirect to the root of the current site.
                    return(Redirect(Url.IsLocalUrl(model.RedirectUrl)
                        ? model.RedirectUrl
                        : CurrentPage !.AncestorOrSelf(1) !.Url(PublishedUrlProvider)));
                }

                // Redirect to current URL by default.
                // This is different from the current 'page' because when using Public Access the current page
                // will be the login page, but the URL will be on the requested page so that's where we need
                // to redirect too.
                return(RedirectToCurrentUmbracoUrl());
            }

            if (result.RequiresTwoFactor)
            {
                MemberIdentityUser attemptedUser = await _memberManager.FindByNameAsync(model.Username);

                if (attemptedUser == null)
                {
                    return(new ValidationErrorResult(
                               $"No local member found for username {model.Username}"));
                }

                var providerNames = await _twoFactorLoginService.GetEnabledTwoFactorProviderNamesAsync(attemptedUser.Key);

                ViewData.SetTwoFactorProviderNames(providerNames);
            }
            else if (result.IsLockedOut)
            {
                ModelState.AddModelError("loginModel", "Member is locked out");
            }
            else if (result.IsNotAllowed)
            {
                ModelState.AddModelError("loginModel", "Member is not allowed");
            }
            else
            {
                ModelState.AddModelError("loginModel", "Invalid username or password");
            }
            return(CurrentUmbracoPage());
        }