diff --git a/src/Microsoft.AspNet.Identity/EmailTokenProvider.cs b/src/Microsoft.AspNet.Identity/EmailTokenProvider.cs
new file mode 100644
index 0000000000..eb5219894e
--- /dev/null
+++ b/src/Microsoft.AspNet.Identity/EmailTokenProvider.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Globalization;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Microsoft.AspNet.Identity
+{
+ ///
+ /// TokenProvider that generates tokens from the user's security stamp and notifies a user via their email
+ ///
+ ///
+ public class EmailTokenProvider : TotpSecurityStampBasedTokenProvider
+ where TUser : class
+ {
+ private string _body;
+ private string _subject;
+
+ ///
+ /// Email subject used when a token notification is received
+ ///
+ public string Subject
+ {
+ get { return _subject ?? string.Empty; }
+ set { _subject = value; }
+ }
+
+ ///
+ /// Format string which will be used for the email body, it will be passed the token for the first parameter
+ ///
+ public string BodyFormat
+ {
+ get { return _body ?? "{0}"; }
+ set { _body = value; }
+ }
+
+ ///
+ /// True if the user has an email set
+ ///
+ ///
+ ///
+ ///
+ public override async Task IsValidProviderForUserAsync(UserManager manager, TUser user,
+ CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var email = await manager.GetEmailAsync(user, cancellationToken);
+ return !String.IsNullOrWhiteSpace(email) && await manager.IsEmailConfirmedAsync(user, cancellationToken);
+ }
+
+ ///
+ /// Returns the email of the user for entropy in the token
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override async Task GetUserModifierAsync(string purpose, UserManager manager,
+ TUser user, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var email = await manager.GetEmailAsync(user, cancellationToken);
+ return "Email:" + purpose + ":" + email;
+ }
+
+ ///
+ /// Notifies the user with a token via email using the Subject and BodyFormat
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override Task NotifyAsync(string token, UserManager 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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Identity/Microsoft.AspNet.Identity.kproj b/src/Microsoft.AspNet.Identity/Microsoft.AspNet.Identity.kproj
index d418832fbb..ee7363ba94 100644
--- a/src/Microsoft.AspNet.Identity/Microsoft.AspNet.Identity.kproj
+++ b/src/Microsoft.AspNet.Identity/Microsoft.AspNet.Identity.kproj
@@ -26,6 +26,7 @@
+
@@ -57,6 +58,8 @@
+
+
diff --git a/src/Microsoft.AspNet.Identity/PhoneNumberTokenProvider.cs b/src/Microsoft.AspNet.Identity/PhoneNumberTokenProvider.cs
new file mode 100644
index 0000000000..100c51586d
--- /dev/null
+++ b/src/Microsoft.AspNet.Identity/PhoneNumberTokenProvider.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Globalization;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Microsoft.AspNet.Identity
+{
+ ///
+ /// TokenProvider that generates tokens from the user's security stamp and notifies a user via their phone number
+ ///
+ ///
+ public class PhoneNumberTokenProvider : TotpSecurityStampBasedTokenProvider
+ where TUser : class
+ {
+ private string _body;
+
+ ///
+ /// Message contents which should contain a format string which the token will be the only argument
+ ///
+ public string MessageFormat
+ {
+ get { return _body ?? "{0}"; }
+ set { _body = value; }
+ }
+
+ ///
+ /// Returns true if the user has a phone number set
+ ///
+ ///
+ ///
+ ///
+ public override async Task IsValidProviderForUserAsync(UserManager 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);
+ }
+
+ ///
+ /// Returns the phone number of the user for entropy in the token
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override async Task GetUserModifierAsync(string purpose, UserManager 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;
+ }
+
+ ///
+ /// Notifies the user with a token via SMS using the MessageFormat
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override Task NotifyAsync(string token, UserManager 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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Identity/Rfc6238AuthenticationService.cs b/src/Microsoft.AspNet.Identity/Rfc6238AuthenticationService.cs
index 07a60be7d7..2a491f505a 100644
--- a/src/Microsoft.AspNet.Identity/Rfc6238AuthenticationService.cs
+++ b/src/Microsoft.AspNet.Identity/Rfc6238AuthenticationService.cs
@@ -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
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Identity/TotpSecurityStampBasedTokenProvider.cs b/src/Microsoft.AspNet.Identity/TotpSecurityStampBasedTokenProvider.cs
new file mode 100644
index 0000000000..c032693585
--- /dev/null
+++ b/src/Microsoft.AspNet.Identity/TotpSecurityStampBasedTokenProvider.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Globalization;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Microsoft.AspNet.Identity
+{
+ ///
+ /// TokenProvider that generates time based codes using the user's security stamp
+ ///
+ ///
+ ///
+ public class TotpSecurityStampBasedTokenProvider : IUserTokenProvider
+ where TUser : class
+ {
+ ///
+ /// This token provider does not notify the user by default
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual Task NotifyAsync(string token, UserManager manager, TUser user,
+ CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return Task.FromResult(0);
+ }
+
+ ///
+ /// Returns true if the provider can generate tokens for the user, by default this is equal to
+ /// manager.SupportsUserSecurityStamp
+ ///
+ ///
+ ///
+ ///
+ public virtual Task IsValidProviderForUserAsync(UserManager manager, TUser user,
+ CancellationToken cancellationToken = default(CancellationToken))
+ {
+ if (manager == null)
+ {
+ throw new ArgumentNullException("manager");
+ }
+ return Task.FromResult(manager.SupportsUserSecurityStamp);
+ }
+
+ ///
+ /// Generate a token for the user using their security stamp
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual async Task GenerateAsync(string purpose, UserManager 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);
+ }
+
+ ///
+ /// Validate the token for the user
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual async Task ValidateAsync(string purpose, string token, UserManager 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);
+ }
+
+ ///
+ /// Used for entropy in the token, uses the user.Id by default
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual async Task GetUserModifierAsync(string purpose, UserManager manager, TUser user,
+ CancellationToken cancellationToken = default(CancellationToken))
+ {
+ if (manager == null)
+ {
+ throw new ArgumentNullException("manager");
+ }
+ string userId = await manager.GetUserIdAsync(user);
+ return "Totp:" + purpose + ":" + userId;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Identity/UserManager.cs b/src/Microsoft.AspNet.Identity/UserManager.cs
index 23163f10e7..0176171209 100644
--- a/src/Microsoft.AspNet.Identity/UserManager.cs
+++ b/src/Microsoft.AspNet.Identity/UserManager.cs
@@ -1291,8 +1291,7 @@ namespace Microsoft.AspNet.Identity
// Two factor APIS
-#if NET45
- internal async Task CreateSecurityToken(TUser user)
+ internal async Task 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
///
/// Verify a phone number code for a specific user and phone number
@@ -1323,14 +1321,12 @@ namespace Microsoft.AspNet.Identity
public virtual async Task 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;
}
diff --git a/src/Microsoft.AspNet.Identity/project.json b/src/Microsoft.AspNet.Identity/project.json
index 77ab50fdc2..f9c78d70fc 100644
--- a/src/Microsoft.AspNet.Identity/project.json
+++ b/src/Microsoft.AspNet.Identity/project.json
@@ -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"
}
}
diff --git a/test/Microsoft.AspNet.Identity.EntityFramework.Test/UserStoreTestBase.cs b/test/Microsoft.AspNet.Identity.EntityFramework.Test/UserStoreTestBase.cs
index 173010894a..066dc80bac 100644
--- a/test/Microsoft.AspNet.Identity.EntityFramework.Test/UserStoreTestBase.cs
+++ b/test/Microsoft.AspNet.Identity.EntityFramework.Test/UserStoreTestBase.cs
@@ -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
- {
- public Task GenerateAsync(string purpose, UserManager manager, ApplicationUser user, CancellationToken token)
- {
- return Task.FromResult(MakeToken(purpose));
- }
-
- public Task ValidateAsync(string purpose, string token, UserManager manager,
- ApplicationUser user, CancellationToken cancellationToken)
- {
- return Task.FromResult(token == MakeToken(purpose));
- }
-
- public Task NotifyAsync(string token, UserManager manager, ApplicationUser user, CancellationToken cancellationToken)
- {
- return manager.SendEmailAsync(user, token, token);
- }
-
- public async Task IsValidProviderForUserAsync(UserManager 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
- {
- public Task GenerateAsync(string purpose, UserManager manager, ApplicationUser user, CancellationToken token)
- {
- return Task.FromResult(MakeToken(purpose));
- }
-
- public Task ValidateAsync(string purpose, string token, UserManager manager,
- ApplicationUser user, CancellationToken cancellationToken)
- {
- return Task.FromResult(token == MakeToken(purpose));
- }
-
- public Task NotifyAsync(string token, UserManager manager, ApplicationUser user, CancellationToken cancellationToken)
- {
- return manager.SendSmsAsync(user, token);
- }
-
- public async Task IsValidProviderForUserAsync(UserManager 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 { 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
+ {
+ 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
- // {
- // 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());
- // 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());
+ 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());
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
- // {
- // 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
+ {
+ 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());
+ manager.RegisterTwoFactorProvider("email", new EmailTokenProvider());
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());
- // 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());
+ 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());
+ manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider());
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());
var user = new ApplicationUser { PhoneNumber = "4251234567" };
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
Assert.False(await manager.VerifyTwoFactorTokenAsync(user, factorId, "bogus"));