-
Notifications
You must be signed in to change notification settings - Fork 641
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
If ConfirmEmailAddresses config is false, users should not be require…
…d to confirm changing their email (#6314)
- Loading branch information
Scott Bommarito
authored
Aug 16, 2018
1 parent
1b3707e
commit 8ac0bcb
Showing
5 changed files
with
140 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -227,7 +227,23 @@ public virtual async Task WhenNewEmailIsSame_RedirectsWithoutChange(Func<Fakes, | |
|
||
[Theory] | ||
[MemberData(AllowedCurrentUsersDataName)] | ||
public virtual async Task WhenNewEmailIsDifferentAndWasConfirmed_SavesChanges(Func<Fakes, User> getCurrentUser) | ||
public virtual Task WhenNewEmailIsUnconfirmedAndDifferentAndWasConfirmed_SavesChanges(Func<Fakes, User> getCurrentUser) | ||
{ | ||
return WhenNewEmailIsDifferentAndWasConfirmedHelper(getCurrentUser, newEmailIsConfirmed: false); | ||
} | ||
|
||
[Theory] | ||
[MemberData(AllowedCurrentUsersDataName)] | ||
public virtual Task WhenNewEmailIsConfirmedAndDifferentAndWasConfirmed_SavesChanges(Func<Fakes, User> getCurrentUser) | ||
{ | ||
return WhenNewEmailIsDifferentAndWasConfirmedHelper(getCurrentUser, newEmailIsConfirmed: true); | ||
} | ||
|
||
/// <remarks> | ||
/// Normally, you should use a single <see cref="TheoryAttribute"/> that enumerates through the possible values of <paramref name="getCurrentUser"/> and <paramref name="newEmailIsConfirmed"/>, | ||
/// but because we are using test case "inheritance" (search for properties with the same name as <see cref="AllowedCurrentUsersDataName"/>), this is not possible. | ||
/// </remarks> | ||
private async Task WhenNewEmailIsDifferentAndWasConfirmedHelper(Func<Fakes, User> getCurrentUser, bool newEmailIsConfirmed) | ||
{ | ||
// Arrange | ||
var controller = GetController(); | ||
|
@@ -236,15 +252,15 @@ public virtual async Task WhenNewEmailIsDifferentAndWasConfirmed_SavesChanges(Fu | |
model.ChangeEmail.NewEmail = "[email protected]"; | ||
|
||
// Act | ||
var result = await InvokeChangeEmail(controller, account, getCurrentUser, model); | ||
var result = await InvokeChangeEmail(controller, account, getCurrentUser, model, newEmailIsConfirmed); | ||
|
||
// Assert | ||
GetMock<IUserService>().Verify(u => u.ChangeEmailAddress(It.IsAny<User>(), It.IsAny<string>()), Times.Once); | ||
ResultAssert.IsRedirectToRoute(result, new { action = controller.AccountAction }); | ||
|
||
GetMock<IMessageService>() | ||
.Verify(m => m.SendEmailChangeConfirmationNotice(It.IsAny<User>(), It.IsAny<string>()), | ||
Times.Once); | ||
newEmailIsConfirmed ? Times.Never() : Times.Once()); | ||
} | ||
|
||
[Theory] | ||
|
@@ -285,6 +301,7 @@ protected virtual Task<ActionResult> InvokeChangeEmail( | |
TUser account, | ||
Func<Fakes, User> getCurrentUser, | ||
TAccountViewModel model = null, | ||
bool newEmailIsConfirmed = false, | ||
EntityException exception = null) | ||
{ | ||
// Arrange | ||
|
@@ -299,7 +316,17 @@ protected virtual Task<ActionResult> InvokeChangeEmail( | |
.Returns(account as User); | ||
|
||
var setup = userService.Setup(u => u.ChangeEmailAddress(It.IsAny<User>(), It.IsAny<string>())) | ||
.Callback<User, string>((acct, newEmail) => { acct.UnconfirmedEmailAddress = newEmail; }); | ||
.Callback<User, string>((acct, newEmail) => | ||
{ | ||
if (newEmailIsConfirmed) | ||
{ | ||
acct.EmailAddress = newEmail; | ||
} | ||
else | ||
{ | ||
acct.UnconfirmedEmailAddress = newEmail; | ||
} | ||
}); | ||
|
||
if (exception != null) | ||
{ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1156,13 +1156,38 @@ public async Task SetsUnconfirmedEmailWhenEmailIsChanged() | |
Users = new[] { user } | ||
}; | ||
|
||
service.MockConfig | ||
.Setup(x => x.ConfirmEmailAddresses) | ||
.Returns(true); | ||
|
||
await service.ChangeEmailAddress(user, "[email protected]"); | ||
|
||
Assert.Equal("[email protected]", user.EmailAddress); | ||
Assert.Equal("[email protected]", user.UnconfirmedEmailAddress); | ||
service.FakeEntitiesContext.VerifyCommitChanges(); | ||
} | ||
|
||
[Fact] | ||
public async Task AutomaticallyConfirmsWhenConfirmEmailAddressesConfigurationIsFalse() | ||
{ | ||
var user = new User { Username = "Bob", EmailAddress = "[email protected]" }; | ||
var service = new TestableUserServiceWithDBFaking | ||
{ | ||
Users = new[] { user } | ||
}; | ||
|
||
service.MockConfig | ||
.Setup(x => x.ConfirmEmailAddresses) | ||
.Returns(false); | ||
|
||
await service.ChangeEmailAddress(user, "[email protected]"); | ||
|
||
Assert.Equal("[email protected]", user.EmailAddress); | ||
Assert.Null(user.UnconfirmedEmailAddress); | ||
Assert.Null(user.EmailConfirmationToken); | ||
service.FakeEntitiesContext.VerifyCommitChanges(); | ||
} | ||
|
||
/// <summary> | ||
/// It has to change the pending confirmation token whenever address changes because otherwise you can do | ||
/// 1. change address, get confirmation email | ||
|
@@ -1178,6 +1203,10 @@ public async Task ModifiesConfirmationTokenWhenEmailAddressChanged() | |
Users = new User[] { user }, | ||
}; | ||
|
||
service.MockConfig | ||
.Setup(x => x.ConfirmEmailAddresses) | ||
.Returns(true); | ||
|
||
await service.ChangeEmailAddress(user, "[email protected]"); | ||
Assert.NotNull(user.EmailConfirmationToken); | ||
Assert.NotEmpty(user.EmailConfirmationToken); | ||
|
@@ -1197,6 +1226,10 @@ public async Task DoesNotModifyAnythingWhenConfirmedEmailAddressNotChanged() | |
Users = new User[] { user }, | ||
}; | ||
|
||
service.MockConfig | ||
.Setup(x => x.ConfirmEmailAddresses) | ||
.Returns(true); | ||
|
||
await service.ChangeEmailAddress(user, "[email protected]"); | ||
Assert.True(user.Confirmed); | ||
Assert.Equal("[email protected]", user.EmailAddress); | ||
|
@@ -1221,6 +1254,10 @@ public async Task DoesNotModifyConfirmationTokenWhenUnconfirmedEmailAddressNotCh | |
Users = new User[] { user }, | ||
}; | ||
|
||
service.MockConfig | ||
.Setup(x => x.ConfirmEmailAddresses) | ||
.Returns(true); | ||
|
||
await service.ChangeEmailAddress(user, "[email protected]"); | ||
Assert.Equal("pending-token", user.EmailConfirmationToken); | ||
} | ||
|
@@ -1784,11 +1821,16 @@ public class TheAddOrganizationAccountMethod | |
|
||
private TestableUserService _service = new TestableUserService(); | ||
|
||
[Fact] | ||
public async Task WithUsernameConflict_ThrowsEntityException() | ||
public static IEnumerable<object[]> ConfirmEmailAddresses_Config => MemberDataHelper.AsDataSet(false, true); | ||
|
||
[Theory] | ||
[MemberData(nameof(ConfirmEmailAddresses_Config))] | ||
public async Task WithUsernameConflict_ThrowsEntityException(bool confirmEmailAddresses) | ||
{ | ||
var conflictUsername = "ialreadyexist"; | ||
|
||
SetUpConfirmEmailAddressesConfig(confirmEmailAddresses); | ||
|
||
_service.MockEntitiesContext | ||
.Setup(x => x.Users) | ||
.Returns(new[] { new User(conflictUsername) }.MockDbSet().Object); | ||
|
@@ -1802,11 +1844,14 @@ public async Task WithUsernameConflict_ThrowsEntityException() | |
Assert.False(_service.Auditing.WroteRecord<UserAuditRecord>()); | ||
} | ||
|
||
[Fact] | ||
public async Task WithEmailConflict_ThrowsEntityException() | ||
[Theory] | ||
[MemberData(nameof(ConfirmEmailAddresses_Config))] | ||
public async Task WithEmailConflict_ThrowsEntityException(bool confirmEmailAddresses) | ||
{ | ||
var conflictEmail = "[email protected]"; | ||
|
||
SetUpConfirmEmailAddressesConfig(confirmEmailAddresses); | ||
|
||
_service.MockEntitiesContext | ||
.Setup(x => x.Users) | ||
.Returns(new[] { new User("user") { EmailAddress = conflictEmail } }.MockDbSet().Object); | ||
|
@@ -1820,25 +1865,31 @@ public async Task WithEmailConflict_ThrowsEntityException() | |
Assert.False(_service.Auditing.WroteRecord<UserAuditRecord>()); | ||
} | ||
|
||
[Fact] | ||
public async Task WhenAdminHasNoTenant_ReturnsNewOrgWithoutPolicy() | ||
[Theory] | ||
[MemberData(nameof(ConfirmEmailAddresses_Config))] | ||
public async Task WhenAdminHasNoTenant_ReturnsNewOrgWithoutPolicy(bool confirmEmailAddresses) | ||
{ | ||
_service.MockEntitiesContext | ||
.Setup(x => x.Users) | ||
.Returns(Enumerable.Empty<User>().MockDbSet().Object); | ||
|
||
SetUpConfirmEmailAddressesConfig(confirmEmailAddresses); | ||
|
||
var org = await InvokeAddOrganization(admin: new User(AdminName) { Credentials = new Credential[0] }); | ||
|
||
AssertNewOrganizationReturned(org, subscribedToPolicy: false); | ||
AssertNewOrganizationReturned(org, subscribedToPolicy: false, confirmEmailAddresses: confirmEmailAddresses); | ||
} | ||
|
||
[Fact] | ||
public async Task WhenAdminHasUnsupportedTenant_ReturnsNewOrgWithoutPolicy() | ||
[Theory] | ||
[MemberData(nameof(ConfirmEmailAddresses_Config))] | ||
public async Task WhenAdminHasUnsupportedTenant_ReturnsNewOrgWithoutPolicy(bool confirmEmailAddresses) | ||
{ | ||
_service.MockEntitiesContext | ||
.Setup(x => x.Users) | ||
.Returns(Enumerable.Empty<User>().MockDbSet().Object); | ||
|
||
SetUpConfirmEmailAddressesConfig(confirmEmailAddresses); | ||
|
||
var mockLoginDiscontinuationConfiguration = new Mock<ILoginDiscontinuationConfiguration>(); | ||
mockLoginDiscontinuationConfiguration | ||
.Setup(x => x.IsTenantIdPolicySupportedForOrganization(It.IsAny<string>(), It.IsAny<string>())) | ||
|
@@ -1850,16 +1901,19 @@ public async Task WhenAdminHasUnsupportedTenant_ReturnsNewOrgWithoutPolicy() | |
|
||
var org = await InvokeAddOrganization(); | ||
|
||
AssertNewOrganizationReturned(org, subscribedToPolicy: false); | ||
AssertNewOrganizationReturned(org, subscribedToPolicy: false, confirmEmailAddresses: confirmEmailAddresses); | ||
} | ||
|
||
[Fact] | ||
public async Task WhenSubscribingToPolicyFails_ReturnsNewOrgWithoutPolicy() | ||
[Theory] | ||
[MemberData(nameof(ConfirmEmailAddresses_Config))] | ||
public async Task WhenSubscribingToPolicyFails_ReturnsNewOrgWithoutPolicy(bool confirmEmailAddresses) | ||
{ | ||
_service.MockEntitiesContext | ||
.Setup(x => x.Users) | ||
.Returns(Enumerable.Empty<User>().MockDbSet().Object); | ||
|
||
SetUpConfirmEmailAddressesConfig(confirmEmailAddresses); | ||
|
||
var mockLoginDiscontinuationConfiguration = new Mock<ILoginDiscontinuationConfiguration>(); | ||
mockLoginDiscontinuationConfiguration | ||
.Setup(x => x.IsTenantIdPolicySupportedForOrganization(It.IsAny<string>(), It.IsAny<string>())) | ||
|
@@ -1875,16 +1929,19 @@ public async Task WhenSubscribingToPolicyFails_ReturnsNewOrgWithoutPolicy() | |
|
||
var org = await InvokeAddOrganization(); | ||
|
||
AssertNewOrganizationReturned(org, subscribedToPolicy: true); | ||
AssertNewOrganizationReturned(org, subscribedToPolicy: true, confirmEmailAddresses: confirmEmailAddresses); | ||
} | ||
|
||
[Fact] | ||
public async Task WhenSubscribingToPolicySucceeds_ReturnsNewOrg() | ||
[Theory] | ||
[MemberData(nameof(ConfirmEmailAddresses_Config))] | ||
public async Task WhenSubscribingToPolicySucceeds_ReturnsNewOrg(bool confirmEmailAddresses) | ||
{ | ||
_service.MockEntitiesContext | ||
.Setup(x => x.Users) | ||
.Returns(Enumerable.Empty<User>().MockDbSet().Object); | ||
|
||
SetUpConfirmEmailAddressesConfig(confirmEmailAddresses); | ||
|
||
var mockLoginDiscontinuationConfiguration = new Mock<ILoginDiscontinuationConfiguration>(); | ||
mockLoginDiscontinuationConfiguration | ||
.Setup(x => x.IsTenantIdPolicySupportedForOrganization(It.IsAny<string>(), It.IsAny<string>())) | ||
|
@@ -1900,7 +1957,7 @@ public async Task WhenSubscribingToPolicySucceeds_ReturnsNewOrg() | |
|
||
var org = await InvokeAddOrganization(); | ||
|
||
AssertNewOrganizationReturned(org, subscribedToPolicy: true); | ||
AssertNewOrganizationReturned(org, subscribedToPolicy: true, confirmEmailAddresses: confirmEmailAddresses); | ||
} | ||
|
||
private Task<Organization> InvokeAddOrganization(string orgName = OrgName, string orgEmail = OrgEmail, User admin = null) | ||
|
@@ -1925,14 +1982,26 @@ private Task<Organization> InvokeAddOrganization(string orgName = OrgName, strin | |
return _service.AddOrganizationAsync(orgName, orgEmail, admin); | ||
} | ||
|
||
private void AssertNewOrganizationReturned(Organization org, bool subscribedToPolicy) | ||
private void AssertNewOrganizationReturned(Organization org, bool subscribedToPolicy, bool confirmEmailAddresses) | ||
{ | ||
Assert.Equal(OrgName, org.Username); | ||
Assert.Equal(OrgEmail, org.UnconfirmedEmailAddress); | ||
|
||
if (confirmEmailAddresses) | ||
{ | ||
Assert.Null(org.EmailAddress); | ||
Assert.Equal(OrgEmail, org.UnconfirmedEmailAddress); | ||
Assert.NotNull(org.EmailConfirmationToken); | ||
} | ||
else | ||
{ | ||
Assert.Null(org.UnconfirmedEmailAddress); | ||
Assert.Equal(OrgEmail, org.EmailAddress); | ||
Assert.Null(org.EmailConfirmationToken); | ||
} | ||
|
||
Assert.Equal(OrgCreatedUtc, org.CreatedUtc); | ||
Assert.True(org.EmailAllowed); | ||
Assert.True(org.NotifyPackagePushed); | ||
Assert.True(!string.IsNullOrEmpty(org.EmailConfirmationToken)); | ||
|
||
// Both the organization and the admin must have a membership to each other. | ||
Func<Membership, bool> hasMembership = m => m.Member.Username == AdminName && m.Organization.Username == OrgName && m.IsAdmin; | ||
|
@@ -1949,6 +2018,13 @@ private void AssertNewOrganizationReturned(Organization org, bool subscribedToPo | |
ar.AffectedMemberIsAdmin == true)); | ||
_service.MockEntitiesContext.Verify(x => x.SaveChangesAsync(), Times.Once()); | ||
} | ||
|
||
private void SetUpConfirmEmailAddressesConfig(bool confirmEmailAddresses) | ||
{ | ||
_service.MockConfig | ||
.Setup(x => x.ConfirmEmailAddresses) | ||
.Returns(confirmEmailAddresses); | ||
} | ||
} | ||
public class TheRejectTransformUserToOrganizationRequestMethod | ||
{ | ||
|