Add SignInManager CanSignIn
new hook which can be used to block sign in Fixes https://github.com/aspnet/Identity/issues/129
This commit is contained in:
parent
2c9f43a160
commit
556c15273e
|
|
@ -58,19 +58,19 @@ namespace Microsoft.AspNet.Identity
|
|||
return await ClaimsFactory.CreateAsync(user);
|
||||
}
|
||||
|
||||
//public virtual async Task<bool> CanSignInAsync(TUser user,
|
||||
// CancellationToken cancellationToken = default(CancellationToken))
|
||||
//{
|
||||
// if (Options.SignIn.RequireConfirmedEmail && !(await UserManager.IsEmailConfirmedAsync(user, cancellationToken)))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// if (Options.SignIn.RequireConfirmedPhoneNumber && !(await UserManager.IsPhoneNumberConfirmedAsync(user, cancellationToken)))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
//}
|
||||
public virtual async Task<bool> CanSignInAsync(TUser user,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (Options.SignIn.RequireConfirmedEmail && !(await UserManager.IsEmailConfirmedAsync(user, cancellationToken)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (Options.SignIn.RequireConfirmedPhoneNumber && !(await UserManager.IsPhoneNumberConfirmedAsync(user, cancellationToken)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual async Task SignInAsync(TUser user, bool isPersistent, string authenticationMethod = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
|
|
@ -94,6 +94,19 @@ namespace Microsoft.AspNet.Identity
|
|||
return UserManager.SupportsUserLockout && await UserManager.IsLockedOutAsync(user, token);
|
||||
}
|
||||
|
||||
private async Task<SignInStatus?> PreSignInCheck(TUser user, CancellationToken token)
|
||||
{
|
||||
if (!await CanSignInAsync(user, token))
|
||||
{
|
||||
return SignInStatus.NotAllowed;
|
||||
}
|
||||
if (await IsLockedOut(user, token))
|
||||
{
|
||||
return SignInStatus.LockedOut;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Task ResetLockout(TUser user, CancellationToken token)
|
||||
{
|
||||
if (UserManager.SupportsUserLockout)
|
||||
|
|
@ -129,9 +142,10 @@ namespace Microsoft.AspNet.Identity
|
|||
public virtual async Task<SignInStatus> PasswordSignInAsync(TUser user, string password,
|
||||
bool isPersistent, bool shouldLockout, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (await IsLockedOut(user, cancellationToken))
|
||||
var error = await PreSignInCheck(user, cancellationToken);
|
||||
if (error != null)
|
||||
{
|
||||
return SignInStatus.LockedOut;
|
||||
return error.Value;
|
||||
}
|
||||
if (await UserManager.CheckPasswordAsync(user, password, cancellationToken))
|
||||
{
|
||||
|
|
@ -233,9 +247,10 @@ namespace Microsoft.AspNet.Identity
|
|||
{
|
||||
return SignInStatus.Failure;
|
||||
}
|
||||
if (await IsLockedOut(user, cancellationToken))
|
||||
var error = await PreSignInCheck(user, cancellationToken);
|
||||
if (error != null)
|
||||
{
|
||||
return SignInStatus.LockedOut;
|
||||
return error.Value;
|
||||
}
|
||||
if (await UserManager.VerifyTwoFactorTokenAsync(user, provider, code, cancellationToken))
|
||||
{
|
||||
|
|
@ -283,9 +298,10 @@ namespace Microsoft.AspNet.Identity
|
|||
{
|
||||
return SignInStatus.Failure;
|
||||
}
|
||||
if (await IsLockedOut(user, cancellationToken))
|
||||
var error = await PreSignInCheck(user, cancellationToken);
|
||||
if (error != null)
|
||||
{
|
||||
return SignInStatus.LockedOut;
|
||||
return error.Value;
|
||||
}
|
||||
return await SignInOrTwoFactorAsync(user, isPersistent, cancellationToken, loginProvider);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ namespace Microsoft.AspNet.Identity
|
|||
Success,
|
||||
LockedOut,
|
||||
RequiresVerification,
|
||||
NotAllowed,
|
||||
Failure
|
||||
}
|
||||
}
|
||||
|
|
@ -501,6 +501,8 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
// Assert
|
||||
context.VerifyAll();
|
||||
response.VerifyAll();
|
||||
contextAccessor.VerifyAll();
|
||||
claimsFactory.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -528,6 +530,8 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
// Assert
|
||||
Assert.Equal(SignInStatus.Failure, result);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
contextAccessor.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -552,6 +556,8 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
// Assert
|
||||
Assert.Equal(SignInStatus.Failure, result);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
contextAccessor.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -588,5 +594,86 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
manager.VerifyAll();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task CanRequireConfirmedEmailForPasswordSignIn(bool confirmed)
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = MockHelpers.MockUserManager<TestUser>();
|
||||
manager.Setup(m => m.IsEmailConfirmedAsync(user, CancellationToken.None)).ReturnsAsync(confirmed).Verifiable();
|
||||
if (confirmed)
|
||||
{
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "password", CancellationToken.None)).ReturnsAsync(true).Verifiable();
|
||||
}
|
||||
var context = new Mock<HttpContext>();
|
||||
var response = new Mock<HttpResponse>();
|
||||
if (confirmed)
|
||||
{
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "password", CancellationToken.None)).ReturnsAsync(true).Verifiable();
|
||||
context.Setup(c => c.Response).Returns(response.Object).Verifiable();
|
||||
response.Setup(r => r.SignIn(It.Is<AuthenticationProperties>(v => v.IsPersistent == false), It.IsAny<ClaimsIdentity>())).Verifiable();
|
||||
}
|
||||
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
|
||||
contextAccessor.Setup(a => a.Value).Returns(context.Object);
|
||||
var roleManager = MockHelpers.MockRoleManager<TestRole>();
|
||||
var identityOptions = new IdentityOptions();
|
||||
identityOptions.SignIn.RequireConfirmedEmail = true;
|
||||
var options = new Mock<IOptions<IdentityOptions>>();
|
||||
options.Setup(a => a.Options).Returns(identityOptions);
|
||||
var claimsFactory = new Mock<ClaimsIdentityFactory<TestUser, TestRole>>(manager.Object, roleManager.Object, options.Object);
|
||||
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
|
||||
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync(user, "password", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(confirmed ? SignInStatus.Success : SignInStatus.NotAllowed, result);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
response.VerifyAll();
|
||||
contextAccessor.VerifyAll();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task CanRequireConfirmedPhoneNumberForPasswordSignIn(bool confirmed)
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = MockHelpers.MockUserManager<TestUser>();
|
||||
manager.Setup(m => m.IsEmailConfirmedAsync(user, CancellationToken.None)).ReturnsAsync(confirmed).Verifiable();
|
||||
var context = new Mock<HttpContext>();
|
||||
var response = new Mock<HttpResponse>();
|
||||
if (confirmed)
|
||||
{
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "password", CancellationToken.None)).ReturnsAsync(true).Verifiable();
|
||||
context.Setup(c => c.Response).Returns(response.Object).Verifiable();
|
||||
response.Setup(r => r.SignIn(It.Is<AuthenticationProperties>(v => v.IsPersistent == false), It.IsAny<ClaimsIdentity>())).Verifiable();
|
||||
}
|
||||
|
||||
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
|
||||
contextAccessor.Setup(a => a.Value).Returns(context.Object);
|
||||
var roleManager = MockHelpers.MockRoleManager<TestRole>();
|
||||
var identityOptions = new IdentityOptions();
|
||||
identityOptions.SignIn.RequireConfirmedEmail = true;
|
||||
var options = new Mock<IOptions<IdentityOptions>>();
|
||||
options.Setup(a => a.Options).Returns(identityOptions);
|
||||
var claimsFactory = new Mock<ClaimsIdentityFactory<TestUser, TestRole>>(manager.Object, roleManager.Object, options.Object);
|
||||
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
|
||||
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync(user, "password", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(confirmed ? SignInStatus.Success : SignInStatus.NotAllowed, result);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
response.VerifyAll();
|
||||
contextAccessor.VerifyAll();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue