diff --git a/src/Microsoft.AspNet.Identity/UserManager.cs b/src/Microsoft.AspNet.Identity/UserManager.cs index 077298fa70..c7df9db3d8 100644 --- a/src/Microsoft.AspNet.Identity/UserManager.cs +++ b/src/Microsoft.AspNet.Identity/UserManager.cs @@ -487,11 +487,17 @@ namespace Microsoft.AspNet.Identity { throw new ArgumentNullException("user"); } - await Store.SetUserNameAsync(user, userName, cancellationToken); - await UpdateNormalizedUserName(user, cancellationToken); + await UpdateUserName(user, userName, cancellationToken); return await UpdateAsync(user, cancellationToken); } + private async Task UpdateUserName(TUser user, string userName, CancellationToken cancellationToken) + { + await Store.SetUserNameAsync(user, userName, cancellationToken); + await UpdateNormalizedUserName(user, cancellationToken); + } + + /// /// Get the user's id /// @@ -1124,6 +1130,11 @@ namespace Microsoft.AspNet.Identity CancellationToken cancellationToken = default(CancellationToken)) { ThrowIfDisposed(); + if (Options.User.UseUserNameAsEmail) + { + return await GetUserNameAsync(user, cancellationToken); + } + var store = GetEmailStore(); if (user == null) { @@ -1143,6 +1154,12 @@ namespace Microsoft.AspNet.Identity CancellationToken cancellationToken = default(CancellationToken)) { ThrowIfDisposed(); + + if (Options.User.UseUserNameAsEmail) + { + await UpdateUserName(user, email, cancellationToken); + } + var store = GetEmailStore(); if (user == null) { @@ -1164,6 +1181,11 @@ namespace Microsoft.AspNet.Identity CancellationToken cancellationToken = default(CancellationToken)) { ThrowIfDisposed(); + if (Options.User.UseUserNameAsEmail) + { + return FindByNameAsync(email, cancellationToken); + } + var store = GetEmailStore(); if (email == null) { diff --git a/src/Microsoft.AspNet.Identity/UserOptions.cs b/src/Microsoft.AspNet.Identity/UserOptions.cs index 7c5b90977d..5b2578aa3b 100644 --- a/src/Microsoft.AspNet.Identity/UserOptions.cs +++ b/src/Microsoft.AspNet.Identity/UserOptions.cs @@ -20,5 +20,10 @@ namespace Microsoft.AspNet.Identity /// If set, enforces that emails are non empty, valid, and unique /// public bool RequireUniqueEmail { get; set; } + + /// + /// If set, the user name will also be considered the email + /// + public bool UseUserNameAsEmail { get; set; } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Identity.EntityFramework.Test/UserStoreTestBase.cs b/test/Microsoft.AspNet.Identity.EntityFramework.Test/UserStoreTestBase.cs index e920c017e8..2836b10290 100644 --- a/test/Microsoft.AspNet.Identity.EntityFramework.Test/UserStoreTestBase.cs +++ b/test/Microsoft.AspNet.Identity.EntityFramework.Test/UserStoreTestBase.cs @@ -502,6 +502,24 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test IdentityResultAssert.IsFailure(result, "A user with that external login already exists."); } + [Fact] + public async Task UserNameAsEmailTest() + { + var manager = CreateManager(); + manager.Options.User.UseUserNameAsEmail = true; + manager.Options.User.AllowOnlyAlphanumericNames = false; + const string email = "email@test.com"; + var user = new ApplicationUser { UserName = email }; + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + Assert.Equal(user, await manager.FindByEmailAsync(email)); + Assert.Equal(email, await manager.GetEmailAsync(user)); + const string newEmail = "modified@woot.com"; + IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, newEmail)); + Assert.Equal(newEmail, user.UserName); + Assert.Equal(newEmail, user.Email); + Assert.False(user.EmailConfirmed); + } + // Email tests [Fact] public async Task CanFindByEmail() @@ -511,8 +529,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test var user = new ApplicationUser { Email = email }; IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); var fetch = await manager.FindByEmailAsync(email); - //Assert.Equal(user, fetch); - Assert.Equal(user.Id, fetch.Id); + Assert.Equal(user, fetch); } [Fact] diff --git a/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs b/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs index ba8c556988..fd678c07b8 100644 --- a/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs @@ -42,8 +42,6 @@ namespace Microsoft.AspNet.Identity.Test Assert.NotNull(manager.Options); } -#if NET45 - //TODO: Mock fails in K (this works fine in net45) [Fact] public async Task CreateCallsStore() { @@ -164,6 +162,65 @@ namespace Microsoft.AspNet.Identity.Test store.VerifyAll(); } + [Fact] + public async Task UseUserNameAsEmailCallsStoreFindByName() + { + // Setup + var store = new Mock>(); + var user = new TestUser {UserName="Foo"}; + store.Setup(s => s.FindByNameAsync(user.UserName, CancellationToken.None)).Returns(Task.FromResult(user)).Verifiable(); + var userManager = MockHelpers.TestUserManager(store.Object); + userManager.Options.User.UseUserNameAsEmail = true; + userManager.UserNameNormalizer = null; + + // Act + var result = await userManager.FindByEmailAsync(user.UserName); + + // Assert + Assert.Equal(user, result); + store.VerifyAll(); + } + + [Fact] + public async Task UseUserNameAsEmailReturnsName() + { + // Setup + var store = new Mock>(); + var user = new TestUser { UserName = "Foo@email.com" }; + store.Setup(s => s.GetUserNameAsync(user, CancellationToken.None)).ReturnsAsync(user.UserName).Verifiable(); + var userManager = MockHelpers.TestUserManager(store.Object); + userManager.Options.User.UseUserNameAsEmail = true; + userManager.UserNameNormalizer = null; + + // Act + var result = await userManager.GetEmailAsync(user); + + // Assert + Assert.Equal(user.UserName, result); + store.VerifyAll(); + } + + [Fact] + public async Task UseUserNameAsEmailUpdatesNameAndEmail() + { + // Setup + var store = new Mock>(); + var user = new TestUser { UserName = "Foo" }; + var email = "foo@foo.com"; + store.Setup(s => s.SetUserNameAsync(user, email, CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable(); + store.Setup(s => s.SetEmailAsync(user, email, CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable(); + store.Setup(s => s.SetEmailConfirmedAsync(user, false, CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable(); + var userManager = MockHelpers.TestUserManager(store.Object); + userManager.Options.User.UseUserNameAsEmail = true; + userManager.UserNameNormalizer = null; + + // Act + IdentityResultAssert.IsSuccess(await userManager.SetEmailAsync(user, email)); + + // Assert + store.VerifyAll(); + } + [Fact] public async Task AddToRolesCallsStore() { @@ -275,8 +332,6 @@ namespace Microsoft.AspNet.Identity.Test store.VerifyAll(); } -#endif - [Fact] public async Task CheckPasswordWithNullUserReturnsFalse() {