Flesh out implementation, add InMemoryTests

- Implement RoleManager
- Replace IIdentityValidator with IUser/Role/Password Validator
- Add test project.json and working tests for InMemoryUserStore
This commit is contained in:
Hao Kung 2014-03-03 17:25:39 -08:00
Родитель 06f9b90aea
Коммит b13d26cab6
16 изменённых файлов: 1407 добавлений и 123 удалений

Просмотреть файл

@ -23,6 +23,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.I
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.InMemory.k10", "src\Microsoft.AspNet.Identity.InMemory\Microsoft.AspNet.Identity.InMemory.k10.csproj", "{D2E7A146-C39F-4302-8EA3-BFA8C1082939}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.Test.net45", "test\Microsoft.AspNet.Identity.Test\Microsoft.AspNet.Identity.Test.net45.csproj", "{E00E23B0-79B8-41E1-9998-57FECA1F2535}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Aspnet.Identity.InMemory.Test.net45", "test\Microsoft.Aspnet.Identity.InMemory.Test\Microsoft.Aspnet.Identity.InMemory.Test.net45.csproj", "{9022EBC9-BAD4-4BCB-85F5-2BB0DD155825}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -34,7 +38,6 @@ Global
{B72401D7-47F6-4A98-89D5-CCBFEFC5B2B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B72401D7-47F6-4A98-89D5-CCBFEFC5B2B8}.Release|Any CPU.Build.0 = Release|Any CPU
{6211450F-FFB8-431F-84E2-9A7620875260}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6211450F-FFB8-431F-84E2-9A7620875260}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6211450F-FFB8-431F-84E2-9A7620875260}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6211450F-FFB8-431F-84E2-9A7620875260}.Release|Any CPU.Build.0 = Release|Any CPU
{E52361C9-1F0B-4229-86A0-E5C7C12A5429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@ -42,7 +45,6 @@ Global
{E52361C9-1F0B-4229-86A0-E5C7C12A5429}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E52361C9-1F0B-4229-86A0-E5C7C12A5429}.Release|Any CPU.Build.0 = Release|Any CPU
{D32483A4-B617-480C-81E6-49CD596B9A34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D32483A4-B617-480C-81E6-49CD596B9A34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D32483A4-B617-480C-81E6-49CD596B9A34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D32483A4-B617-480C-81E6-49CD596B9A34}.Release|Any CPU.Build.0 = Release|Any CPU
{054B3FFA-7196-466F-9A8A-593FFE037A69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@ -50,9 +52,16 @@ Global
{054B3FFA-7196-466F-9A8A-593FFE037A69}.Release|Any CPU.ActiveCfg = Release|Any CPU
{054B3FFA-7196-466F-9A8A-593FFE037A69}.Release|Any CPU.Build.0 = Release|Any CPU
{D2E7A146-C39F-4302-8EA3-BFA8C1082939}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D2E7A146-C39F-4302-8EA3-BFA8C1082939}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2E7A146-C39F-4302-8EA3-BFA8C1082939}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2E7A146-C39F-4302-8EA3-BFA8C1082939}.Release|Any CPU.Build.0 = Release|Any CPU
{E00E23B0-79B8-41E1-9998-57FECA1F2535}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E00E23B0-79B8-41E1-9998-57FECA1F2535}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E00E23B0-79B8-41E1-9998-57FECA1F2535}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E00E23B0-79B8-41E1-9998-57FECA1F2535}.Release|Any CPU.Build.0 = Release|Any CPU
{9022EBC9-BAD4-4BCB-85F5-2BB0DD155825}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9022EBC9-BAD4-4BCB-85F5-2BB0DD155825}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9022EBC9-BAD4-4BCB-85F5-2BB0DD155825}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9022EBC9-BAD4-4BCB-85F5-2BB0DD155825}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -60,6 +69,8 @@ Global
GlobalSection(NestedProjects) = preSolution
{F6B0C0E9-C346-49D0-B583-95B6CE04BB1B} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
{77CEDA6C-A833-455D-8357-649BFD944724} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
{E00E23B0-79B8-41E1-9998-57FECA1F2535} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
{9022EBC9-BAD4-4BCB-85F5-2BB0DD155825} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
{B72401D7-47F6-4A98-89D5-CCBFEFC5B2B8} = {F6B0C0E9-C346-49D0-B583-95B6CE04BB1B}
{E52361C9-1F0B-4229-86A0-E5C7C12A5429} = {F6B0C0E9-C346-49D0-B583-95B6CE04BB1B}
{054B3FFA-7196-466F-9A8A-593FFE037A69} = {F6B0C0E9-C346-49D0-B583-95B6CE04BB1B}

Просмотреть файл

@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
#if NET45
using System.Security.Claims;
#else
using System.Security.ClaimsK;
#endif
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
namespace Microsoft.AspNet.Identity.InMemory
{
@ -17,12 +14,16 @@ namespace Microsoft.AspNet.Identity.InMemory
private readonly IList<UserLoginInfo> _logins;
private readonly IList<string> _roles;
public InMemoryUser(string name)
public InMemoryUser()
{
Id = Guid.NewGuid().ToString();
_logins = new List<UserLoginInfo>();
_claims = new List<Claim>();
_roles = new List<string>();
}
public InMemoryUser(string name) : this()
{
UserName = name;
}

Просмотреть файл

@ -10,55 +10,57 @@ using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity.InMemory
{
public class InMemoryUserStore :
IUserStore<InMemoryUser, string>,
IUserLoginStore<InMemoryUser, string>,
IUserRoleStore<InMemoryUser, string>,
IUserClaimStore<InMemoryUser, string>,
IUserPasswordStore<InMemoryUser, string>,
IUserSecurityStampStore<InMemoryUser, string>,
IUserEmailStore<InMemoryUser, string>,
IUserLockoutStore<InMemoryUser, string>,
IUserPhoneNumberStore<InMemoryUser, string>
public class InMemoryUserStore<TUser> :
IUserStore<TUser, string>,
IUserLoginStore<TUser, string>,
IUserRoleStore<TUser, string>,
IUserClaimStore<TUser, string>,
IUserPasswordStore<TUser, string>,
IUserSecurityStampStore<TUser, string>,
IUserEmailStore<TUser, string>,
IUserLockoutStore<TUser, string>,
IUserPhoneNumberStore<TUser, string>
where TUser : InMemoryUser
{
private readonly Dictionary<UserLoginInfo, InMemoryUser> _logins =
new Dictionary<UserLoginInfo, InMemoryUser>(new LoginComparer());
private readonly Dictionary<UserLoginInfo, TUser> _logins =
new Dictionary<UserLoginInfo, TUser>(new LoginComparer());
private readonly Dictionary<string, InMemoryUser> _users = new Dictionary<string, InMemoryUser>();
private readonly Dictionary<string, TUser> _users = new Dictionary<string, TUser>();
public IQueryable<InMemoryUser> Users
public IQueryable<TUser> Users
{
get { return _users.Values.AsQueryable(); }
}
public Task<IList<Claim>> GetClaims(InMemoryUser user)
public Task<IList<Claim>> GetClaims(TUser user)
{
return Task.FromResult(user.Claims);
}
public Task AddClaim(InMemoryUser user, Claim claim)
public Task AddClaim(TUser user, Claim claim)
{
user.Claims.Add(claim);
return Task.FromResult(0);
}
public Task RemoveClaim(InMemoryUser user, Claim claim)
public Task RemoveClaim(TUser user, Claim claim)
{
user.Claims.Remove(claim);
return Task.FromResult(0);
}
public Task AddLogin(InMemoryUser user, UserLoginInfo login)
public Task AddLogin(TUser user, UserLoginInfo login)
{
user.Logins.Add(login);
_logins[login] = user;
return Task.FromResult(0);
}
public Task RemoveLogin(InMemoryUser user, UserLoginInfo login)
public Task RemoveLogin(TUser user, UserLoginInfo login)
{
var logs =
user.Logins.Where(l => l.ProviderKey == login.ProviderKey && l.LoginProvider == login.LoginProvider);
user.Logins.Where(l => l.ProviderKey == login.ProviderKey && l.LoginProvider == login.LoginProvider)
.ToList();
foreach (var l in logs)
{
user.Logins.Remove(l);
@ -67,100 +69,100 @@ namespace Microsoft.AspNet.Identity.InMemory
return Task.FromResult(0);
}
public Task<IList<UserLoginInfo>> GetLogins(InMemoryUser user)
public Task<IList<UserLoginInfo>> GetLogins(TUser user)
{
return Task.FromResult(user.Logins);
}
public Task<InMemoryUser> Find(UserLoginInfo login)
public Task<TUser> Find(UserLoginInfo login)
{
if (_logins.ContainsKey(login))
{
return Task.FromResult(_logins[login]);
}
return Task.FromResult<InMemoryUser>(null);
return Task.FromResult<TUser>(null);
}
public Task SetPasswordHash(InMemoryUser user, string passwordHash)
public Task SetPasswordHash(TUser user, string passwordHash)
{
user.PasswordHash = passwordHash;
return Task.FromResult(0);
}
public Task<string> GetPasswordHash(InMemoryUser user)
public Task<string> GetPasswordHash(TUser user)
{
return Task.FromResult(user.PasswordHash);
}
public Task<bool> HasPassword(InMemoryUser user)
public Task<bool> HasPassword(TUser user)
{
return Task.FromResult(user.PasswordHash != null);
}
public Task AddToRole(InMemoryUser user, string role)
public Task AddToRole(TUser user, string role)
{
user.Roles.Add(role);
return Task.FromResult(0);
}
public Task RemoveFromRole(InMemoryUser user, string role)
public Task RemoveFromRole(TUser user, string role)
{
user.Roles.Remove(role);
return Task.FromResult(0);
}
public Task<IList<string>> GetRoles(InMemoryUser user)
public Task<IList<string>> GetRoles(TUser user)
{
return Task.FromResult(user.Roles);
}
public Task<bool> IsInRole(InMemoryUser user, string role)
public Task<bool> IsInRole(TUser user, string role)
{
return Task.FromResult(user.Roles.Contains(role));
}
public Task SetSecurityStamp(InMemoryUser user, string stamp)
public Task SetSecurityStamp(TUser user, string stamp)
{
user.SecurityStamp = stamp;
return Task.FromResult(0);
}
public Task<string> GetSecurityStamp(InMemoryUser user)
public Task<string> GetSecurityStamp(TUser user)
{
return Task.FromResult(user.SecurityStamp);
}
public Task Create(InMemoryUser user)
public Task Create(TUser user)
{
_users[user.Id] = user;
return Task.FromResult(0);
}
public Task Update(InMemoryUser user)
public Task Update(TUser user)
{
_users[user.Id] = user;
return Task.FromResult(0);
}
public Task<InMemoryUser> FindById(string userId)
public Task<TUser> FindById(string userId)
{
if (_users.ContainsKey(userId))
{
return Task.FromResult(_users[userId]);
}
return Task.FromResult<InMemoryUser>(null);
return Task.FromResult<TUser>(null);
}
public void Dispose()
{
}
public Task<InMemoryUser> FindByName(string userName)
public Task<TUser> FindByName(string userName)
{
return Task.FromResult(Users.FirstOrDefault(u => String.Equals(u.UserName, userName, StringComparison.OrdinalIgnoreCase)));
}
public Task Delete(InMemoryUser user)
public Task Delete(TUser user)
{
if (user == null || !_users.ContainsKey(user.Id))
{
@ -170,89 +172,89 @@ namespace Microsoft.AspNet.Identity.InMemory
return Task.FromResult(0);
}
public Task SetEmail(InMemoryUser user, string email)
public Task SetEmail(TUser user, string email)
{
user.Email = email;
return Task.FromResult(0);
}
public Task<string> GetEmail(InMemoryUser user)
public Task<string> GetEmail(TUser user)
{
return Task.FromResult(user.Email);
}
public Task<bool> GetEmailConfirmed(InMemoryUser user)
public Task<bool> GetEmailConfirmed(TUser user)
{
return Task.FromResult(user.EmailConfirmed);
}
public Task SetEmailConfirmed(InMemoryUser user, bool confirmed)
public Task SetEmailConfirmed(TUser user, bool confirmed)
{
user.EmailConfirmed = confirmed;
return Task.FromResult(0);
}
public Task<InMemoryUser> FindByEmail(string email)
public Task<TUser> FindByEmail(string email)
{
return Task.FromResult(Users.FirstOrDefault(u => String.Equals(u.Email, email, StringComparison.OrdinalIgnoreCase)));
}
public Task<DateTimeOffset> GetLockoutEndDate(InMemoryUser user)
public Task<DateTimeOffset> GetLockoutEndDate(TUser user)
{
return Task.FromResult(user.LockoutEnd);
}
public Task SetLockoutEndDate(InMemoryUser user, DateTimeOffset lockoutEnd)
public Task SetLockoutEndDate(TUser user, DateTimeOffset lockoutEnd)
{
user.LockoutEnd = lockoutEnd;
return Task.FromResult(0);
}
public Task<int> IncrementAccessFailedCount(InMemoryUser user)
public Task<int> IncrementAccessFailedCount(TUser user)
{
user.AccessFailedCount++;
return Task.FromResult(user.AccessFailedCount);
}
public Task ResetAccessFailedCount(InMemoryUser user)
public Task ResetAccessFailedCount(TUser user)
{
user.AccessFailedCount = 0;
return Task.FromResult(0);
}
public Task<int> GetAccessFailedCount(InMemoryUser user)
public Task<int> GetAccessFailedCount(TUser user)
{
return Task.FromResult(user.AccessFailedCount);
}
public Task<bool> GetLockoutEnabled(InMemoryUser user)
public Task<bool> GetLockoutEnabled(TUser user)
{
return Task.FromResult(user.LockoutEnabled);
}
public Task SetLockoutEnabled(InMemoryUser user, bool enabled)
public Task SetLockoutEnabled(TUser user, bool enabled)
{
user.LockoutEnabled = enabled;
return Task.FromResult(0);
}
public Task SetPhoneNumber(InMemoryUser user, string phoneNumber)
public Task SetPhoneNumber(TUser user, string phoneNumber)
{
user.PhoneNumber = phoneNumber;
return Task.FromResult(0);
}
public Task<string> GetPhoneNumber(InMemoryUser user)
public Task<string> GetPhoneNumber(TUser user)
{
return Task.FromResult(user.PhoneNumber);
}
public Task<bool> GetPhoneNumberConfirmed(InMemoryUser user)
public Task<bool> GetPhoneNumberConfirmed(TUser user)
{
return Task.FromResult(user.PhoneNumberConfirmed);
}
public Task SetPhoneNumberConfirmed(InMemoryUser user, bool confirmed)
public Task SetPhoneNumberConfirmed(TUser user, bool confirmed)
{
user.PhoneNumberConfirmed = confirmed;
return Task.FromResult(0);

Просмотреть файл

@ -1,18 +0,0 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Used to validate an item
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IIdentityValidator<in T>
{
/// <summary>
/// Validate the item
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
Task<IdentityResult> Validate(T item);
}
}

Просмотреть файл

@ -0,0 +1,16 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Used to validate passwords
/// </summary>
public interface IPasswordValidator
{
/// <summary>
/// Validate the item
/// </summary>
/// <returns></returns>
Task<IdentityResult> Validate(string password);
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Used to validate a role
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IRoleValidator<in T>
{
/// <summary>
/// Validate the user
/// </summary>
/// <param name="role"></param>
/// <returns></returns>
Task<IdentityResult> Validate(T role);
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Used to validate a user
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IUserValidator<in T>
{
/// <summary>
/// Validate the user
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
Task<IdentityResult> Validate(T user);
}
}

Просмотреть файл

@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Used to validate some basic password policy like length and number of non alphanumerics
/// </summary>
public class PasswordValidator : IPasswordValidator
{
/// <summary>
/// Minimum required length
/// </summary>
public int RequiredLength { get; set; }
/// <summary>
/// Require a non letter or digit character
/// </summary>
public bool RequireNonLetterOrDigit { get; set; }
/// <summary>
/// Require a lower case letter ('a' - 'z')
/// </summary>
public bool RequireLowercase { get; set; }
/// <summary>
/// Require an upper case letter ('A' - 'Z')
/// </summary>
public bool RequireUppercase { get; set; }
/// <summary>
/// Require a digit ('0' - '9')
/// </summary>
public bool RequireDigit { get; set; }
/// <summary>
/// Ensures that the string is of the required length and meets the configured requirements
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public virtual Task<IdentityResult> Validate(string item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
var errors = new List<string>();
if (string.IsNullOrWhiteSpace(item) || item.Length < RequiredLength)
{
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.PasswordTooShort, RequiredLength));
}
if (RequireNonLetterOrDigit && item.All(IsLetterOrDigit))
{
errors.Add(Resources.PasswordRequireNonLetterOrDigit);
}
if (RequireDigit && item.All(c => !IsDigit(c)))
{
errors.Add(Resources.PasswordRequireDigit);
}
if (RequireLowercase && item.All(c => !IsLower(c)))
{
errors.Add(Resources.PasswordRequireLower);
}
if (RequireUppercase && item.All(c => !IsUpper(c)))
{
errors.Add(Resources.PasswordRequireUpper);
}
if (errors.Count == 0)
{
return Task.FromResult(IdentityResult.Success);
}
return Task.FromResult(IdentityResult.Failed(String.Join(" ", errors)));
}
/// <summary>
/// Returns true if the character is a digit between '0' and '9'
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
public virtual bool IsDigit(char c)
{
return c >= '0' && c <= '9';
}
/// <summary>
/// Returns true if the character is between 'a' and 'z'
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
public virtual bool IsLower(char c)
{
return c >= 'a' && c <= 'z';
}
/// <summary>
/// Returns true if the character is between 'A' and 'Z'
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
public virtual bool IsUpper(char c)
{
return c >= 'A' && c <= 'Z';
}
/// <summary>
/// Returns true if the character is upper, lower, or a digit
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
public virtual bool IsLetterOrDigit(char c)
{
return IsUpper(c) || IsLower(c) || IsDigit(c);
}
}
}

Просмотреть файл

@ -0,0 +1,213 @@
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Exposes role related api which will automatically save changes to the RoleStore
/// </summary>
/// <typeparam name="TRole"></typeparam>
public class RoleManager<TRole> : RoleManager<TRole, string> where TRole : class, IRole<string>
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="store"></param>
public RoleManager(IRoleStore<TRole, string> store)
: base(store)
{
}
}
/// <summary>
/// Exposes role related api which will automatically save changes to the RoleStore
/// </summary>
/// <typeparam name="TRole"></typeparam>
/// <typeparam name="TKey"></typeparam>
public class RoleManager<TRole, TKey> : IDisposable
where TRole : class, IRole<TKey>
where TKey : IEquatable<TKey>
{
private bool _disposed;
/// <summary>
/// Constructor
/// </summary>
/// <param name="store">The IRoleStore is responsible for commiting changes via the UpdateAsync/CreateAsync methods</param>
public RoleManager(IRoleStore<TRole, TKey> store)
{
if (store == null)
{
throw new ArgumentNullException("store");
}
Store = store;
RoleValidator = new RoleValidator<TRole, TKey>(this);
}
/// <summary>
/// Persistence abstraction that the Manager operates against
/// </summary>
protected IRoleStore<TRole, TKey> Store { get; private set; }
/// <summary>
/// Used to validate roles before persisting changes
/// </summary>
public IRoleValidator<TRole> RoleValidator { get; set; }
/// <summary>
/// Returns an IQueryable of roles if the store is an IQueryableRoleStore
/// </summary>
public virtual IQueryable<TRole> Roles
{
get
{
var queryableStore = Store as IQueryableRoleStore<TRole, TKey>;
if (queryableStore == null)
{
throw new NotSupportedException(Resources.StoreNotIQueryableRoleStore);
}
return queryableStore.Roles;
}
}
/// <summary>
/// Dispose this object
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private async Task<IdentityResult> ValidateRoleInternal(TRole role)
{
return (RoleValidator == null) ? IdentityResult.Success : await RoleValidator.Validate(role).ConfigureAwait(false);
}
/// <summary>
/// Create a role
/// </summary>
/// <param name="role"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> Create(TRole role)
{
ThrowIfDisposed();
if (role == null)
{
throw new ArgumentNullException("role");
}
var result = await ValidateRoleInternal(role);
if (!result.Succeeded)
{
return result;
}
await Store.Create(role);
return IdentityResult.Success;
}
/// <summary>
/// Update an existing role
/// </summary>
/// <param name="role"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> Update(TRole role)
{
ThrowIfDisposed();
if (role == null)
{
throw new ArgumentNullException("role");
}
var result = await ValidateRoleInternal(role);
if (!result.Succeeded)
{
return result;
}
await Store.Update(role).ConfigureAwait(false);
return IdentityResult.Success;
}
/// <summary>
/// Delete a role
/// </summary>
/// <param name="role"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> Delete(TRole role)
{
ThrowIfDisposed();
if (role == null)
{
throw new ArgumentNullException("role");
}
await Store.Delete(role).ConfigureAwait(false);
return IdentityResult.Success;
}
/// <summary>
/// Returns true if the role exists
/// </summary>
/// <param name="roleName"></param>
/// <returns></returns>
public virtual async Task<bool> RoleExists(string roleName)
{
ThrowIfDisposed();
if (roleName == null)
{
throw new ArgumentNullException("roleName");
}
return await FindByName(roleName).ConfigureAwait(false) != null;
}
/// <summary>
/// Find a role by id
/// </summary>
/// <param name="roleId"></param>
/// <returns></returns>
public virtual async Task<TRole> FindById(TKey roleId)
{
ThrowIfDisposed();
return await Store.FindById(roleId).ConfigureAwait(false);
}
/// <summary>
/// Find a role by name
/// </summary>
/// <param name="roleName"></param>
/// <returns></returns>
public virtual async Task<TRole> FindByName(string roleName)
{
ThrowIfDisposed();
if (roleName == null)
{
throw new ArgumentNullException("roleName");
}
return await Store.FindByName(roleName).ConfigureAwait(false);
}
private void ThrowIfDisposed()
{
if (_disposed)
{
throw new ObjectDisposedException(GetType().Name);
}
}
/// <summary>
/// When disposing, actually dipose the store
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (disposing && !_disposed)
{
Store.Dispose();
}
_disposed = true;
}
}
}

Просмотреть файл

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Validates roles before they are saved
/// </summary>
/// <typeparam name="TRole"></typeparam>
/// <typeparam name="TKey"></typeparam>
public class RoleValidator<TRole, TKey> : IRoleValidator<TRole>
where TRole : class, IRole<TKey>
where TKey : IEquatable<TKey>
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="manager"></param>
public RoleValidator(RoleManager<TRole, TKey> manager)
{
if (manager == null)
{
throw new ArgumentNullException("manager");
}
Manager = manager;
}
private RoleManager<TRole, TKey> Manager { get; set; }
/// <summary>
/// Validates a role before saving
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> Validate(TRole item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
var errors = new List<string>();
await ValidateRoleName(item, errors);
if (errors.Count > 0)
{
return IdentityResult.Failed(errors.ToArray());
}
return IdentityResult.Success;
}
private async Task ValidateRoleName(TRole role, List<string> errors)
{
if (string.IsNullOrWhiteSpace(role.Name))
{
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.PropertyTooShort, "Name"));
}
else
{
var owner = await Manager.FindByName(role.Name);
if (owner != null && !EqualityComparer<TKey>.Default.Equals(owner.Id, role.Id))
{
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.DuplicateName, role.Name));
}
}
}
}
}

Просмотреть файл

@ -29,8 +29,6 @@ namespace Microsoft.AspNet.Identity
private TimeSpan _defaultLockout = TimeSpan.Zero;
private bool _disposed;
private IPasswordHasher _passwordHasher;
private IIdentityValidator<string> _passwordValidator;
private IIdentityValidator<TUser> _userValidator;
/// <summary>
/// Constructor which takes a service provider to find the default interfaces to hook up
@ -45,6 +43,8 @@ namespace Microsoft.AspNet.Identity
Store = serviceProvider.GetService<IUserStore<TUser, TKey>>();
ClaimsIdentityFactory = serviceProvider.GetService<IClaimsIdentityFactory<TUser, TKey>>();
PasswordHasher = serviceProvider.GetService<IPasswordHasher>();
UserValidator = serviceProvider.GetService<IUserValidator<TUser>>();
PasswordValidator = serviceProvider.GetService<IPasswordValidator>();
// TODO: validator interfaces, and maybe each optional store as well? Email and SMS services?
}
@ -59,8 +59,7 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("store");
}
Store = store;
//UserValidator = new UserValidator<TUser, TKey>(this);
//PasswordValidator = new MinimumLengthValidator(6);
UserValidator = new UserValidator<TUser, TKey>(this);
//PasswordHasher = new PasswordHasher();
//ClaimsIdentityFactory = new ClaimsIdentityFactory<TUser, TKey>();
}
@ -94,44 +93,12 @@ namespace Microsoft.AspNet.Identity
/// <summary>
/// Used to validate users before persisting changes
/// </summary>
public IIdentityValidator<TUser> UserValidator
{
get
{
ThrowIfDisposed();
return _userValidator;
}
set
{
ThrowIfDisposed();
if (value == null)
{
throw new ArgumentNullException("value");
}
_userValidator = value;
}
}
public IUserValidator<TUser> UserValidator { get; set; }
/// <summary>
/// Used to validate passwords before persisting changes
/// </summary>
public IIdentityValidator<string> PasswordValidator
{
get
{
ThrowIfDisposed();
return _passwordValidator;
}
set
{
ThrowIfDisposed();
if (value == null)
{
throw new ArgumentNullException("value");
}
_passwordValidator = value;
}
}
public IPasswordValidator PasswordValidator { get; set; }
/// <summary>
/// Used to create claims identities from users
@ -359,6 +326,10 @@ namespace Microsoft.AspNet.Identity
return ClaimsIdentityFactory.Create(this, user, authenticationType);
}
private async Task<IdentityResult> ValidateUserInternal(TUser user) {
return (UserValidator == null) ? IdentityResult.Success : await UserValidator.Validate(user).ConfigureAwait(false);
}
/// <summary>
/// Create a user with no password
/// </summary>
@ -368,7 +339,7 @@ namespace Microsoft.AspNet.Identity
{
ThrowIfDisposed();
await UpdateSecurityStampInternal(user).ConfigureAwait(false);
var result = await UserValidator.Validate(user).ConfigureAwait(false);
var result = await ValidateUserInternal(user);
if (!result.Succeeded)
{
return result;
@ -393,8 +364,7 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
var result = await UserValidator.Validate(user).ConfigureAwait(false);
var result = await ValidateUserInternal(user);
if (!result.Succeeded)
{
return result;
@ -612,10 +582,13 @@ namespace Microsoft.AspNet.Identity
internal async Task<IdentityResult> UpdatePasswordInternal(IUserPasswordStore<TUser, TKey> passwordStore,
TUser user, string newPassword)
{
var result = await PasswordValidator.Validate(newPassword).ConfigureAwait(false);
if (!result.Succeeded)
if (PasswordValidator != null)
{
return result;
var result = await PasswordValidator.Validate(newPassword).ConfigureAwait(false);
if (!result.Succeeded)
{
return result;
}
}
await
passwordStore.SetPasswordHash(user, PasswordHasher.HashPassword(newPassword)).ConfigureAwait(false);

Просмотреть файл

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net.Mail;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Validates users before they are saved
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public class UserValidator<TUser, TKey> : IUserValidator<TUser>
where TUser : class, IUser<TKey>
where TKey : IEquatable<TKey>
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="manager"></param>
public UserValidator(UserManager<TUser, TKey> manager)
{
if (manager == null)
{
throw new ArgumentNullException("manager");
}
AllowOnlyAlphanumericUserNames = true;
Manager = manager;
}
/// <summary>
/// Only allow [A-Za-z0-9@_] in UserNames
/// </summary>
public bool AllowOnlyAlphanumericUserNames { get; set; }
/// <summary>
/// If set, enforces that emails are non empty, valid, and unique
/// </summary>
public bool RequireUniqueEmail { get; set; }
private UserManager<TUser, TKey> Manager { get; set; }
/// <summary>
/// Validates a user before saving
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> Validate(TUser item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
var errors = new List<string>();
await ValidateUserName(item, errors);
if (RequireUniqueEmail)
{
await ValidateEmail(item, errors);
}
if (errors.Count > 0)
{
return IdentityResult.Failed(errors.ToArray());
}
return IdentityResult.Success;
}
private async Task ValidateUserName(TUser user, List<string> errors)
{
if (string.IsNullOrWhiteSpace(user.UserName))
{
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.PropertyTooShort, "Name"));
}
else if (AllowOnlyAlphanumericUserNames && !Regex.IsMatch(user.UserName, @"^[A-Za-z0-9@_\.]+$"))
{
// If any characters are not letters or digits, its an illegal user name
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.InvalidUserName, user.UserName));
}
else
{
var owner = await Manager.FindByName(user.UserName);
if (owner != null && !EqualityComparer<TKey>.Default.Equals(owner.Id, user.Id))
{
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.DuplicateName, user.UserName));
}
}
}
// make sure email is not empty, valid, and unique
private async Task ValidateEmail(TUser user, List<string> errors)
{
var email = await Manager.GetEmailStore().GetEmail(user).ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(email))
{
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.PropertyTooShort, "Email"));
return;
}
try
{
var m = new MailAddress(email);
}
catch (FormatException)
{
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.InvalidEmail, email));
return;
}
var owner = await Manager.FindByEmail(email);
if (owner != null && !EqualityComparer<TKey>.Default.Equals(owner.Id, user.Id))
{
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.DuplicateEmail, email));
}
}
}
}

Просмотреть файл

@ -0,0 +1,691 @@
using System;
using System.Linq;
#if NET45
using System.Security.Claims;
#else
using System.Security.ClaimsK;
#endif
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNet.Identity.InMemory.Test
{
public class InMemoryStoreTest
{
[Fact]
public async Task DeleteUserTest()
{
var manager = CreateManager();
var user = new InMemoryUser("Delete");
UnitTestHelper.IsSuccess(await manager.Create(user));
UnitTestHelper.IsSuccess(await manager.Delete(user));
Assert.Null(await manager.FindById(user.Id));
}
[Fact]
public async Task CreateUserNoPasswordTest()
{
var manager = CreateManager();
UnitTestHelper.IsSuccess(await manager.Create(new InMemoryUser("CreateUserTest")));
var user = await manager.FindByName("CreateUserTest");
Assert.NotNull(user);
Assert.Null(user.PasswordHash);
var logins = await manager.GetLogins(user.Id);
Assert.NotNull(logins);
Assert.Equal(0, logins.Count());
}
[Fact]
public async Task CreateUserAddLoginTest()
{
var manager = CreateManager();
const string userName = "CreateExternalUserTest";
const string provider = "ZzAuth";
const string providerKey = "HaoKey";
UnitTestHelper.IsSuccess(await manager.Create(new InMemoryUser(userName)));
var user = await manager.FindByName(userName);
var login = new UserLoginInfo(provider, providerKey);
UnitTestHelper.IsSuccess(await manager.AddLogin(user.Id, login));
var logins = await manager.GetLogins(user.Id);
Assert.NotNull(logins);
Assert.Equal(1, logins.Count());
Assert.Equal(provider, logins.First().LoginProvider);
Assert.Equal(providerKey, logins.First().ProviderKey);
}
//[Fact]
//public async Task CreateUserLoginAndAddPasswordTest()
//{
// var manager = CreateManager();
// var login = new UserLoginInfo("Provider", "key");
// var user = new InMemoryUser("CreateUserLoginAddPasswordTest");
// UnitTestHelper.IsSuccess(await manager.Create(user));
// UnitTestHelper.IsSuccess(await manager.AddLogin(user.Id, login));
// UnitTestHelper.IsSuccess(await manager.AddPassword(user.Id, "password"));
// var logins = await manager.GetLogins(user.Id);
// Assert.NotNull(logins);
// Assert.Equal(1, logins.Count());
// Assert.Equal(user, await manager.Find(login));
// Assert.Equal(user, await manager.Find(user.UserName, "password"));
//}
[Fact]
public async Task CreateUserAddRemoveLoginTest()
{
var manager = CreateManager();
var user = new InMemoryUser("CreateUserAddRemoveLoginTest");
var login = new UserLoginInfo("Provider", "key");
var result = await manager.Create(user);
Assert.NotNull(user);
UnitTestHelper.IsSuccess(result);
UnitTestHelper.IsSuccess(await manager.AddLogin(user.Id, login));
Assert.Equal(user, await manager.Find(login));
var logins = await manager.GetLogins(user.Id);
Assert.NotNull(logins);
Assert.Equal(1, logins.Count());
Assert.Equal(login.LoginProvider, logins.Last().LoginProvider);
Assert.Equal(login.ProviderKey, logins.Last().ProviderKey);
var stamp = user.SecurityStamp;
UnitTestHelper.IsSuccess(await manager.RemoveLogin(user.Id, login));
Assert.Null(await manager.Find(login));
logins = await manager.GetLogins(user.Id);
Assert.NotNull(logins);
Assert.Equal(0, logins.Count());
Assert.NotEqual(stamp, user.SecurityStamp);
}
//[Fact]
//public async Task RemovePasswordTest()
//{
// var manager = CreateManager();
// var user = new InMemoryUser("RemovePasswordTest");
// const string password = "password";
// UnitTestHelper.IsSuccess(await manager.Create(user, password));
// var stamp = user.SecurityStamp;
// UnitTestHelper.IsSuccess(await manager.RemovePassword(user.Id));
// var u = await manager.FindByName(user.UserName);
// Assert.NotNull(u);
// Assert.Null(u.PasswordHash);
// Assert.NotEqual(stamp, user.SecurityStamp);
//}
//[Fact]
//public async Task ChangePasswordTest()
//{
// var manager = CreateManager();
// var user = new InMemoryUser("ChangePasswordTest");
// const string password = "password";
// const string newPassword = "newpassword";
// UnitTestHelper.IsSuccess(await manager.Create(user, password));
// var stamp = user.SecurityStamp;
// Assert.NotNull(stamp);
// UnitTestHelper.IsSuccess(await manager.ChangePassword(user.Id, password, newPassword));
// Assert.Null(await manager.Find(user.UserName, password));
// Assert.Equal(user, await manager.Find(user.UserName, newPassword));
// Assert.NotEqual(stamp, user.SecurityStamp);
//}
[Fact]
public async Task AddRemoveUserClaimTest()
{
var manager = CreateManager();
var user = new InMemoryUser("ClaimsAddRemove");
UnitTestHelper.IsSuccess(await manager.Create(user));
Claim[] claims = { new Claim("c", "v"), new Claim("c2", "v2"), new Claim("c2", "v3") };
foreach (Claim c in claims)
{
UnitTestHelper.IsSuccess(await manager.AddClaim(user.Id, c));
}
var userClaims = await manager.GetClaims(user.Id);
Assert.Equal(3, userClaims.Count);
UnitTestHelper.IsSuccess(await manager.RemoveClaim(user.Id, claims[0]));
userClaims = await manager.GetClaims(user.Id);
Assert.Equal(2, userClaims.Count);
UnitTestHelper.IsSuccess(await manager.RemoveClaim(user.Id, claims[1]));
userClaims = await manager.GetClaims(user.Id);
Assert.Equal(1, userClaims.Count);
UnitTestHelper.IsSuccess(await manager.RemoveClaim(user.Id, claims[2]));
userClaims = await manager.GetClaims(user.Id);
Assert.Equal(0, userClaims.Count);
}
//[Fact]
//public async Task ChangePasswordFallsIfPasswordTooShortTest()
//{
// var manager = CreateManager();
// var user = new InMemoryUser("user");
// const string password = "password";
// UnitTestHelper.IsSuccess(await manager.Create(user, password));
// var result = await manager.ChangePassword(user.Id, password, "n");
// UnitTestHelper.IsFailure(result, "Passwords must be at least 6 characters.");
//}
//[Fact]
//public async Task ChangePasswordFallsIfPasswordWrongTest()
//{
// var manager = CreateManager();
// var user = new InMemoryUser("user");
// UnitTestHelper.IsSuccess(await manager.Create(user, "password"));
// var result = await manager.ChangePassword(user.Id, "bogus", "newpassword");
// UnitTestHelper.IsFailure(result, "Incorrect password.");
//}
[Fact]
public async Task AddDupeUserFailsTest()
{
var manager = CreateManager();
var user = new InMemoryUser("dupe");
var user2 = new InMemoryUser("dupe");
UnitTestHelper.IsSuccess(await manager.Create(user));
UnitTestHelper.IsFailure(await manager.Create(user2), "Name dupe is already taken.");
}
[Fact]
public async Task UpdateSecurityStampTest()
{
var manager = CreateManager();
var user = new InMemoryUser("stampMe");
Assert.Null(user.SecurityStamp);
UnitTestHelper.IsSuccess(await manager.Create(user));
var stamp = user.SecurityStamp;
Assert.NotNull(stamp);
UnitTestHelper.IsSuccess(await manager.UpdateSecurityStamp(user.Id));
Assert.NotEqual(stamp, user.SecurityStamp);
}
//[Fact]
//public async Task AddDupeLoginFailsTest()
//{
// var manager = CreateManager();
// var user = new InMemoryUser("DupeLogin");
// var login = new UserLoginInfo("provder", "key");
// UnitTestHelper.IsSuccess(await manager.Create(user));
// UnitTestHelper.IsSuccess(await manager.AddLogin(user.Id, login));
// var result = await manager.AddLogin(user.Id, login);
// UnitTestHelper.IsFailure(result, "A user with that external login already exists.");
//}
// Lockout tests
[Fact]
public async Task SingleFailureLockout()
{
var mgr = CreateManager();
mgr.DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1);
mgr.UserLockoutEnabledByDefault = true;
var user = new InMemoryUser("fastLockout");
UnitTestHelper.IsSuccess(await mgr.Create(user));
Assert.True(await mgr.GetLockoutEnabled(user.Id));
Assert.True(user.LockoutEnabled);
Assert.False(await mgr.IsLockedOut(user.Id));
UnitTestHelper.IsSuccess(await mgr.AccessFailed(user.Id));
Assert.True(await mgr.IsLockedOut(user.Id));
Assert.True(await mgr.GetLockoutEndDate(user.Id) > DateTimeOffset.UtcNow.AddMinutes(55));
Assert.Equal(0, await mgr.GetAccessFailedCount(user.Id));
}
[Fact]
public async Task TwoFailureLockout()
{
var mgr = CreateManager();
mgr.DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1);
mgr.UserLockoutEnabledByDefault = true;
mgr.MaxFailedAccessAttemptsBeforeLockout = 2;
var user = new InMemoryUser("twoFailureLockout");
UnitTestHelper.IsSuccess(await mgr.Create(user));
Assert.True(await mgr.GetLockoutEnabled(user.Id));
Assert.True(user.LockoutEnabled);
Assert.False(await mgr.IsLockedOut(user.Id));
UnitTestHelper.IsSuccess(await mgr.AccessFailed(user.Id));
Assert.False(await mgr.IsLockedOut(user.Id));
Assert.False(await mgr.GetLockoutEndDate(user.Id) > DateTimeOffset.UtcNow.AddMinutes(55));
Assert.Equal(1, await mgr.GetAccessFailedCount(user.Id));
UnitTestHelper.IsSuccess(await mgr.AccessFailed(user.Id));
Assert.True(await mgr.IsLockedOut(user.Id));
Assert.True(await mgr.GetLockoutEndDate(user.Id) > DateTimeOffset.UtcNow.AddMinutes(55));
Assert.Equal(0, await mgr.GetAccessFailedCount(user.Id));
}
[Fact]
public async Task ResetLockoutTest()
{
var mgr = CreateManager();
mgr.DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1);
mgr.UserLockoutEnabledByDefault = true;
mgr.MaxFailedAccessAttemptsBeforeLockout = 2;
var user = new InMemoryUser("resetLockout");
UnitTestHelper.IsSuccess(await mgr.Create(user));
Assert.True(await mgr.GetLockoutEnabled(user.Id));
Assert.True(user.LockoutEnabled);
Assert.False(await mgr.IsLockedOut(user.Id));
UnitTestHelper.IsSuccess(await mgr.AccessFailed(user.Id));
Assert.False(await mgr.IsLockedOut(user.Id));
Assert.False(await mgr.GetLockoutEndDate(user.Id) > DateTimeOffset.UtcNow.AddMinutes(55));
Assert.Equal(1, await mgr.GetAccessFailedCount(user.Id));
UnitTestHelper.IsSuccess(await mgr.ResetAccessFailedCount(user.Id));
Assert.Equal(0, await mgr.GetAccessFailedCount(user.Id));
Assert.False(await mgr.IsLockedOut(user.Id));
Assert.False(await mgr.GetLockoutEndDate(user.Id) > DateTimeOffset.UtcNow.AddMinutes(55));
UnitTestHelper.IsSuccess(await mgr.AccessFailed(user.Id));
Assert.False(await mgr.IsLockedOut(user.Id));
Assert.False(await mgr.GetLockoutEndDate(user.Id) > DateTimeOffset.UtcNow.AddMinutes(55));
Assert.Equal(1, await mgr.GetAccessFailedCount(user.Id));
}
[Fact]
public async Task EnableLockoutManually()
{
var mgr = CreateManager();
mgr.DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1);
mgr.MaxFailedAccessAttemptsBeforeLockout = 2;
var user = new InMemoryUser("manualLockout");
UnitTestHelper.IsSuccess(await mgr.Create(user));
Assert.False(await mgr.GetLockoutEnabled(user.Id));
Assert.False(user.LockoutEnabled);
UnitTestHelper.IsSuccess(await mgr.SetLockoutEnabled(user.Id, true));
Assert.True(await mgr.GetLockoutEnabled(user.Id));
Assert.True(user.LockoutEnabled);
Assert.False(await mgr.IsLockedOut(user.Id));
UnitTestHelper.IsSuccess(await mgr.AccessFailed(user.Id));
Assert.False(await mgr.IsLockedOut(user.Id));
Assert.False(await mgr.GetLockoutEndDate(user.Id) > DateTimeOffset.UtcNow.AddMinutes(55));
Assert.Equal(1, await mgr.GetAccessFailedCount(user.Id));
UnitTestHelper.IsSuccess(await mgr.AccessFailed(user.Id));
Assert.True(await mgr.IsLockedOut(user.Id));
Assert.True(await mgr.GetLockoutEndDate(user.Id) > DateTimeOffset.UtcNow.AddMinutes(55));
Assert.Equal(0, await mgr.GetAccessFailedCount(user.Id));
}
[Fact]
public async Task UserNotLockedOutWithNullDateTimeAndIsSetToNullDate()
{
var mgr = CreateManager();
mgr.UserLockoutEnabledByDefault = true;
var user = new InMemoryUser("LockoutTest");
UnitTestHelper.IsSuccess(await mgr.Create(user));
Assert.True(await mgr.GetLockoutEnabled(user.Id));
Assert.True(user.LockoutEnabled);
UnitTestHelper.IsSuccess(await mgr.SetLockoutEndDate(user.Id, new DateTimeOffset()));
Assert.False(await mgr.IsLockedOut(user.Id));
Assert.Equal(new DateTimeOffset(), await mgr.GetLockoutEndDate(user.Id));
Assert.Equal(new DateTimeOffset(), user.LockoutEnd);
}
[Fact]
public async Task LockoutFailsIfNotEnabled()
{
var mgr = CreateManager();
var user = new InMemoryUser("LockoutNotEnabledTest");
UnitTestHelper.IsSuccess(await mgr.Create(user));
Assert.False(await mgr.GetLockoutEnabled(user.Id));
Assert.False(user.LockoutEnabled);
UnitTestHelper.IsFailure(await mgr.SetLockoutEndDate(user.Id, new DateTimeOffset()), "Lockout is not enabled for this user.");
Assert.False(await mgr.IsLockedOut(user.Id));
}
[Fact]
public async Task LockoutEndToUtcNowMinus1SecInUserShouldNotBeLockedOut()
{
var mgr = CreateManager();
mgr.UserLockoutEnabledByDefault = true;
var user = new InMemoryUser("LockoutUtcNowTest") { LockoutEnd = DateTimeOffset.UtcNow.AddSeconds(-1) };
UnitTestHelper.IsSuccess(await mgr.Create(user));
Assert.True(await mgr.GetLockoutEnabled(user.Id));
Assert.True(user.LockoutEnabled);
Assert.False(await mgr.IsLockedOut(user.Id));
}
[Fact]
public async Task LockoutEndToUtcNowSubOneSecondWithManagerShouldNotBeLockedOut()
{
var mgr = CreateManager();
mgr.UserLockoutEnabledByDefault = true;
var user = new InMemoryUser("LockoutUtcNowTest");
UnitTestHelper.IsSuccess(await mgr.Create(user));
Assert.True(await mgr.GetLockoutEnabled(user.Id));
Assert.True(user.LockoutEnabled);
UnitTestHelper.IsSuccess(await mgr.SetLockoutEndDate(user.Id, DateTimeOffset.UtcNow.AddSeconds(-1)));
Assert.False(await mgr.IsLockedOut(user.Id));
}
[Fact]
public async Task LockoutEndToUtcNowPlus5ShouldBeLockedOut()
{
var mgr = CreateManager();
mgr.UserLockoutEnabledByDefault = true;
var user = new InMemoryUser("LockoutUtcNowTest") { LockoutEnd = DateTimeOffset.UtcNow.AddMinutes(5) };
UnitTestHelper.IsSuccess(await mgr.Create(user));
Assert.True(await mgr.GetLockoutEnabled(user.Id));
Assert.True(user.LockoutEnabled);
Assert.True(await mgr.IsLockedOut(user.Id));
}
[Fact]
public async Task UserLockedOutWithDateTimeLocalKindNowPlus30()
{
var mgr = CreateManager();
mgr.UserLockoutEnabledByDefault = true;
var user = new InMemoryUser("LockoutTest");
UnitTestHelper.IsSuccess(await mgr.Create(user));
Assert.True(await mgr.GetLockoutEnabled(user.Id));
Assert.True(user.LockoutEnabled);
var lockoutEnd = new DateTimeOffset(DateTime.Now.AddMinutes(30).ToLocalTime());
UnitTestHelper.IsSuccess(await mgr.SetLockoutEndDate(user.Id, lockoutEnd));
Assert.True(await mgr.IsLockedOut(user.Id));
var end = await mgr.GetLockoutEndDate(user.Id);
Assert.Equal(lockoutEnd, end);
}
// Role Tests
[Fact]
public async Task CreateRoleTest()
{
var manager = CreateRoleManager();
var role = new InMemoryRole("create");
Assert.False(await manager.RoleExists(role.Name));
UnitTestHelper.IsSuccess(await manager.Create(role));
Assert.True(await manager.RoleExists(role.Name));
}
//[Fact]
//public async Task BadValidatorBlocksCreateTest()
//{
// var manager = CreateRoleManager();
// manager.RoleValidator = new AlwaysBadValidator<InMemoryRole>();
// UnitTestHelper.IsFailure(await manager.Create(new InMemoryRole("blocked")),
// AlwaysBadValidator<InMemoryRole>.ErrorMessage);
//}
//[Fact]
//public async Task BadValidatorBlocksAllUpdatesTest()
//{
// var manager = CreateRoleManager();
// var role = new InMemoryRole("poorguy");
// UnitTestHelper.IsSuccess(await manager.Create(role));
// var error = AlwaysBadValidator<InMemoryRole>.ErrorMessage;
// manager.RoleValidator = new AlwaysBadValidator<InMemoryRole>();
// UnitTestHelper.IsFailure(await manager.Update(role), error);
//}
[Fact]
public async Task DeleteRoleTest()
{
var manager = CreateRoleManager();
var role = new InMemoryRole("delete");
Assert.False(await manager.RoleExists(role.Name));
UnitTestHelper.IsSuccess(await manager.Create(role));
UnitTestHelper.IsSuccess(await manager.Delete(role));
Assert.False(await manager.RoleExists(role.Name));
}
[Fact]
public async Task RoleFindByIdTest()
{
var manager = CreateRoleManager();
var role = new InMemoryRole("FindById");
Assert.Null(await manager.FindById(role.Id));
UnitTestHelper.IsSuccess(await manager.Create(role));
Assert.Equal(role, await manager.FindById(role.Id));
}
[Fact]
public async Task RoleFindByNameTest()
{
var manager = CreateRoleManager();
var role = new InMemoryRole("FindByName");
Assert.Null(await manager.FindByName(role.Name));
Assert.False(await manager.RoleExists(role.Name));
UnitTestHelper.IsSuccess(await manager.Create(role));
Assert.Equal(role, await manager.FindByName(role.Name));
}
[Fact]
public async Task UpdateRoleNameTest()
{
var manager = CreateRoleManager();
var role = new InMemoryRole("update");
Assert.False(await manager.RoleExists(role.Name));
UnitTestHelper.IsSuccess(await manager.Create(role));
Assert.True(await manager.RoleExists(role.Name));
role.Name = "Changed";
UnitTestHelper.IsSuccess(await manager.Update(role));
Assert.False(await manager.RoleExists("update"));
Assert.Equal(role, await manager.FindByName(role.Name));
}
[Fact]
public async Task QuerableRolesTest()
{
var manager = CreateRoleManager();
InMemoryRole[] roles =
{
new InMemoryRole("r1"), new InMemoryRole("r2"), new InMemoryRole("r3"),
new InMemoryRole("r4")
};
foreach (var r in roles)
{
UnitTestHelper.IsSuccess(await manager.Create(r));
}
Assert.Equal(roles.Length, manager.Roles.Count());
var r1 = manager.Roles.FirstOrDefault(r => r.Name == "r1");
Assert.Equal(roles[0], r1);
}
//[Fact]
//public async Task DeleteRoleNonEmptySucceedsTest()
//{
// // Need fail if not empty?
// var userMgr = CreateManager();
// var roleMgr = CreateRoleManager();
// var role = new InMemoryRole("deleteNonEmpty");
// Assert.False(await roleMgr.RoleExists(role.Name));
// UnitTestHelper.IsSuccess(await roleMgr.Create(role));
// var user = new InMemoryUser("t");
// UnitTestHelper.IsSuccess(await userMgr.Create(user));
// UnitTestHelper.IsSuccess(await userMgr.AddToRole(user.Id, role.Name));
// UnitTestHelper.IsSuccess(await roleMgr.Delete(role));
// Assert.Null(await roleMgr.FindByName(role.Name));
// Assert.False(await roleMgr.RoleExists(role.Name));
// // REVIEW: We should throw if deleteing a non empty role?
// var roles = await userMgr.GetRoles(user.Id);
// // In memory this doesn't work since there's no concept of cascading deletes
// //Assert.Equal(0, roles.Count());
//}
////[Fact]
////public async Task DeleteUserRemovesFromRoleTest()
////{
//// // Need fail if not empty?
//// var userMgr = CreateManager();
//// var roleMgr = CreateRoleManager();
//// var role = new InMemoryRole("deleteNonEmpty");
//// Assert.False(await roleMgr.RoleExists(role.Name));
//// UnitTestHelper.IsSuccess(await roleMgr.Create(role));
//// var user = new InMemoryUser("t");
//// UnitTestHelper.IsSuccess(await userMgr.Create(user));
//// UnitTestHelper.IsSuccess(await userMgr.AddToRole(user.Id, role.Name));
//// UnitTestHelper.IsSuccess(await userMgr.Delete(user));
//// role = roleMgr.FindById(role.Id);
////}
[Fact]
public async Task CreateRoleFailsIfExistsTest()
{
var manager = CreateRoleManager();
var role = new InMemoryRole("dupeRole");
Assert.False(await manager.RoleExists(role.Name));
UnitTestHelper.IsSuccess(await manager.Create(role));
Assert.True(await manager.RoleExists(role.Name));
var role2 = new InMemoryRole("dupeRole");
UnitTestHelper.IsFailure(await manager.Create(role2));
}
[Fact]
public async Task AddUserToRoleTest()
{
var manager = CreateManager();
var roleManager = CreateRoleManager();
var role = new InMemoryRole("addUserTest");
UnitTestHelper.IsSuccess(await roleManager.Create(role));
InMemoryUser[] users =
{
new InMemoryUser("1"), new InMemoryUser("2"), new InMemoryUser("3"),
new InMemoryUser("4")
};
foreach (InMemoryUser u in users)
{
UnitTestHelper.IsSuccess(await manager.Create(u));
UnitTestHelper.IsSuccess(await manager.AddToRole(u.Id, role.Name));
Assert.True(await manager.IsInRole(u.Id, role.Name));
}
}
[Fact]
public async Task GetRolesForUserTest()
{
var userManager = CreateManager();
var roleManager = CreateRoleManager();
InMemoryUser[] users =
{
new InMemoryUser("u1"), new InMemoryUser("u2"), new InMemoryUser("u3"),
new InMemoryUser("u4")
};
InMemoryRole[] roles =
{
new InMemoryRole("r1"), new InMemoryRole("r2"), new InMemoryRole("r3"),
new InMemoryRole("r4")
};
foreach (var u in users)
{
UnitTestHelper.IsSuccess(await userManager.Create(u));
}
foreach (var r in roles)
{
UnitTestHelper.IsSuccess(await roleManager.Create(r));
foreach (var u in users)
{
UnitTestHelper.IsSuccess(await userManager.AddToRole(u.Id, r.Name));
Assert.True(await userManager.IsInRole(u.Id, r.Name));
}
}
foreach (var u in users)
{
var rs = await userManager.GetRoles(u.Id);
Assert.Equal(roles.Length, rs.Count);
foreach (var r in roles)
{
Assert.True(rs.Any(role => role == r.Name));
}
}
}
[Fact]
public async Task RemoveUserFromRoleWithMultipleRoles()
{
var userManager = CreateManager();
var roleManager = CreateRoleManager();
var user = new InMemoryUser("MultiRoleUser");
UnitTestHelper.IsSuccess(await userManager.Create(user));
InMemoryRole[] roles =
{
new InMemoryRole("r1"), new InMemoryRole("r2"), new InMemoryRole("r3"),
new InMemoryRole("r4")
};
foreach (var r in roles)
{
UnitTestHelper.IsSuccess(await roleManager.Create(r));
UnitTestHelper.IsSuccess(await userManager.AddToRole(user.Id, r.Name));
Assert.True(await userManager.IsInRole(user.Id, r.Name));
}
UnitTestHelper.IsSuccess(await userManager.RemoveFromRole(user.Id, roles[2].Name));
Assert.False(await userManager.IsInRole(user.Id, roles[2].Name));
}
[Fact]
public async Task RemoveUserFromRoleTest()
{
var userManager = CreateManager();
var roleManager = CreateRoleManager();
InMemoryUser[] users =
{
new InMemoryUser("1"), new InMemoryUser("2"), new InMemoryUser("3"),
new InMemoryUser("4")
};
foreach (var u in users)
{
UnitTestHelper.IsSuccess(await userManager.Create(u));
}
var r = new InMemoryRole("r1");
UnitTestHelper.IsSuccess(await roleManager.Create(r));
foreach (var u in users)
{
UnitTestHelper.IsSuccess(await userManager.AddToRole(u.Id, r.Name));
Assert.True(await userManager.IsInRole(u.Id, r.Name));
}
foreach (var u in users)
{
UnitTestHelper.IsSuccess(await userManager.RemoveFromRole(u.Id, r.Name));
Assert.False(await userManager.IsInRole(u.Id, r.Name));
}
}
[Fact]
public async Task RemoveUserNotInRoleFailsTest()
{
var userMgr = CreateManager();
var roleMgr = CreateRoleManager();
var role = new InMemoryRole("addUserDupeTest");
var user = new InMemoryUser("user1");
UnitTestHelper.IsSuccess(await userMgr.Create(user));
UnitTestHelper.IsSuccess(await roleMgr.Create(role));
var result = await userMgr.RemoveFromRole(user.Id, role.Name);
UnitTestHelper.IsFailure(result, "User is not in role.");
}
[Fact]
public async Task AddUserToRoleFailsIfAlreadyInRoleTest()
{
var userMgr = CreateManager();
var roleMgr = CreateRoleManager();
var role = new InMemoryRole("addUserDupeTest");
var user = new InMemoryUser("user1");
UnitTestHelper.IsSuccess(await userMgr.Create(user));
UnitTestHelper.IsSuccess(await roleMgr.Create(role));
UnitTestHelper.IsSuccess(await userMgr.AddToRole(user.Id, role.Name));
Assert.True(await userMgr.IsInRole(user.Id, role.Name));
UnitTestHelper.IsFailure(await userMgr.AddToRole(user.Id, role.Name), "User already in role.");
}
[Fact]
public async Task FindRoleByNameWithManagerTest()
{
var roleMgr = CreateRoleManager();
var role = new InMemoryRole("findRoleByNameTest");
UnitTestHelper.IsSuccess(await roleMgr.Create(role));
Assert.Equal(role.Id, (await roleMgr.FindByName(role.Name)).Id);
}
[Fact]
public async Task FindRoleWithManagerTest()
{
var roleMgr = CreateRoleManager();
var role = new InMemoryRole("findRoleTest");
UnitTestHelper.IsSuccess(await roleMgr.Create(role));
Assert.Equal(role.Name, (await roleMgr.FindById(role.Id)).Name);
}
private static UserManager<InMemoryUser, string> CreateManager()
{
return new UserManager<InMemoryUser, string>(new InMemoryUserStore<InMemoryUser>());
}
private static RoleManager<InMemoryRole> CreateRoleManager()
{
return new RoleManager<InMemoryRole>(new InMemoryRoleStore());
}
}
}

Просмотреть файл

@ -0,0 +1,29 @@
using System;
using System.Linq;
using Microsoft.AspNet.Identity;
using Xunit;
namespace Microsoft.AspNet.Identity.InMemory.Test
{
public static class UnitTestHelper
{
public static void IsSuccess(IdentityResult result)
{
Assert.NotNull(result);
Assert.True(result.Succeeded);
}
public static void IsFailure(IdentityResult result)
{
Assert.NotNull(result);
Assert.False(result.Succeeded);
}
public static void IsFailure(IdentityResult result, string error)
{
Assert.NotNull(result);
Assert.False(result.Succeeded);
Assert.Equal(error, result.Errors.First());
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
{
"version": "0.1-alpha-*",
"dependencies": {
"Microsoft.AspNet.Identity" : "0.1-alpha-*",
"Microsoft.AspNet.Identity.InMemory" : "0.1-alpha-*",
"Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*"
},
"configurations": {
"net45": {
"dependencies": {
"xunit": "1.9.2"
}
}
}
}

Просмотреть файл

@ -0,0 +1,14 @@
{
"version": "0.1-alpha-*",
"dependencies": {
"Microsoft.AspNet.Identity" : "0.1-alpha-*",
"Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*"
},
"configurations": {
"net45": {
"dependencies": {
"xunit": "1.9.2"
}
}
}
}