Skip to content

Commit

Permalink
Merge pull request NuGet#355 from NuGet/email
Browse files Browse the repository at this point in the history
Fixed NuGet#315 for realz, actually allowing log on with email.
  • Loading branch information
jeffhandley committed Dec 9, 2011
2 parents 3b9baab + e572e1f commit 909caa6
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 25 deletions.
43 changes: 32 additions & 11 deletions Facts/Controllers/AuthenticationControllerFacts.cs
Expand Up @@ -24,18 +24,39 @@ public void WillShowTheViewWithErrorsIfTheModelStateIsInvalid()
}

[Fact]
public void WillLogTheUserOnWhenTheUsernameAndPasswordAreValidAndUserIsConfirmed()
public void CanLogTheUserOnWithUserName()
{
var formsAuthSvc = new Mock<IFormsAuthenticationService>();
var userSvc = new Mock<IUserService>();
userSvc.Setup(x => x.FindByUsernameAndPassword("theUsername", "thePassword"))
userSvc.Setup(x => x.FindByUsernameOrEmailAddressAndPassword("theUsername", "thePassword"))
.Returns(new User("theUsername", null) { EmailAddress = "confirmed@example.com" });
var controller = CreateController(
formsAuthSvc: formsAuthSvc,
userSvc: userSvc);

controller.LogOn(
new SignInRequest() { UserName = "theUsername", Password = "thePassword" },
new SignInRequest() { UserNameOrEmail = "theUsername", Password = "thePassword" },
"theReturnUrl");

formsAuthSvc.Verify(x => x.SetAuthCookie(
"theUsername",
true,
null));
}

[Fact]
public void CanLogTheUserOnWithEmailAddress()
{
var formsAuthSvc = new Mock<IFormsAuthenticationService>();
var userSvc = new Mock<IUserService>();
userSvc.Setup(x => x.FindByUsernameOrEmailAddressAndPassword("confirmed@example.com", "thePassword"))
.Returns(new User("theUsername", null) { EmailAddress = "confirmed@example.com" });
var controller = CreateController(
formsAuthSvc: formsAuthSvc,
userSvc: userSvc);

controller.LogOn(
new SignInRequest() { UserNameOrEmail = "confirmed@example.com", Password = "thePassword" },
"theReturnUrl");

formsAuthSvc.Verify(x => x.SetAuthCookie(
Expand All @@ -50,14 +71,14 @@ public void WillNotLogTheUserOnWhenTheUsernameAndPasswordAreValidAndUserIsNotCon
var formsAuthSvc = new Mock<IFormsAuthenticationService>();
formsAuthSvc.Setup(x => x.SetAuthCookie(It.IsAny<string>(), It.IsAny<bool>(), null)).Throws(new InvalidOperationException());
var userSvc = new Mock<IUserService>();
userSvc.Setup(x => x.FindByUsernameAndPassword("theUsername", "thePassword"))
userSvc.Setup(x => x.FindByUsernameOrEmailAddressAndPassword("theUsername", "thePassword"))
.Returns(new User("theUsername", null));
var controller = CreateController(
formsAuthSvc: formsAuthSvc,
userSvc: userSvc);

controller.LogOn(
new SignInRequest() { UserName = "theUsername", Password = "thePassword" },
new SignInRequest() { UserNameOrEmail = "theUsername", Password = "thePassword" },
"theReturnUrl");
}

Expand All @@ -66,7 +87,7 @@ public void WillLogTheUserOnWithRolesWhenTheUsernameAndPasswordAreValidAndUserIs
{
var formsAuthSvc = new Mock<IFormsAuthenticationService>();
var userSvc = new Mock<IUserService>();
userSvc.Setup(x => x.FindByUsernameAndPassword("theUsername", "thePassword"))
userSvc.Setup(x => x.FindByUsernameOrEmailAddressAndPassword("theUsername", "thePassword"))
.Returns(new User("theUsername", null)
{
Roles = new[] { new Role { Name = "Administrators" } },
Expand All @@ -77,7 +98,7 @@ public void WillLogTheUserOnWithRolesWhenTheUsernameAndPasswordAreValidAndUserIs
userSvc: userSvc);

controller.LogOn(
new SignInRequest() { UserName = "theUsername", Password = "thePassword" },
new SignInRequest() { UserNameOrEmail = "theUsername", Password = "thePassword" },
"theReturnUrl");

formsAuthSvc.Verify(x => x.SetAuthCookie(
Expand All @@ -90,7 +111,7 @@ public void WillLogTheUserOnWithRolesWhenTheUsernameAndPasswordAreValidAndUserIs
public void WillInvalidateModelStateAndShowTheViewWithErrorsWhenTheUsernameAndPasswordAreNotValid()
{
var userSvc = new Mock<IUserService>();
userSvc.Setup(x => x.FindByUsernameAndPassword(It.IsAny<string>(), It.IsAny<string>()))
userSvc.Setup(x => x.FindByUsernameOrEmailAddressAndPassword(It.IsAny<string>(), It.IsAny<string>()))
.Returns((User)null);
var controller = CreateController(userSvc: userSvc);

Expand All @@ -106,7 +127,7 @@ public void WillInvalidateModelStateAndShowTheViewWithErrorsWhenTheUsernameAndPa
public void WillRedirectToTheReturnUrl()
{
var userSvc = new Mock<IUserService>();
userSvc.Setup(x => x.FindByUsernameAndPassword(It.IsAny<string>(), It.IsAny<string>()))
userSvc.Setup(x => x.FindByUsernameOrEmailAddressAndPassword(It.IsAny<string>(), It.IsAny<string>()))
.Returns(new User("theUsername", null) { EmailAddress = "confirmed@example.com" });
var controller = CreateController(
userSvc: userSvc,
Expand Down Expand Up @@ -140,7 +161,7 @@ public void WillLogTheUserOff()
public void WillRedirectToTheReturnUrl()
{
var userSvc = new Mock<IUserService>();
userSvc.Setup(x => x.FindByUsernameAndPassword(It.IsAny<string>(), It.IsAny<string>()))
userSvc.Setup(x => x.FindByUsernameOrEmailAddressAndPassword(It.IsAny<string>(), It.IsAny<string>()))
.Returns(new User("theUsername", null));
var controller = CreateController(
userSvc: userSvc,
Expand Down Expand Up @@ -182,4 +203,4 @@ public void WillRedirectToTheReturnUrl()
return controller.Object;
}
}
}
}
41 changes: 39 additions & 2 deletions Facts/Services/UsersServiceFacts.cs
Expand Up @@ -46,7 +46,7 @@ public void WillThrowIfTheEmailAddressIsAlreadyInUse()
}

[Fact]
public void WillHasThePassword()
public void WillHashThePassword()
{
var cryptoSvc = new Mock<ICryptographyService>();
cryptoSvc
Expand Down Expand Up @@ -550,6 +550,43 @@ public void ThrowsArgumentExceptionForNullUser()
}
}

public class TheFindByUsernameOrEmailAndPasswordMethod
{
[Fact]
public void FindsUsersByUserName()
{
var user = new User { Username = "theUsername", HashedPassword = "thePassword", EmailAddress = "test@example.com" };
var userRepository = new Mock<IEntityRepository<User>>();
userRepository.Setup(r => r.GetAll()).Returns(new[] { user }.AsQueryable());

var crypto = new Mock<ICryptographyService>();
crypto.Setup(c => c.ValidateSaltedHash(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns(true);

var service = CreateUsersService(cryptoSvc: crypto, userRepo: userRepository);

var foundByUserName = service.FindByUsernameOrEmailAddressAndPassword("theUsername", "thePassword");
Assert.NotNull(foundByUserName);
Assert.Same(user, foundByUserName);
}

[Fact]
public void FindsUsersByEmailAddress()
{
var user = new User { Username = "theUsername", HashedPassword = "thePassword", EmailAddress = "test@example.com" };
var userRepository = new Mock<IEntityRepository<User>>();
userRepository.Setup(r => r.GetAll()).Returns(new[] { user }.AsQueryable());

var crypto = new Mock<ICryptographyService>();
crypto.Setup(c => c.ValidateSaltedHash(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns(true);

var service = CreateUsersService(cryptoSvc: crypto, userRepo: userRepository);

var foundByEmailAddress = service.FindByUsernameOrEmailAddressAndPassword("test@example.com", "thePassword");
Assert.NotNull(foundByEmailAddress);
Assert.Same(user, foundByEmailAddress);
}
}

static UserService CreateUsersService(
GallerySetting settings = null,
Mock<ICryptographyService> cryptoSvc = null,
Expand All @@ -576,4 +613,4 @@ public void ThrowsArgumentExceptionForNullUser()
return userSvc.Object;
}
}
}
}
4 changes: 2 additions & 2 deletions Website/Controllers/AuthenticationController.cs
Expand Up @@ -33,8 +33,8 @@ public virtual ActionResult LogOn(SignInRequest request, string returnUrl)
if (!ModelState.IsValid)
return View();

var user = userSvc.FindByUsernameAndPassword(
request.UserName,
var user = userSvc.FindByUsernameOrEmailAddressAndPassword(
request.UserNameOrEmail,
request.Password);

if (user == null)
Expand Down
6 changes: 3 additions & 3 deletions Website/RequestModels/SignInRequest.cs
Expand Up @@ -5,9 +5,9 @@ namespace NuGetGallery
public class SignInRequest
{
[Required]
[Display(Name = "Username")]
[Hint("Enter your username.")]
public string UserName { get; set; }
[Display(Name = "Username or Email")]
[Hint("Enter your username or email address.")]
public string UserNameOrEmail { get; set; }

[Required]
[DataType(DataType.Password)]
Expand Down
6 changes: 3 additions & 3 deletions Website/Services/IUserService.cs
Expand Up @@ -19,15 +19,15 @@ public interface IUserService

User FindByUsername(string username);

User FindByUsernameAndPassword(
string username,
User FindByUsernameOrEmailAddressAndPassword(
string usernameOrEmail,
string password);

string GenerateApiKey(string username);

bool ConfirmEmailAddress(User user, string token);

bool ChangePassword(string username, string oldPassword, string newPassword);
bool ChangePassword(string usernameOrEmail, string oldPassword, string newPassword);

User GeneratePasswordResetToken(string usernameOrEmail, int tokenExpirationMinutes);

Expand Down
9 changes: 5 additions & 4 deletions Website/Services/UserService.cs
Expand Up @@ -116,13 +116,14 @@ public virtual User FindByUsername(string username)
.SingleOrDefault();
}

public virtual User FindByUsernameAndPassword(
string username,
public virtual User FindByUsernameOrEmailAddressAndPassword(
string usernameOrEmail,
string password)
{
// TODO: validate input

var user = FindByUsername(username);
var user = FindByUsername(usernameOrEmail)
?? FindByEmailAddress(usernameOrEmail);

if (user == null)
return null;
Expand All @@ -149,7 +150,7 @@ public string GenerateApiKey(string username)

public bool ChangePassword(string username, string oldPassword, string newPassword)
{
var user = FindByUsernameAndPassword(username, oldPassword);
var user = FindByUsernameOrEmailAddressAndPassword(username, oldPassword);
if (user == null)
{
return false;
Expand Down

0 comments on commit 909caa6

Please sign in to comment.