Add Email and Phone TOTP providers
Now that HMACSHA1 is available on K
This commit is contained in:
parent
661464004b
commit
076ea0385f
|
|
@ -0,0 +1,80 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// TokenProvider that generates tokens from the user's security stamp and notifies a user via their email
|
||||
/// </summary>
|
||||
/// <typeparam name="TUser"></typeparam>
|
||||
public class EmailTokenProvider<TUser> : TotpSecurityStampBasedTokenProvider<TUser>
|
||||
where TUser : class
|
||||
{
|
||||
private string _body;
|
||||
private string _subject;
|
||||
|
||||
/// <summary>
|
||||
/// Email subject used when a token notification is received
|
||||
/// </summary>
|
||||
public string Subject
|
||||
{
|
||||
get { return _subject ?? string.Empty; }
|
||||
set { _subject = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Format string which will be used for the email body, it will be passed the token for the first parameter
|
||||
/// </summary>
|
||||
public string BodyFormat
|
||||
{
|
||||
get { return _body ?? "{0}"; }
|
||||
set { _body = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if the user has an email set
|
||||
/// </summary>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<bool> IsValidProviderForUserAsync(UserManager<TUser> manager, TUser user,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var email = await manager.GetEmailAsync(user, cancellationToken);
|
||||
return !String.IsNullOrWhiteSpace(email) && await manager.IsEmailConfirmedAsync(user, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the email of the user for entropy in the token
|
||||
/// </summary>
|
||||
/// <param name="purpose"></param>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<string> GetUserModifierAsync(string purpose, UserManager<TUser> manager,
|
||||
TUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var email = await manager.GetEmailAsync(user, cancellationToken);
|
||||
return "Email:" + purpose + ":" + email;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notifies the user with a token via email using the Subject and BodyFormat
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public override Task NotifyAsync(string token, UserManager<TUser> manager, TUser user,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
throw new ArgumentNullException("manager");
|
||||
}
|
||||
return manager.SendEmailAsync(user, Subject, String.Format(CultureInfo.CurrentCulture, BodyFormat, token), cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
<Compile Include="ClaimsIdentityOptions.cs" />
|
||||
<Compile Include="Crypto.cs" />
|
||||
<Compile Include="DefaultAuthenticationTypes.cs" />
|
||||
<Compile Include="PhoneNumberTokenProvider.cs" />
|
||||
<Compile Include="IAuthenticationManager.cs" />
|
||||
<Compile Include="IClaimsIdentityFactory.cs" />
|
||||
<Compile Include="IdentityBuilder.cs" />
|
||||
|
|
@ -57,6 +58,8 @@
|
|||
<Compile Include="IUserRoleStore.cs" />
|
||||
<Compile Include="IUserSecurityStampStore.cs" />
|
||||
<Compile Include="IUserStore.cs" />
|
||||
<Compile Include="EmailTokenProvider.cs" />
|
||||
<Compile Include="TotpSecurityStampBasedTokenProvider.cs" />
|
||||
<Compile Include="IUserTokenProvider.cs" />
|
||||
<Compile Include="IUserTwoFactorStore.cs" />
|
||||
<Compile Include="IUserValidator.cs" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// TokenProvider that generates tokens from the user's security stamp and notifies a user via their phone number
|
||||
/// </summary>
|
||||
/// <typeparam name="TUser"></typeparam>
|
||||
public class PhoneNumberTokenProvider<TUser> : TotpSecurityStampBasedTokenProvider<TUser>
|
||||
where TUser : class
|
||||
{
|
||||
private string _body;
|
||||
|
||||
/// <summary>
|
||||
/// Message contents which should contain a format string which the token will be the only argument
|
||||
/// </summary>
|
||||
public string MessageFormat
|
||||
{
|
||||
get { return _body ?? "{0}"; }
|
||||
set { _body = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the user has a phone number set
|
||||
/// </summary>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<bool> IsValidProviderForUserAsync(UserManager<TUser> manager, TUser user,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
throw new ArgumentNullException("manager");
|
||||
}
|
||||
var phoneNumber = await manager.GetPhoneNumberAsync(user, cancellationToken);
|
||||
return !String.IsNullOrWhiteSpace(phoneNumber) && await manager.IsPhoneNumberConfirmedAsync(user, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the phone number of the user for entropy in the token
|
||||
/// </summary>
|
||||
/// <param name="purpose"></param>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<string> GetUserModifierAsync(string purpose, UserManager<TUser> manager,
|
||||
TUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
throw new ArgumentNullException("manager");
|
||||
}
|
||||
var phoneNumber = await manager.GetPhoneNumberAsync(user, cancellationToken);
|
||||
return "PhoneNumber:" + purpose + ":" + phoneNumber;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notifies the user with a token via SMS using the MessageFormat
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public override Task NotifyAsync(string token, UserManager<TUser> manager, TUser user,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
throw new ArgumentNullException("manager");
|
||||
}
|
||||
return manager.SendSmsAsync(user, String.Format(CultureInfo.CurrentCulture, MessageFormat, token), cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#if NET45
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
|
|
@ -17,7 +15,7 @@ namespace Microsoft.AspNet.Identity
|
|||
|
||||
public SecurityToken(byte[] data)
|
||||
{
|
||||
_data = (byte[]) data.Clone();
|
||||
_data = (byte[])data.Clone();
|
||||
}
|
||||
|
||||
internal byte[] GetDataNoClone()
|
||||
|
|
@ -39,10 +37,10 @@ namespace Microsoft.AspNet.Identity
|
|||
|
||||
// See https://tools.ietf.org/html/rfc4226
|
||||
// We can add an optional modifier
|
||||
var timestepAsBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((long) timestepNumber));
|
||||
var timestepAsBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((long)timestepNumber));
|
||||
var hash = hashAlgorithm.ComputeHash(ApplyModifier(timestepAsBytes, modifier));
|
||||
|
||||
// GenerateAsync DT string
|
||||
// Generate DT string
|
||||
var offset = hash[hash.Length - 1] & 0xf;
|
||||
Debug.Assert(offset + 4 < hash.Length);
|
||||
var binaryCode = (hash[offset] & 0x7f) << 24
|
||||
|
|
@ -50,7 +48,7 @@ namespace Microsoft.AspNet.Identity
|
|||
| (hash[offset + 2] & 0xff) << 8
|
||||
| (hash[offset + 3] & 0xff);
|
||||
|
||||
return binaryCode%mod;
|
||||
return binaryCode % mod;
|
||||
}
|
||||
|
||||
private static byte[] ApplyModifier(byte[] input, string modifier)
|
||||
|
|
@ -71,7 +69,7 @@ namespace Microsoft.AspNet.Identity
|
|||
private static ulong GetCurrentTimeStepNumber()
|
||||
{
|
||||
var delta = DateTime.UtcNow - _unixEpoch;
|
||||
return (ulong) (delta.Ticks/_timestep.Ticks);
|
||||
return (ulong)(delta.Ticks / _timestep.Ticks);
|
||||
}
|
||||
|
||||
public static int GenerateCode(SecurityToken securityToken, string modifier = null)
|
||||
|
|
@ -102,7 +100,7 @@ namespace Microsoft.AspNet.Identity
|
|||
{
|
||||
for (var i = -2; i <= 2; i++)
|
||||
{
|
||||
var computedTotp = ComputeTotp(hashAlgorithm, (ulong) ((long) currentTimeStep + i), modifier);
|
||||
var computedTotp = ComputeTotp(hashAlgorithm, (ulong)((long)currentTimeStep + i), modifier);
|
||||
if (computedTotp == code)
|
||||
{
|
||||
return true;
|
||||
|
|
@ -115,4 +113,3 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// TokenProvider that generates time based codes using the user's security stamp
|
||||
/// </summary>
|
||||
/// <typeparam name="TUser"></typeparam>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
public class TotpSecurityStampBasedTokenProvider<TUser> : IUserTokenProvider<TUser>
|
||||
where TUser : class
|
||||
{
|
||||
/// <summary>
|
||||
/// This token provider does not notify the user by default
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task NotifyAsync(string token, UserManager<TUser> manager, TUser user,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the provider can generate tokens for the user, by default this is equal to
|
||||
/// manager.SupportsUserSecurityStamp
|
||||
/// </summary>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task<bool> IsValidProviderForUserAsync(UserManager<TUser> manager, TUser user,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
throw new ArgumentNullException("manager");
|
||||
}
|
||||
return Task.FromResult(manager.SupportsUserSecurityStamp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a token for the user using their security stamp
|
||||
/// </summary>
|
||||
/// <param name="purpose"></param>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task<string> GenerateAsync(string purpose, UserManager<TUser> manager, TUser user,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
throw new ArgumentNullException("manager");
|
||||
}
|
||||
var token = await manager.CreateSecurityTokenAsync(user);
|
||||
var modifier = await GetUserModifierAsync(purpose, manager, user);
|
||||
return Rfc6238AuthenticationService.GenerateCode(token, modifier).ToString("D6", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the token for the user
|
||||
/// </summary>
|
||||
/// <param name="purpose"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task<bool> ValidateAsync(string purpose, string token, UserManager<TUser> manager,
|
||||
TUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
throw new ArgumentNullException("manager");
|
||||
}
|
||||
int code;
|
||||
if (!Int32.TryParse(token, out code))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var securityToken = await manager.CreateSecurityTokenAsync(user);
|
||||
var modifier = await GetUserModifierAsync(purpose, manager, user);
|
||||
return securityToken != null && Rfc6238AuthenticationService.ValidateCode(securityToken, code, modifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used for entropy in the token, uses the user.Id by default
|
||||
/// </summary>
|
||||
/// <param name="purpose"></param>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task<string> GetUserModifierAsync(string purpose, UserManager<TUser> manager, TUser user,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
throw new ArgumentNullException("manager");
|
||||
}
|
||||
string userId = await manager.GetUserIdAsync(user);
|
||||
return "Totp:" + purpose + ":" + userId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1291,8 +1291,7 @@ namespace Microsoft.AspNet.Identity
|
|||
|
||||
// Two factor APIS
|
||||
|
||||
#if NET45
|
||||
internal async Task<SecurityToken> CreateSecurityToken(TUser user)
|
||||
internal async Task<SecurityToken> CreateSecurityTokenAsync(TUser user)
|
||||
{
|
||||
return
|
||||
new SecurityToken(Encoding.Unicode.GetBytes(await GetSecurityStampAsync(user)));
|
||||
|
|
@ -1308,10 +1307,9 @@ namespace Microsoft.AspNet.Identity
|
|||
{
|
||||
ThrowIfDisposed();
|
||||
return
|
||||
Rfc6238AuthenticationService.GenerateCode(await CreateSecurityToken(user), phoneNumber)
|
||||
Rfc6238AuthenticationService.GenerateCode(await CreateSecurityTokenAsync(user), phoneNumber)
|
||||
.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Verify a phone number code for a specific user and phone number
|
||||
|
|
@ -1323,14 +1321,12 @@ namespace Microsoft.AspNet.Identity
|
|||
public virtual async Task<bool> VerifyChangePhoneNumberTokenAsync(TUser user, string token, string phoneNumber)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
#if NET45
|
||||
var securityToken = await CreateSecurityToken(user);
|
||||
var securityToken = await CreateSecurityTokenAsync(user);
|
||||
int code;
|
||||
if (securityToken != null && Int32.TryParse(token, out code))
|
||||
{
|
||||
return Rfc6238AuthenticationService.ValidateCode(securityToken, code, phoneNumber);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
"System.Linq": "4.0.0.0",
|
||||
"System.Linq.Expressions": "4.0.0.0",
|
||||
"System.Linq.Queryable": "4.0.0.0",
|
||||
"System.Net.Primitives": "4.0.10.0",
|
||||
"System.Reflection": "4.0.10.0",
|
||||
"System.Reflection.Extensions": "4.0.0.0",
|
||||
"System.Resources.ResourceManager": "4.0.0.0",
|
||||
|
|
@ -25,7 +26,10 @@
|
|||
"System.Runtime.Extensions": "4.0.10.0",
|
||||
"System.Security.Principal": "4.0.0.0",
|
||||
"System.Security.Cryptography.DeriveBytes": "4.0.0.0",
|
||||
"System.Security.Cryptography.Hashing": "4.0.0.0",
|
||||
"System.Security.Cryptography.Hashing.Algorithms": "4.0.0.0",
|
||||
"System.Text.Encoding": "4.0.20.0",
|
||||
"System.Text.Encoding.Extensions": "4.0.10.0",
|
||||
"System.Threading.Tasks": "4.0.10.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1011,10 +1011,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
|
|||
var role = new ApplicationRole();
|
||||
Assert.Null(await manager.FindByIdAsync(role.Id.ToString()));
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
|
||||
//Assert.Equal(role, await manager.FindByIdAsync(role.Id.ToString()));
|
||||
var fetch = await manager.FindByIdAsync(role.Id.ToString());
|
||||
Assert.Equal(role.Id, fetch.Id);
|
||||
Assert.Equal(role.Name, fetch.Name);
|
||||
Assert.Equal(role, await manager.FindByIdAsync(role.Id.ToString()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1025,10 +1022,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
|
|||
Assert.Null(await manager.FindByNameAsync(role.Name));
|
||||
Assert.False(await manager.RoleExistsAsync(role.Name));
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
|
||||
var fetch = await manager.FindByNameAsync(role.Name);
|
||||
//Assert.Equal(role, fetch);
|
||||
Assert.Equal(role.Id, fetch.Id);
|
||||
Assert.Equal(role.Name, fetch.Name);
|
||||
Assert.Equal(role, await manager.FindByNameAsync(role.Name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1299,7 +1293,6 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
|
|||
Assert.NotEqual(stamp, user.SecurityStamp);
|
||||
}
|
||||
|
||||
#if NET45
|
||||
[Fact]
|
||||
public async Task CanChangePhoneNumber()
|
||||
{
|
||||
|
|
@ -1346,65 +1339,6 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
|
|||
Assert.False(await manager.VerifyChangePhoneNumberTokenAsync(user, token2, num1));
|
||||
Assert.False(await manager.VerifyChangePhoneNumberTokenAsync(user, token1, num2));
|
||||
}
|
||||
#endif
|
||||
|
||||
private class EmailTokenProvider : IUserTokenProvider<ApplicationUser>
|
||||
{
|
||||
public Task<string> GenerateAsync(string purpose, UserManager<ApplicationUser> manager, ApplicationUser user, CancellationToken token)
|
||||
{
|
||||
return Task.FromResult(MakeToken(purpose));
|
||||
}
|
||||
|
||||
public Task<bool> ValidateAsync(string purpose, string token, UserManager<ApplicationUser> manager,
|
||||
ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(token == MakeToken(purpose));
|
||||
}
|
||||
|
||||
public Task NotifyAsync(string token, UserManager<ApplicationUser> manager, ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
return manager.SendEmailAsync(user, token, token);
|
||||
}
|
||||
|
||||
public async Task<bool> IsValidProviderForUserAsync(UserManager<ApplicationUser> manager, ApplicationUser user, CancellationToken token)
|
||||
{
|
||||
return !string.IsNullOrEmpty(await manager.GetEmailAsync(user));
|
||||
}
|
||||
|
||||
private static string MakeToken(string purpose)
|
||||
{
|
||||
return "email:" + purpose;
|
||||
}
|
||||
}
|
||||
|
||||
private class SmsTokenProvider : IUserTokenProvider<ApplicationUser>
|
||||
{
|
||||
public Task<string> GenerateAsync(string purpose, UserManager<ApplicationUser> manager, ApplicationUser user, CancellationToken token)
|
||||
{
|
||||
return Task.FromResult(MakeToken(purpose));
|
||||
}
|
||||
|
||||
public Task<bool> ValidateAsync(string purpose, string token, UserManager<ApplicationUser> manager,
|
||||
ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(token == MakeToken(purpose));
|
||||
}
|
||||
|
||||
public Task NotifyAsync(string token, UserManager<ApplicationUser> manager, ApplicationUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
return manager.SendSmsAsync(user, token);
|
||||
}
|
||||
|
||||
public async Task<bool> IsValidProviderForUserAsync(UserManager<ApplicationUser> manager, ApplicationUser user, CancellationToken token)
|
||||
{
|
||||
return !string.IsNullOrEmpty(await manager.GetPhoneNumberAsync(user));
|
||||
}
|
||||
|
||||
private static string MakeToken(string purpose)
|
||||
{
|
||||
return "sms:" + purpose;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanEmailTwoFactorToken()
|
||||
|
|
@ -1413,8 +1347,10 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
|
|||
var messageService = new TestMessageService();
|
||||
manager.EmailService = messageService;
|
||||
const string factorId = "EmailCode";
|
||||
manager.RegisterTwoFactorProvider(factorId, new EmailTokenProvider());
|
||||
var subject = "Subject";
|
||||
manager.RegisterTwoFactorProvider(factorId, new EmailTokenProvider<ApplicationUser> { Subject = subject });
|
||||
var user = new ApplicationUser { Email = "foo@foo.com" };
|
||||
user.EmailConfirmed = true;
|
||||
const string password = "password";
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password));
|
||||
var stamp = user.SecurityStamp;
|
||||
|
|
@ -1422,9 +1358,10 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
|
|||
var token = await manager.GenerateTwoFactorTokenAsync(user, factorId);
|
||||
Assert.NotNull(token);
|
||||
Assert.Null(messageService.Message);
|
||||
Assert.True(await manager.IsEmailConfirmedAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await manager.NotifyTwoFactorTokenAsync(user, factorId, token));
|
||||
Assert.NotNull(messageService.Message);
|
||||
Assert.Equal(token, messageService.Message.Subject);
|
||||
Assert.Equal(subject, messageService.Message.Subject);
|
||||
Assert.Equal(token, messageService.Message.Body);
|
||||
Assert.True(await manager.VerifyTwoFactorTokenAsync(user, factorId, token));
|
||||
}
|
||||
|
|
@ -1441,49 +1378,48 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
|
|||
"No IUserTwoFactorProvider for 'Bogus' is registered.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EmailTokenFactorWithFormatTest()
|
||||
{
|
||||
var manager = CreateManager();
|
||||
var messageService = new TestMessageService();
|
||||
manager.EmailService = messageService;
|
||||
const string factorId = "EmailCode";
|
||||
manager.RegisterTwoFactorProvider(factorId, new EmailTokenProvider<ApplicationUser>
|
||||
{
|
||||
Subject = "Security Code",
|
||||
BodyFormat = "Your code is: {0}"
|
||||
});
|
||||
var user = new ApplicationUser { Email = "foo@foo.com" };
|
||||
const string password = "password";
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password));
|
||||
var stamp = user.SecurityStamp;
|
||||
Assert.NotNull(stamp);
|
||||
var token = await manager.GenerateTwoFactorTokenAsync(user, factorId);
|
||||
Assert.NotNull(token);
|
||||
Assert.Null(messageService.Message);
|
||||
IdentityResultAssert.IsSuccess(await manager.NotifyTwoFactorTokenAsync(user, factorId, token));
|
||||
Assert.NotNull(messageService.Message);
|
||||
Assert.Equal("Security Code", messageService.Message.Subject);
|
||||
Assert.Equal("Your code is: " + token, messageService.Message.Body);
|
||||
Assert.True(await manager.VerifyTwoFactorTokenAsync(user, factorId, token));
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
//public async Task EmailTokenFactorWithFormatTest()
|
||||
//{
|
||||
// var manager = CreateManager();
|
||||
// var messageService = new TestMessageService();
|
||||
// manager.EmailService = messageService;
|
||||
// const string factorId = "EmailCode";
|
||||
// manager.RegisterTwoFactorProvider(factorId, new EmailTokenProvider<ApplicationUser>
|
||||
// {
|
||||
// Subject = "Security Code",
|
||||
// BodyFormat = "Your code is: {0}"
|
||||
// });
|
||||
// var user = new ApplicationUser("EmailCodeTest") { Email = "foo@foo.com" };
|
||||
// const string password = "password";
|
||||
// IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password));
|
||||
// var stamp = user.SecurityStamp;
|
||||
// Assert.NotNull(stamp);
|
||||
// var token = await manager.GenerateTwoFactorTokenAsync(user, factorId);
|
||||
// Assert.NotNull(token);
|
||||
// Assert.Null(messageService.Message);
|
||||
// IdentityResultAssert.IsSuccess(await manager.NotifyTwoFactorTokenAsync(user, factorId, token));
|
||||
// Assert.NotNull(messageService.Message);
|
||||
// Assert.Equal("Security Code", messageService.Message.Subject);
|
||||
// Assert.Equal("Your code is: " + token, messageService.Message.Body);
|
||||
// Assert.True(await manager.VerifyTwoFactorTokenAsync(user, factorId, token));
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public async Task EmailFactorFailsAfterSecurityStampChangeTest()
|
||||
//{
|
||||
// var manager = CreateManager();
|
||||
// const string factorId = "EmailCode";
|
||||
// manager.RegisterTwoFactorProvider(factorId, new EmailTokenProvider<ApplicationUser>());
|
||||
// var user = new ApplicationUser("EmailCodeTest") { Email = "foo@foo.com" };
|
||||
// IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
// var stamp = user.SecurityStamp;
|
||||
// Assert.NotNull(stamp);
|
||||
// var token = await manager.GenerateTwoFactorTokenAsync(user, factorId);
|
||||
// Assert.NotNull(token);
|
||||
// IdentityResultAssert.IsSuccess(await manager.UpdateSecurityStampAsync(user));
|
||||
// Assert.False(await manager.VerifyTwoFactorTokenAsync(user, factorId, token));
|
||||
//}
|
||||
[Fact]
|
||||
public async Task EmailFactorFailsAfterSecurityStampChangeTest()
|
||||
{
|
||||
var manager = CreateManager();
|
||||
const string factorId = "EmailCode";
|
||||
manager.RegisterTwoFactorProvider(factorId, new EmailTokenProvider<ApplicationUser>());
|
||||
var user = new ApplicationUser { Email = "foo@foo.com" };
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
var stamp = user.SecurityStamp;
|
||||
Assert.NotNull(stamp);
|
||||
var token = await manager.GenerateTwoFactorTokenAsync(user, factorId);
|
||||
Assert.NotNull(token);
|
||||
IdentityResultAssert.IsSuccess(await manager.UpdateSecurityStampAsync(user));
|
||||
Assert.False(await manager.VerifyTwoFactorTokenAsync(user, factorId, token));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EnableTwoFactorChangesSecurityStamp()
|
||||
|
|
@ -1532,7 +1468,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
|
|||
var messageService = new TestMessageService();
|
||||
manager.SmsService = messageService;
|
||||
const string factorId = "PhoneCode";
|
||||
manager.RegisterTwoFactorProvider(factorId, new SmsTokenProvider());
|
||||
manager.RegisterTwoFactorProvider(factorId, new PhoneNumberTokenProvider<ApplicationUser>());
|
||||
var user = new ApplicationUser { PhoneNumber = "4251234567" };
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
var stamp = user.SecurityStamp;
|
||||
|
|
@ -1546,29 +1482,29 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
|
|||
Assert.True(await manager.VerifyTwoFactorTokenAsync(user, factorId, token));
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
//public async Task PhoneTokenFactorFormatTest()
|
||||
//{
|
||||
// var manager = CreateManager();
|
||||
// var messageService = new TestMessageService();
|
||||
// manager.SmsService = messageService;
|
||||
// const string factorId = "PhoneCode";
|
||||
// manager.RegisterTwoFactorProvider(factorId, new PhoneNumberTokenProvider<ApplicationUser>
|
||||
// {
|
||||
// MessageFormat = "Your code is: {0}"
|
||||
// });
|
||||
// var user = new ApplicationUser("PhoneCodeTest") { PhoneNumber = "4251234567" };
|
||||
// IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
// var stamp = user.SecurityStamp;
|
||||
// Assert.NotNull(stamp);
|
||||
// var token = await manager.GenerateTwoFactorTokenAsync(user, factorId);
|
||||
// Assert.NotNull(token);
|
||||
// Assert.Null(messageService.Message);
|
||||
// IdentityResultAssert.IsSuccess(await manager.NotifyTwoFactorTokenAsync(user, factorId, token));
|
||||
// Assert.NotNull(messageService.Message);
|
||||
// Assert.Equal("Your code is: " + token, messageService.Message.Body);
|
||||
// Assert.True(await manager.VerifyTwoFactorTokenAsync(user, factorId, token));
|
||||
//}
|
||||
[Fact]
|
||||
public async Task PhoneTokenFactorFormatTest()
|
||||
{
|
||||
var manager = CreateManager();
|
||||
var messageService = new TestMessageService();
|
||||
manager.SmsService = messageService;
|
||||
const string factorId = "PhoneCode";
|
||||
manager.RegisterTwoFactorProvider(factorId, new PhoneNumberTokenProvider<ApplicationUser>
|
||||
{
|
||||
MessageFormat = "Your code is: {0}"
|
||||
});
|
||||
var user = new ApplicationUser { PhoneNumber = "4251234567" };
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
var stamp = user.SecurityStamp;
|
||||
Assert.NotNull(stamp);
|
||||
var token = await manager.GenerateTwoFactorTokenAsync(user, factorId);
|
||||
Assert.NotNull(token);
|
||||
Assert.Null(messageService.Message);
|
||||
IdentityResultAssert.IsSuccess(await manager.NotifyTwoFactorTokenAsync(user, factorId, token));
|
||||
Assert.NotNull(messageService.Message);
|
||||
Assert.Equal("Your code is: " + token, messageService.Message.Body);
|
||||
Assert.True(await manager.VerifyTwoFactorTokenAsync(user, factorId, token));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GenerateTwoFactorWithUnknownFactorProviderWillThrow()
|
||||
|
|
@ -1599,8 +1535,8 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
|
|||
public async Task CanGetValidTwoFactor()
|
||||
{
|
||||
var manager = CreateManager();
|
||||
manager.RegisterTwoFactorProvider("phone", new SmsTokenProvider());
|
||||
manager.RegisterTwoFactorProvider("email", new EmailTokenProvider());
|
||||
manager.RegisterTwoFactorProvider("phone", new PhoneNumberTokenProvider<ApplicationUser>());
|
||||
manager.RegisterTwoFactorProvider("email", new EmailTokenProvider<ApplicationUser>());
|
||||
var user = new ApplicationUser();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
var factors = await manager.GetValidTwoFactorProvidersAsync(user);
|
||||
|
|
@ -1609,11 +1545,22 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
|
|||
IdentityResultAssert.IsSuccess(await manager.SetPhoneNumberAsync(user, "111-111-1111"));
|
||||
factors = await manager.GetValidTwoFactorProvidersAsync(user);
|
||||
Assert.NotNull(factors);
|
||||
Assert.True(factors.Count() == 0);
|
||||
user.PhoneNumberConfirmed = true;
|
||||
IdentityResultAssert.IsSuccess(await manager.UpdateAsync(user));
|
||||
factors = await manager.GetValidTwoFactorProvidersAsync(user);
|
||||
Assert.NotNull(factors);
|
||||
Assert.True(factors.Count() == 1);
|
||||
Assert.Equal("phone", factors[0]);
|
||||
IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, "test@test.com"));
|
||||
factors = await manager.GetValidTwoFactorProvidersAsync(user);
|
||||
Assert.NotNull(factors);
|
||||
Assert.True(factors.Count() == 1);
|
||||
Assert.Equal("phone", factors[0]);
|
||||
user.EmailConfirmed = true;
|
||||
IdentityResultAssert.IsSuccess(await manager.UpdateAsync(user));
|
||||
factors = await manager.GetValidTwoFactorProvidersAsync(user);
|
||||
Assert.NotNull(factors);
|
||||
Assert.True(factors.Count() == 2);
|
||||
IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, null));
|
||||
factors = await manager.GetValidTwoFactorProvidersAsync(user);
|
||||
|
|
@ -1622,29 +1569,29 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
|
|||
Assert.Equal("phone", factors[0]);
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
//public async Task PhoneFactorFailsAfterSecurityStampChangeTest()
|
||||
//{
|
||||
// var manager = CreateManager();
|
||||
// var factorId = "PhoneCode";
|
||||
// manager.RegisterTwoFactorProvider(factorId, new PhoneNumberTokenProvider<ApplicationUser>());
|
||||
// var user = new ApplicationUser("PhoneCodeTest");
|
||||
// user.PhoneNumber = "4251234567";
|
||||
// IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
// var stamp = user.SecurityStamp;
|
||||
// Assert.NotNull(stamp);
|
||||
// var token = await manager.GenerateTwoFactorTokenAsync(user, factorId);
|
||||
// Assert.NotNull(token);
|
||||
// IdentityResultAssert.IsSuccess(await manager.UpdateSecurityStampAsync(user));
|
||||
// Assert.False(await manager.VerifyTwoFactorTokenAsync(user, factorId, token));
|
||||
//}
|
||||
[Fact]
|
||||
public async Task PhoneFactorFailsAfterSecurityStampChangeTest()
|
||||
{
|
||||
var manager = CreateManager();
|
||||
var factorId = "PhoneCode";
|
||||
manager.RegisterTwoFactorProvider(factorId, new PhoneNumberTokenProvider<ApplicationUser>());
|
||||
var user = new ApplicationUser();
|
||||
user.PhoneNumber = "4251234567";
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
var stamp = user.SecurityStamp;
|
||||
Assert.NotNull(stamp);
|
||||
var token = await manager.GenerateTwoFactorTokenAsync(user, factorId);
|
||||
Assert.NotNull(token);
|
||||
IdentityResultAssert.IsSuccess(await manager.UpdateSecurityStampAsync(user));
|
||||
Assert.False(await manager.VerifyTwoFactorTokenAsync(user, factorId, token));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task VerifyTokenFromWrongTokenProviderFails()
|
||||
{
|
||||
var manager = CreateManager();
|
||||
manager.RegisterTwoFactorProvider("PhoneCode", new SmsTokenProvider());
|
||||
manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider());
|
||||
manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationUser>());
|
||||
manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser>());
|
||||
var user = new ApplicationUser { PhoneNumber = "4251234567" };
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
var token = await manager.GenerateTwoFactorTokenAsync(user, "PhoneCode");
|
||||
|
|
@ -1657,7 +1604,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
|
|||
{
|
||||
var manager = CreateManager();
|
||||
const string factorId = "PhoneCode";
|
||||
manager.RegisterTwoFactorProvider(factorId, new SmsTokenProvider());
|
||||
manager.RegisterTwoFactorProvider(factorId, new PhoneNumberTokenProvider<ApplicationUser>());
|
||||
var user = new ApplicationUser { PhoneNumber = "4251234567" };
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
Assert.False(await manager.VerifyTwoFactorTokenAsync(user, factorId, "bogus"));
|
||||
|
|
|
|||
Loading…
Reference in New Issue