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);
|
return await ClaimsFactory.CreateAsync(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
//public virtual async Task<bool> CanSignInAsync(TUser user,
|
public virtual async Task<bool> CanSignInAsync(TUser user,
|
||||||
// CancellationToken cancellationToken = default(CancellationToken))
|
CancellationToken cancellationToken = default(CancellationToken))
|
||||||
//{
|
{
|
||||||
// if (Options.SignIn.RequireConfirmedEmail && !(await UserManager.IsEmailConfirmedAsync(user, cancellationToken)))
|
if (Options.SignIn.RequireConfirmedEmail && !(await UserManager.IsEmailConfirmedAsync(user, cancellationToken)))
|
||||||
// {
|
{
|
||||||
// return false;
|
return false;
|
||||||
// }
|
}
|
||||||
// if (Options.SignIn.RequireConfirmedPhoneNumber && !(await UserManager.IsPhoneNumberConfirmedAsync(user, cancellationToken)))
|
if (Options.SignIn.RequireConfirmedPhoneNumber && !(await UserManager.IsPhoneNumberConfirmedAsync(user, cancellationToken)))
|
||||||
// {
|
{
|
||||||
// return false;
|
return false;
|
||||||
// }
|
}
|
||||||
// return true;
|
return true;
|
||||||
//}
|
}
|
||||||
|
|
||||||
public virtual async Task SignInAsync(TUser user, bool isPersistent, string authenticationMethod = null,
|
public virtual async Task SignInAsync(TUser user, bool isPersistent, string authenticationMethod = null,
|
||||||
CancellationToken cancellationToken = default(CancellationToken))
|
CancellationToken cancellationToken = default(CancellationToken))
|
||||||
|
|
@ -94,6 +94,19 @@ namespace Microsoft.AspNet.Identity
|
||||||
return UserManager.SupportsUserLockout && await UserManager.IsLockedOutAsync(user, token);
|
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)
|
private Task ResetLockout(TUser user, CancellationToken token)
|
||||||
{
|
{
|
||||||
if (UserManager.SupportsUserLockout)
|
if (UserManager.SupportsUserLockout)
|
||||||
|
|
@ -129,9 +142,10 @@ namespace Microsoft.AspNet.Identity
|
||||||
public virtual async Task<SignInStatus> PasswordSignInAsync(TUser user, string password,
|
public virtual async Task<SignInStatus> PasswordSignInAsync(TUser user, string password,
|
||||||
bool isPersistent, bool shouldLockout, CancellationToken cancellationToken = default(CancellationToken))
|
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))
|
if (await UserManager.CheckPasswordAsync(user, password, cancellationToken))
|
||||||
{
|
{
|
||||||
|
|
@ -233,9 +247,10 @@ namespace Microsoft.AspNet.Identity
|
||||||
{
|
{
|
||||||
return SignInStatus.Failure;
|
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))
|
if (await UserManager.VerifyTwoFactorTokenAsync(user, provider, code, cancellationToken))
|
||||||
{
|
{
|
||||||
|
|
@ -283,9 +298,10 @@ namespace Microsoft.AspNet.Identity
|
||||||
{
|
{
|
||||||
return SignInStatus.Failure;
|
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);
|
return await SignInOrTwoFactorAsync(user, isPersistent, cancellationToken, loginProvider);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ namespace Microsoft.AspNet.Identity
|
||||||
Success,
|
Success,
|
||||||
LockedOut,
|
LockedOut,
|
||||||
RequiresVerification,
|
RequiresVerification,
|
||||||
|
NotAllowed,
|
||||||
Failure
|
Failure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -501,6 +501,8 @@ namespace Microsoft.AspNet.Identity.Test
|
||||||
// Assert
|
// Assert
|
||||||
context.VerifyAll();
|
context.VerifyAll();
|
||||||
response.VerifyAll();
|
response.VerifyAll();
|
||||||
|
contextAccessor.VerifyAll();
|
||||||
|
claimsFactory.VerifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -528,6 +530,8 @@ namespace Microsoft.AspNet.Identity.Test
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(SignInStatus.Failure, result);
|
Assert.Equal(SignInStatus.Failure, result);
|
||||||
manager.VerifyAll();
|
manager.VerifyAll();
|
||||||
|
context.VerifyAll();
|
||||||
|
contextAccessor.VerifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -552,6 +556,8 @@ namespace Microsoft.AspNet.Identity.Test
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(SignInStatus.Failure, result);
|
Assert.Equal(SignInStatus.Failure, result);
|
||||||
manager.VerifyAll();
|
manager.VerifyAll();
|
||||||
|
context.VerifyAll();
|
||||||
|
contextAccessor.VerifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -588,5 +594,86 @@ namespace Microsoft.AspNet.Identity.Test
|
||||||
manager.VerifyAll();
|
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