diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs
index ddedc15c3b..87cf6d2579 100644
--- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs
+++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs
@@ -1247,6 +1247,10 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
{
throw new ArgumentNullException(nameof(user));
}
+ if (stamp == null)
+ {
+ throw new ArgumentNullException(nameof(stamp));
+ }
user.SecurityStamp = stamp;
return TaskCache.CompletedTask;
}
diff --git a/src/Microsoft.AspNetCore.Identity/IdentityErrorDescriber.cs b/src/Microsoft.AspNetCore.Identity/IdentityErrorDescriber.cs
index 54c024c79e..914e82e5ea 100644
--- a/src/Microsoft.AspNetCore.Identity/IdentityErrorDescriber.cs
+++ b/src/Microsoft.AspNetCore.Identity/IdentityErrorDescriber.cs
@@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Identity
///
/// Returns the default .
///
- /// The default ,
+ /// The default .
public virtual IdentityError DefaultError()
{
return new IdentityError
diff --git a/src/Microsoft.AspNetCore.Identity/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Identity/Properties/Resources.Designer.cs
index 0029258790..fa00dea7f6 100644
--- a/src/Microsoft.AspNetCore.Identity/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNetCore.Identity/Properties/Resources.Designer.cs
@@ -250,6 +250,22 @@ namespace Microsoft.AspNetCore.Identity
return string.Format(CultureInfo.CurrentCulture, GetString("NoTokenProvider"), p0);
}
+ ///
+ /// User security stamp cannot be null.
+ ///
+ internal static string NullSecurityStamp
+ {
+ get { return GetString("NullSecurityStamp"); }
+ }
+
+ ///
+ /// User security stamp cannot be null.
+ ///
+ internal static string FormatNullSecurityStamp()
+ {
+ return GetString("NullSecurityStamp");
+ }
+
///
/// Incorrect password.
///
diff --git a/src/Microsoft.AspNetCore.Identity/Resources.resx b/src/Microsoft.AspNetCore.Identity/Resources.resx
index 85e16fc30d..3e0512b167 100644
--- a/src/Microsoft.AspNetCore.Identity/Resources.resx
+++ b/src/Microsoft.AspNetCore.Identity/Resources.resx
@@ -177,6 +177,10 @@
No IUserTokenProvider named '{0}' is registered.
Error when there is no IUserTokenProvider
+
+ User security stamp cannot be null.
+ Error when a user's security stamp is null.
+
Incorrect password.
Error when a password doesn't match
diff --git a/src/Microsoft.AspNetCore.Identity/UserManager.cs b/src/Microsoft.AspNetCore.Identity/UserManager.cs
index d3eff1b91d..ffd67bd867 100644
--- a/src/Microsoft.AspNetCore.Identity/UserManager.cs
+++ b/src/Microsoft.AspNetCore.Identity/UserManager.cs
@@ -2236,6 +2236,14 @@ namespace Microsoft.AspNetCore.Identity
private async Task ValidateUserInternal(TUser user)
{
+ if (SupportsUserSecurityStamp)
+ {
+ var stamp = await GetSecurityStampAsync(user);
+ if (stamp == null)
+ {
+ throw new InvalidOperationException(Resources.NullSecurityStamp);
+ }
+ }
var errors = new List();
foreach (var v in UserValidators)
{
diff --git a/test/Microsoft.AspNetCore.Identity.Test/UserManagerTest.cs b/test/Microsoft.AspNetCore.Identity.Test/UserManagerTest.cs
index 664bc14f9f..61a0e1e0ec 100644
--- a/test/Microsoft.AspNetCore.Identity.Test/UserManagerTest.cs
+++ b/test/Microsoft.AspNetCore.Identity.Test/UserManagerTest.cs
@@ -483,6 +483,42 @@ namespace Microsoft.AspNetCore.Identity.Test
hasher.VerifyAll();
}
+ [Fact]
+ public async Task CreateFailsWithNullSecurityStamp()
+ {
+ // Setup
+ var store = new Mock>();
+ var manager = MockHelpers.TestUserManager(store.Object);
+ var user = new TestUser { UserName = "nulldude" };
+ store.Setup(s => s.GetSecurityStampAsync(user, It.IsAny())).ReturnsAsync(null).Verifiable();
+
+ // Act
+ // Assert
+ var ex = await Assert.ThrowsAsync(() => manager.CreateAsync(user));
+ Assert.Contains(Resources.NullSecurityStamp, ex.Message);
+
+ store.VerifyAll();
+ }
+
+ [Fact]
+ public async Task UpdateFailsWithNullSecurityStamp()
+ {
+ // Setup
+ var store = new Mock>();
+ var manager = MockHelpers.TestUserManager(store.Object);
+ var user = new TestUser { UserName = "nulldude" };
+ store.Setup(s => s.GetSecurityStampAsync(user, It.IsAny())).ReturnsAsync(null).Verifiable();
+
+ // Act
+ // Assert
+ var ex = await Assert.ThrowsAsync(() => manager.UpdateAsync(user));
+ Assert.Contains(Resources.NullSecurityStamp, ex.Message);
+
+ store.VerifyAll();
+ }
+
+
+
[Fact]
public async Task RemoveClaimsCallsStore()
{