first commit
This commit is contained in:
+30
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AspNetCore.Identity.MongoDbCore" Version="1.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="2.4.4" />
|
||||
<PackageReference Include="MongoDbGenericRepository" Version="1.3.0" />
|
||||
<PackageReference Include="Moq" Version="4.7.142" />
|
||||
<PackageReference Include="xunit" Version="2.3.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Identity.Test;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Test
|
||||
{
|
||||
public class ApiConsistencyTest : ApiConsistencyTestBase
|
||||
{
|
||||
protected override Assembly TargetAssembly => typeof(IdentityUser).GetTypeInfo().Assembly;
|
||||
}
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Test
|
||||
{
|
||||
//public class CustomPocoTest : IClassFixture<MongoDatabaseFixture>
|
||||
//{
|
||||
// private readonly MongoDatabaseFixture _fixture;
|
||||
|
||||
// public CustomPocoTest(MongoDatabaseFixture fixture)
|
||||
// {
|
||||
// _fixture = fixture;
|
||||
// }
|
||||
|
||||
// public class User<TKey> where TKey : IEquatable<TKey>
|
||||
// {
|
||||
// public TKey Id { get; set; }
|
||||
// public string UserName { get; set; }
|
||||
// }
|
||||
|
||||
// public class CustomDbContext<TKey> : DbContext where TKey : IEquatable<TKey>
|
||||
// {
|
||||
// public CustomDbContext(DbContextOptions options) : base(options)
|
||||
// { }
|
||||
|
||||
// public DbSet<User<TKey>> Users { get; set; }
|
||||
|
||||
// }
|
||||
|
||||
// public CustomDbContext<TKey> GetContext<TKey>() where TKey : IEquatable<TKey>
|
||||
// {
|
||||
// return DbUtil.Create<CustomDbContext<TKey>>(_fixture.ConnectionString);
|
||||
// }
|
||||
|
||||
// public CustomDbContext<TKey> CreateContext<TKey>(bool delete = false) where TKey : IEquatable<TKey>
|
||||
// {
|
||||
// var db = GetContext<TKey>();
|
||||
// if (delete)
|
||||
// {
|
||||
// db.Database.EnsureDeleted();
|
||||
// }
|
||||
// db.Database.EnsureCreated();
|
||||
// return db;
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public async Task CanUpdateNameGuid()
|
||||
// {
|
||||
// using (var db = CreateContext<Guid>(true))
|
||||
// {
|
||||
// var oldName = Guid.NewGuid().ToString();
|
||||
// var user = new User<Guid> { UserName = oldName, Id = Guid.NewGuid() };
|
||||
// db.Users.Add(user);
|
||||
// await db.SaveChangesAsync();
|
||||
// var newName = Guid.NewGuid().ToString();
|
||||
// user.UserName = newName;
|
||||
// await db.SaveChangesAsync();
|
||||
// Assert.Null(db.Users.SingleOrDefault(u => u.UserName == oldName));
|
||||
// Assert.Equal(user, db.Users.Single(u => u.UserName == newName));
|
||||
// }
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public async Task CanUpdateNameString()
|
||||
// {
|
||||
// using (var db = CreateContext<string>(true))
|
||||
// {
|
||||
// var oldName = Guid.NewGuid().ToString();
|
||||
// var user = new User<string> { UserName = oldName, Id = Guid.NewGuid().ToString() };
|
||||
// db.Users.Add(user);
|
||||
// await db.SaveChangesAsync();
|
||||
// var newName = Guid.NewGuid().ToString();
|
||||
// user.UserName = newName;
|
||||
// await db.SaveChangesAsync();
|
||||
// Assert.Null(db.Users.SingleOrDefault(u => u.UserName == oldName));
|
||||
// Assert.Equal(user, db.Users.Single(u => u.UserName == newName));
|
||||
// }
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public async Task CanCreateUserInt()
|
||||
// {
|
||||
// using (var db = CreateContext<int>(true))
|
||||
// {
|
||||
// var user = new User<int>();
|
||||
// db.Users.Add(user);
|
||||
// await db.SaveChangesAsync();
|
||||
// user.UserName = "Boo";
|
||||
// await db.SaveChangesAsync();
|
||||
// var fetch = db.Users.First(u => u.UserName == "Boo");
|
||||
// Assert.Equal(user, fetch);
|
||||
// }
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public async Task CanCreateUserIntViaSet()
|
||||
// {
|
||||
// using (var db = CreateContext<int>(true))
|
||||
// {
|
||||
// var user = new User<int>();
|
||||
// var users = db.Set<User<int>>();
|
||||
// users.Add(user);
|
||||
// await db.SaveChangesAsync();
|
||||
// user.UserName = "Boo";
|
||||
// await db.SaveChangesAsync();
|
||||
// var fetch = users.First(u => u.UserName == "Boo");
|
||||
// Assert.Equal(user, fetch);
|
||||
// }
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public async Task CanUpdateNameInt()
|
||||
// {
|
||||
// using (var db = CreateContext<int>(true))
|
||||
// {
|
||||
// var oldName = Guid.NewGuid().ToString();
|
||||
// var user = new User<int> { UserName = oldName };
|
||||
// db.Users.Add(user);
|
||||
// await db.SaveChangesAsync();
|
||||
// var newName = Guid.NewGuid().ToString();
|
||||
// user.UserName = newName;
|
||||
// await db.SaveChangesAsync();
|
||||
// Assert.Null(db.Users.SingleOrDefault(u => u.UserName == oldName));
|
||||
// Assert.Equal(user, db.Users.Single(u => u.UserName == newName));
|
||||
// }
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public async Task CanUpdateNameIntWithSet()
|
||||
// {
|
||||
// using (var db = CreateContext<int>(true))
|
||||
// {
|
||||
// var oldName = Guid.NewGuid().ToString();
|
||||
// var user = new User<int> { UserName = oldName };
|
||||
// db.Set<User<int>>().Add(user);
|
||||
// await db.SaveChangesAsync();
|
||||
// var newName = Guid.NewGuid().ToString();
|
||||
// user.UserName = newName;
|
||||
// await db.SaveChangesAsync();
|
||||
// Assert.Null(db.Set<User<int>>().SingleOrDefault(u => u.UserName == oldName));
|
||||
// Assert.Equal(user, db.Set<User<int>>().Single(u => u.UserName == newName));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity.Test;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
using AspNetCore.Identity.MongoDbCore.IntegrationTests.Infrastructure;
|
||||
using MongoDbGenericRepository;
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using AspNetCore.Identity.MongoDbCore;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Test
|
||||
{
|
||||
public abstract class SqlStoreOnlyUsersTestBase<TUser, TKey> : UserManagerSpecificationTestBase<TUser, TKey>, IClassFixture<MongoDatabaseFixture<TUser, TKey>>
|
||||
where TUser : MongoIdentityUser<TKey>, new()
|
||||
where TKey : IEquatable<TKey>
|
||||
{
|
||||
private readonly MongoDatabaseFixture<TUser, TKey> _fixture;
|
||||
|
||||
protected SqlStoreOnlyUsersTestBase(MongoDatabaseFixture<TUser, TKey> fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
protected override bool ShouldSkipDbTests()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override TUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "",
|
||||
bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false)
|
||||
{
|
||||
var user = new TUser
|
||||
{
|
||||
UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()),
|
||||
Email = email,
|
||||
PhoneNumber = phoneNumber,
|
||||
LockoutEnabled = lockoutEnabled,
|
||||
LockoutEnd = lockoutEnd
|
||||
};
|
||||
_fixture.UsersToDelete.Add(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
protected override Expression<Func<TUser, bool>> UserNameEqualsPredicate(string userName) => u => u.UserName == userName;
|
||||
|
||||
protected override Expression<Func<TUser, bool>> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName);
|
||||
|
||||
public IMongoDbContext CreateContext()
|
||||
{
|
||||
return Container.MongoRepository.Context;
|
||||
}
|
||||
|
||||
|
||||
protected override void AddUserStore(IServiceCollection services, object context = null)
|
||||
{
|
||||
services.AddSingleton<IUserStore<TUser>>(new MongoUserOnlyStore<TUser, IMongoDbContext, TKey>(Container.MongoRepository.Context));
|
||||
}
|
||||
|
||||
protected override void SetUserPasswordHash(TUser user, string hashedPassword)
|
||||
{
|
||||
user.PasswordHash = hashedPassword;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteUserRemovesTokensTest()
|
||||
{
|
||||
// Need fail if not empty?
|
||||
var userMgr = CreateManager();
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await userMgr.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await userMgr.SetAuthenticationTokenAsync(user, "provider", "test", "value"));
|
||||
|
||||
Assert.Equal("value", await userMgr.GetAuthenticationTokenAsync(user, "provider", "test"));
|
||||
|
||||
IdentityResultAssert.IsSuccess(await userMgr.DeleteAsync(user));
|
||||
|
||||
Assert.Null(await userMgr.GetAuthenticationTokenAsync(user, "provider", "test"));
|
||||
}
|
||||
|
||||
private IQueryable<TUser> GetQueryable()
|
||||
{
|
||||
return Container.MongoRepository.Context.GetCollection<TUser>().AsQueryable();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanCreateUserUsingEF()
|
||||
{
|
||||
var user = CreateTestUser();
|
||||
Container.MongoRepository.AddOne<TUser, TKey>(user);
|
||||
Assert.True(GetQueryable().Any(u => u.UserName == user.UserName));
|
||||
Assert.NotNull(GetQueryable().FirstOrDefault(u => u.UserName == user.UserName));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanCreateUsingManager()
|
||||
{
|
||||
var manager = CreateManager();
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await manager.DeleteAsync(user));
|
||||
}
|
||||
|
||||
private async Task LazyLoadTestSetup(IMongoDbContext db, TUser user)
|
||||
{
|
||||
var context = CreateContext();
|
||||
var manager = CreateManager(context);
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, new UserLoginInfo("provider", user.Id.ToString(), "display")));
|
||||
Claim[] userClaims =
|
||||
{
|
||||
new Claim("Whatever", "Value"),
|
||||
new Claim("Whatever2", "Value2")
|
||||
};
|
||||
foreach (var c in userClaims)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, c));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LoadFromDbFindByIdTest()
|
||||
{
|
||||
var db = CreateContext();
|
||||
var user = CreateTestUser();
|
||||
await LazyLoadTestSetup(db, user);
|
||||
|
||||
db = CreateContext();
|
||||
var manager = CreateManager(db);
|
||||
|
||||
var userById = await manager.FindByIdAsync(user.Id.ToString());
|
||||
Assert.Equal(2, (await manager.GetClaimsAsync(userById)).Count);
|
||||
Assert.Equal(1, (await manager.GetLoginsAsync(userById)).Count);
|
||||
Assert.Equal(2, (await manager.GetRolesAsync(userById)).Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LoadFromDbFindByNameTest()
|
||||
{
|
||||
var db = CreateContext();
|
||||
var user = CreateTestUser();
|
||||
await LazyLoadTestSetup(db, user);
|
||||
|
||||
db = CreateContext();
|
||||
var manager = CreateManager(db);
|
||||
var userByName = await manager.FindByNameAsync(user.UserName);
|
||||
Assert.Equal(2, (await manager.GetClaimsAsync(userByName)).Count);
|
||||
Assert.Equal(1, (await manager.GetLoginsAsync(userByName)).Count);
|
||||
Assert.Equal(2, (await manager.GetRolesAsync(userByName)).Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LoadFromDbFindByLoginTest()
|
||||
{
|
||||
var db = CreateContext();
|
||||
var user = CreateTestUser();
|
||||
await LazyLoadTestSetup(db, user);
|
||||
|
||||
db = CreateContext();
|
||||
var manager = CreateManager(db);
|
||||
var userByLogin = await manager.FindByLoginAsync("provider", user.Id.ToString());
|
||||
Assert.Equal(2, (await manager.GetClaimsAsync(userByLogin)).Count);
|
||||
Assert.Equal(1, (await manager.GetLoginsAsync(userByLogin)).Count);
|
||||
Assert.Equal(2, (await manager.GetRolesAsync(userByLogin)).Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LoadFromDbFindByEmailTest()
|
||||
{
|
||||
var db = CreateContext();
|
||||
var user = CreateTestUser();
|
||||
user.Email = "fooz@fizzy.pop";
|
||||
await LazyLoadTestSetup(db, user);
|
||||
|
||||
db = CreateContext();
|
||||
var manager = CreateManager(db);
|
||||
var userByEmail = await manager.FindByEmailAsync(user.Email);
|
||||
Assert.Equal(2, (await manager.GetClaimsAsync(userByEmail)).Count);
|
||||
Assert.Equal(1, (await manager.GetLoginsAsync(userByEmail)).Count);
|
||||
Assert.Equal(2, (await manager.GetRolesAsync(userByEmail)).Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity.Test;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Xunit;
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using AspNetCore.Identity.MongoDbCore.Extensions;
|
||||
using AspNetCore.Identity.MongoDbCore;
|
||||
using MongoDB.Driver;
|
||||
using AspNetCore.Identity.MongoDbCore.IntegrationTests.Infrastructure;
|
||||
using MongoDbGenericRepository;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Test
|
||||
{
|
||||
// TODO: Add test variation with non IdentityDbContext
|
||||
|
||||
public abstract class SqlStoreTestBase<TUser, TRole, TKey> : IdentitySpecificationTestBase<TUser, TRole, TKey>,
|
||||
IClassFixture<MongoDatabaseFixture<TUser, TRole, TKey>>
|
||||
where TUser : MongoIdentityUser<TKey>, new()
|
||||
where TRole : MongoIdentityRole<TKey>, new()
|
||||
where TKey : IEquatable<TKey>
|
||||
{
|
||||
private readonly MongoDatabaseFixture<TUser, TRole, TKey> _fixture;
|
||||
|
||||
protected SqlStoreTestBase(MongoDatabaseFixture<TUser, TRole, TKey> fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
protected override void SetupIdentityServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
// configure the default type name
|
||||
services.ConfigureMongoDbIdentity<TUser, TRole, TKey>(Container.MongoDbIdentityConfiguration, Container.MongoRepository.Context);
|
||||
|
||||
services.AddLogging();
|
||||
services.AddSingleton<ILogger<UserManager<TUser>>>(new TestLogger<UserManager<TUser>>());
|
||||
services.AddSingleton<ILogger<RoleManager<TRole>>>(new TestLogger<RoleManager<TRole>>());
|
||||
}
|
||||
|
||||
protected override bool ShouldSkipDbTests()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override TUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "",
|
||||
bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false)
|
||||
{
|
||||
var user = new TUser
|
||||
{
|
||||
UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()),
|
||||
Email = email,
|
||||
PhoneNumber = phoneNumber,
|
||||
LockoutEnabled = lockoutEnabled,
|
||||
LockoutEnd = lockoutEnd
|
||||
};
|
||||
_fixture.UsersToDelete.Add(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
protected override TRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false)
|
||||
{
|
||||
var roleName = useRoleNamePrefixAsRoleName ? roleNamePrefix : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid());
|
||||
var role = new TRole() { Name = roleName };
|
||||
_fixture.RolesToDelete.Add(role);
|
||||
return role;
|
||||
}
|
||||
|
||||
protected override Expression<Func<TRole, bool>> RoleNameEqualsPredicate(string roleName) => r => r.Name == roleName;
|
||||
|
||||
protected override Expression<Func<TUser, bool>> UserNameEqualsPredicate(string userName) => u => u.UserName == userName;
|
||||
|
||||
protected override Expression<Func<TRole, bool>> RoleNameStartsWithPredicate(string roleName) => r => r.Name.StartsWith(roleName);
|
||||
|
||||
protected override Expression<Func<TUser, bool>> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName);
|
||||
|
||||
|
||||
protected override void AddUserStore(IServiceCollection services, object context = null)
|
||||
{
|
||||
services.AddSingleton<IUserStore<TUser>>(new MongoUserStore<TUser, TRole, IMongoDbContext, TKey>(Container.MongoRepository.Context));
|
||||
}
|
||||
|
||||
protected override void AddRoleStore(IServiceCollection services, object context = null)
|
||||
{
|
||||
services.AddSingleton<IRoleStore<TRole>>(new MongoRoleStore<TRole, IMongoDbContext, TKey>(Container.MongoRepository.Context));
|
||||
}
|
||||
|
||||
protected override void SetUserPasswordHash(TUser user, string hashedPassword)
|
||||
{
|
||||
user.PasswordHash = hashedPassword;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteRoleNonEmptySucceedsTest()
|
||||
{
|
||||
var userMgr = CreateManager();
|
||||
var roleMgr = CreateRoleManager();
|
||||
var roleName = "delete" + Guid.NewGuid().ToString();
|
||||
var role = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
Assert.False(await roleMgr.RoleExistsAsync(roleName));
|
||||
IdentityResultAssert.IsSuccess(await roleMgr.CreateAsync(role));
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await userMgr.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await userMgr.AddToRoleAsync(user, roleName));
|
||||
var roles = await userMgr.GetRolesAsync(user);
|
||||
Assert.Single(roles);
|
||||
IdentityResultAssert.IsSuccess(await roleMgr.DeleteAsync(role));
|
||||
Assert.Null(await roleMgr.FindByNameAsync(roleName));
|
||||
Assert.False(await roleMgr.RoleExistsAsync(roleName));
|
||||
// REVIEW: We should throw if deleteing a non empty role?
|
||||
roles = await userMgr.GetRolesAsync(user);
|
||||
|
||||
Assert.Empty(roles);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteUserRemovesFromRoleTest()
|
||||
{
|
||||
// Need fail if not empty?
|
||||
var userMgr = CreateManager();
|
||||
var roleMgr = CreateRoleManager();
|
||||
var roleName = "deleteUserRemove" + Guid.NewGuid().ToString();
|
||||
var role = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
Assert.False(await roleMgr.RoleExistsAsync(roleName));
|
||||
IdentityResultAssert.IsSuccess(await roleMgr.CreateAsync(role));
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await userMgr.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await userMgr.AddToRoleAsync(user, roleName));
|
||||
|
||||
var roles = await userMgr.GetRolesAsync(user);
|
||||
Assert.Single(roles);
|
||||
|
||||
IdentityResultAssert.IsSuccess(await userMgr.DeleteAsync(user));
|
||||
|
||||
roles = await userMgr.GetRolesAsync(user);
|
||||
Assert.Empty(roles);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteUserRemovesTokensTest()
|
||||
{
|
||||
// Need fail if not empty?
|
||||
var userMgr = CreateManager();
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await userMgr.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await userMgr.SetAuthenticationTokenAsync(user, "provider", "test", "value"));
|
||||
|
||||
Assert.Equal("value", await userMgr.GetAuthenticationTokenAsync(user, "provider", "test"));
|
||||
|
||||
IdentityResultAssert.IsSuccess(await userMgr.DeleteAsync(user));
|
||||
|
||||
Assert.Null(await userMgr.GetAuthenticationTokenAsync(user, "provider", "test"));
|
||||
}
|
||||
|
||||
private IQueryable<TUser> GetQueryable()
|
||||
{
|
||||
return Container.MongoRepository.Context.GetCollection<TUser>().AsQueryable();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanCreateUserUsingEF()
|
||||
{
|
||||
var user = CreateTestUser();
|
||||
Container.MongoRepository.AddOne<TUser, TKey>(user);
|
||||
Assert.True(GetQueryable().Any(u => u.UserName == user.UserName));
|
||||
Assert.NotNull(GetQueryable().FirstOrDefault(u => u.UserName == user.UserName));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanCreateUsingManager()
|
||||
{
|
||||
var manager = CreateManager();
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await manager.DeleteAsync(user));
|
||||
}
|
||||
|
||||
private async Task LazyLoadTestSetup(TUser user)
|
||||
{
|
||||
var manager = CreateManager();
|
||||
var role = CreateRoleManager();
|
||||
var admin = CreateTestRole("Admin" + Guid.NewGuid().ToString());
|
||||
var local = CreateTestRole("Local" + Guid.NewGuid().ToString());
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, new UserLoginInfo("provider", user.Id.ToString(), "display")));
|
||||
IdentityResultAssert.IsSuccess(await role.CreateAsync(admin));
|
||||
IdentityResultAssert.IsSuccess(await role.CreateAsync(local));
|
||||
IdentityResultAssert.IsSuccess(await manager.AddToRoleAsync(user, admin.Name));
|
||||
IdentityResultAssert.IsSuccess(await manager.AddToRoleAsync(user, local.Name));
|
||||
Claim[] userClaims =
|
||||
{
|
||||
new Claim("Whatever", "Value"),
|
||||
new Claim("Whatever2", "Value2")
|
||||
};
|
||||
foreach (var c in userClaims)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, c));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LoadFromDbFindByIdTest()
|
||||
{
|
||||
var user = CreateTestUser();
|
||||
await LazyLoadTestSetup(user);
|
||||
|
||||
var manager = CreateManager();
|
||||
|
||||
var userById = await manager.FindByIdAsync(user.Id.ToString());
|
||||
Assert.Equal(2, (await manager.GetClaimsAsync(userById)).Count);
|
||||
Assert.Equal(1, (await manager.GetLoginsAsync(userById)).Count);
|
||||
Assert.Equal(2, (await manager.GetRolesAsync(userById)).Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LoadFromDbFindByNameTest()
|
||||
{
|
||||
var user = CreateTestUser();
|
||||
await LazyLoadTestSetup(user);
|
||||
var manager = CreateManager();
|
||||
var userByName = await manager.FindByNameAsync(user.UserName);
|
||||
Assert.Equal(2, (await manager.GetClaimsAsync(userByName)).Count);
|
||||
Assert.Equal(1, (await manager.GetLoginsAsync(userByName)).Count);
|
||||
Assert.Equal(2, (await manager.GetRolesAsync(userByName)).Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LoadFromDbFindByLoginTest()
|
||||
{
|
||||
var user = CreateTestUser();
|
||||
await LazyLoadTestSetup(user);
|
||||
|
||||
var manager = CreateManager();
|
||||
var userByLogin = await manager.FindByLoginAsync("provider", user.Id.ToString());
|
||||
Assert.Equal(2, (await manager.GetClaimsAsync(userByLogin)).Count);
|
||||
Assert.Equal(1, (await manager.GetLoginsAsync(userByLogin)).Count);
|
||||
Assert.Equal(2, (await manager.GetRolesAsync(userByLogin)).Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LoadFromDbFindByEmailTest()
|
||||
{
|
||||
var user = CreateTestUser();
|
||||
user.Email = "fooz@fizzy.pop";
|
||||
await LazyLoadTestSetup(user);
|
||||
|
||||
var manager = CreateManager();
|
||||
var userByEmail = await manager.FindByEmailAsync(user.Email);
|
||||
Assert.Equal(2, (await manager.GetClaimsAsync(userByEmail)).Count);
|
||||
Assert.Equal(1, (await manager.GetLoginsAsync(userByEmail)).Count);
|
||||
Assert.Equal(2, (await manager.GetRolesAsync(userByEmail)).Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using AspNetCore.Identity.MongoDbCore;
|
||||
using MongoDbGenericRepository;
|
||||
using AspNetCore.Identity.MongoDbCore.IntegrationTests.Infrastructure;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Test
|
||||
{
|
||||
public class GuidUser : MongoIdentityUser<Guid>
|
||||
{
|
||||
public GuidUser() : base()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class GuidRole : MongoIdentityRole<Guid>
|
||||
{
|
||||
public GuidRole() : base()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class UserStoreGuidTest : SqlStoreTestBase<GuidUser, GuidRole, Guid>
|
||||
{
|
||||
public UserStoreGuidTest(MongoDatabaseFixture<GuidUser, GuidRole, Guid> fixture)
|
||||
: base(fixture)
|
||||
{
|
||||
}
|
||||
|
||||
public class ApplicationUserStore : MongoUserStore<GuidUser, GuidRole, IMongoDbContext, Guid>
|
||||
{
|
||||
public ApplicationUserStore(IMongoDbContext context) : base(Container.MongoRepository.Context) { }
|
||||
}
|
||||
|
||||
public class ApplicationRoleStore : MongoRoleStore<GuidRole, IMongoDbContext, Guid>
|
||||
{
|
||||
public ApplicationRoleStore(IMongoDbContext context) : base(Container.MongoRepository.Context) { }
|
||||
}
|
||||
|
||||
protected override void AddUserStore(IServiceCollection services, object context = null)
|
||||
{
|
||||
services.AddSingleton<IUserStore<GuidUser>>(new ApplicationUserStore(Container.MongoRepository.Context));
|
||||
}
|
||||
|
||||
protected override void AddRoleStore(IServiceCollection services, object context = null)
|
||||
{
|
||||
services.AddSingleton<IRoleStore<GuidRole>>(new ApplicationRoleStore(Container.MongoRepository.Context));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Test
|
||||
{
|
||||
public class IntUser : MongoIdentityUser<int>
|
||||
{
|
||||
public IntUser() : base()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class IntRole : MongoIdentityRole<int>
|
||||
{
|
||||
public IntRole() : base()
|
||||
{
|
||||
Name = Guid.NewGuid().ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class UserStoreIntTest : SqlStoreTestBase<IntUser, IntRole, int>
|
||||
{
|
||||
public UserStoreIntTest(MongoDatabaseFixture<IntUser, IntRole, int> fixture)
|
||||
: base(fixture)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Test
|
||||
{
|
||||
public class StringUser : MongoDbIdentityUser
|
||||
{
|
||||
public StringUser() : base()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class StringRole : MongoDbIdentityRole
|
||||
{
|
||||
public StringRole() : base()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class UserStoreStringKeyTest : SqlStoreTestBase<StringUser, StringRole, string>
|
||||
{
|
||||
public UserStoreStringKeyTest(MongoDatabaseFixture<StringUser, StringRole, string> fixture)
|
||||
: base(fixture)
|
||||
{ }
|
||||
|
||||
}
|
||||
}
|
||||
+364
@@ -0,0 +1,364 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity.Test;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using AspNetCore.Identity.MongoDbCore;
|
||||
using MongoDB.Driver;
|
||||
using AspNetCore.Identity.MongoDbCore.IntegrationTests.Infrastructure;
|
||||
using AspNetCore.Identity.MongoDbCore.Infrastructure;
|
||||
using MongoDbGenericRepository;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Test
|
||||
{
|
||||
|
||||
public class ApplicationDbContext : MongoIdentityDbContext<ApplicationUser>
|
||||
{
|
||||
public ApplicationDbContext(string connectionString, string databaseName) : base(connectionString, databaseName)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Applicationcontext
|
||||
{
|
||||
public static ApplicationDbContext Instance = new ApplicationDbContext(
|
||||
Container.MongoDbIdentityConfiguration.MongoDbSettings.ConnectionString,
|
||||
Container.MongoDbIdentityConfiguration.MongoDbSettings.DatabaseName);
|
||||
}
|
||||
|
||||
public class UserStoreTest : IdentitySpecificationTestBase<MongoDbIdentityUser, MongoDbIdentityRole>, IClassFixture<MongoDatabaseFixture<MongoDbIdentityUser, MongoDbIdentityRole, string>>
|
||||
{
|
||||
private readonly MongoDatabaseFixture<MongoDbIdentityUser, MongoDbIdentityRole,string> _fixture;
|
||||
|
||||
public UserStoreTest(MongoDatabaseFixture<MongoDbIdentityUser, MongoDbIdentityRole,string> fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
protected override bool ShouldSkipDbTests()
|
||||
=> false;
|
||||
|
||||
[Fact]
|
||||
public void CanCreateUserUsingEF()
|
||||
{
|
||||
var user = CreateTestUser();
|
||||
user.Id = Guid.NewGuid().ToString();
|
||||
var guidString = user.Id.ToString();
|
||||
user.UserName = guidString;
|
||||
Container.MongoRepository.AddOne<MongoDbIdentityUser, string>(user);
|
||||
Assert.True(Container.MongoRepository.Any<MongoDbIdentityUser, string>(u => u.UserName == guidString));
|
||||
Assert.NotNull(Container.MongoRepository.GetOne<MongoDbIdentityUser, string>(u => u.UserName == guidString));
|
||||
}
|
||||
|
||||
protected override void AddUserStore(IServiceCollection services, object context = null)
|
||||
{
|
||||
services.AddSingleton<IUserStore<MongoDbIdentityUser>>(new MongoUserStore<MongoDbIdentityUser, MongoDbIdentityRole, IMongoDbContext, string>(Container.MongoRepository.Context));
|
||||
}
|
||||
|
||||
protected override void AddRoleStore(IServiceCollection services, object context = null)
|
||||
{
|
||||
services.AddSingleton<IRoleStore<MongoDbIdentityRole>>(new MongoRoleStore<MongoDbIdentityRole, IMongoDbContext>(Container.MongoRepository.Context));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SqlUserStoreMethodsThrowWhenDisposedTest()
|
||||
{
|
||||
var store = new MongoUserStore(Container.MongoRepository.Context);
|
||||
store.Dispose();
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.AddClaimsAsync(null, null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.AddLoginAsync(null, null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.AddToRoleAsync(null, null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.GetClaimsAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.GetLoginsAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.GetRolesAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.IsInRoleAsync(null, null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.RemoveClaimsAsync(null, null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.RemoveLoginAsync(null, null, null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(
|
||||
async () => await store.RemoveFromRoleAsync(null, null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.RemoveClaimsAsync(null, null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.ReplaceClaimAsync(null, null, null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.FindByLoginAsync(null, null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.FindByIdAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.FindByNameAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.CreateAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.UpdateAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.DeleteAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(
|
||||
async () => await store.SetEmailConfirmedAsync(null, true));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(async () => await store.GetEmailConfirmedAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(
|
||||
async () => await store.SetPhoneNumberConfirmedAsync(null, true));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(
|
||||
async () => await store.GetPhoneNumberConfirmedAsync(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UserStorePublicNullCheckTest()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>("context", () => new MongoUserStore(null));
|
||||
var store = new MongoUserStore(Container.MongoRepository.Context);
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetUserIdAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetUserNameAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.SetUserNameAsync(null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.CreateAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.UpdateAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.DeleteAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.AddClaimsAsync(null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.ReplaceClaimAsync(null, null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.RemoveClaimsAsync(null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetClaimsAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetLoginsAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetRolesAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.AddLoginAsync(null, null));
|
||||
await
|
||||
Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.RemoveLoginAsync(null, null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.AddToRoleAsync(null, null));
|
||||
await
|
||||
Assert.ThrowsAsync<ArgumentNullException>("user",
|
||||
async () => await store.RemoveFromRoleAsync(null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.IsInRoleAsync(null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetPasswordHashAsync(null));
|
||||
await
|
||||
Assert.ThrowsAsync<ArgumentNullException>("user",
|
||||
async () => await store.SetPasswordHashAsync(null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetSecurityStampAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user",
|
||||
async () => await store.SetSecurityStampAsync(null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("login", async () => await store.AddLoginAsync(new MongoDbIdentityUser("fake"), null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("claims",
|
||||
async () => await store.AddClaimsAsync(new MongoDbIdentityUser("fake"), null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("claims",
|
||||
async () => await store.RemoveClaimsAsync(new MongoDbIdentityUser("fake"), null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetEmailConfirmedAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user",
|
||||
async () => await store.SetEmailConfirmedAsync(null, true));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetEmailAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.SetEmailAsync(null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetPhoneNumberAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.SetPhoneNumberAsync(null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user",
|
||||
async () => await store.GetPhoneNumberConfirmedAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user",
|
||||
async () => await store.SetPhoneNumberConfirmedAsync(null, true));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetTwoFactorEnabledAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user",
|
||||
async () => await store.SetTwoFactorEnabledAsync(null, true));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetAccessFailedCountAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetLockoutEnabledAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.SetLockoutEnabledAsync(null, false));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.GetLockoutEndDateAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.SetLockoutEndDateAsync(null, new DateTimeOffset()));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.ResetAccessFailedCountAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", async () => await store.IncrementAccessFailedCountAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentException>("normalizedRoleName", async () => await store.AddToRoleAsync(new MongoDbIdentityUser("fake"), null));
|
||||
await Assert.ThrowsAsync<ArgumentException>("normalizedRoleName", async () => await store.RemoveFromRoleAsync(new MongoDbIdentityUser("fake"), null));
|
||||
await Assert.ThrowsAsync<ArgumentException>("normalizedRoleName", async () => await store.IsInRoleAsync(new MongoDbIdentityUser("fake"), null));
|
||||
await Assert.ThrowsAsync<ArgumentException>("normalizedRoleName", async () => await store.AddToRoleAsync(new MongoDbIdentityUser("fake"), ""));
|
||||
await Assert.ThrowsAsync<ArgumentException>("normalizedRoleName", async () => await store.RemoveFromRoleAsync(new MongoDbIdentityUser("fake"), ""));
|
||||
await Assert.ThrowsAsync<ArgumentException>("normalizedRoleName", async () => await store.IsInRoleAsync(new MongoDbIdentityUser("fake"), ""));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanCreateUsingManager()
|
||||
{
|
||||
var manager = CreateManager();
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await manager.DeleteAsync(user));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TwoUsersSamePasswordDifferentHash()
|
||||
{
|
||||
var manager = CreateManager();
|
||||
var userA = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(userA, "password"));
|
||||
var userB = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(userB, "password"));
|
||||
|
||||
Assert.NotEqual(userA.PasswordHash, userB.PasswordHash);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddUserToUnknownRoleFails()
|
||||
{
|
||||
var manager = CreateManager();
|
||||
var u = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(u));
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
async () => await manager.AddToRoleAsync(u, "bogus"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ConcurrentUpdatesWillFail()
|
||||
{
|
||||
var user = CreateTestUser();
|
||||
var manager = CreateManager();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
var manager1 = CreateManager();
|
||||
var manager2 = CreateManager();
|
||||
var user1 = await manager1.FindByIdAsync(user.Id);
|
||||
var user2 = await manager2.FindByIdAsync(user.Id);
|
||||
Assert.NotNull(user1);
|
||||
Assert.NotNull(user2);
|
||||
Assert.NotSame(user1, user2);
|
||||
user1.UserName = Guid.NewGuid().ToString();
|
||||
user2.UserName = Guid.NewGuid().ToString();
|
||||
IdentityResultAssert.IsSuccess(await manager1.UpdateAsync(user1));
|
||||
IdentityResultAssert.IsFailure(await manager2.UpdateAsync(user2), new IdentityErrorDescriber().ConcurrencyFailure());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ConcurrentUpdatesWillFailWithDetachedUser()
|
||||
{
|
||||
var user = CreateTestUser();
|
||||
var manager = CreateManager();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
var manager1 = CreateManager();
|
||||
var manager2 = CreateManager();
|
||||
var user2 = await manager2.FindByIdAsync(user.Id);
|
||||
Assert.NotNull(user2);
|
||||
Assert.NotSame(user, user2);
|
||||
user.UserName = Guid.NewGuid().ToString();
|
||||
user2.UserName = Guid.NewGuid().ToString();
|
||||
IdentityResultAssert.IsSuccess(await manager1.UpdateAsync(user));
|
||||
IdentityResultAssert.IsFailure(await manager2.UpdateAsync(user2), new IdentityErrorDescriber().ConcurrencyFailure());
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteAModifiedUserWillFail()
|
||||
{
|
||||
var user = CreateTestUser();
|
||||
|
||||
var manager = CreateManager();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
|
||||
var manager1 = CreateManager();
|
||||
var manager2 = CreateManager();
|
||||
var user1 = await manager1.FindByIdAsync(user.Id);
|
||||
var user2 = await manager2.FindByIdAsync(user.Id);
|
||||
Assert.NotNull(user1);
|
||||
Assert.NotNull(user2);
|
||||
Assert.NotSame(user1, user2);
|
||||
user1.UserName = Guid.NewGuid().ToString();
|
||||
IdentityResultAssert.IsSuccess(await manager1.UpdateAsync(user1));
|
||||
IdentityResultAssert.IsFailure(await manager2.DeleteAsync(user2), new IdentityErrorDescriber().ConcurrencyFailure());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ConcurrentRoleUpdatesWillFail()
|
||||
{
|
||||
var role = CreateRole();
|
||||
|
||||
var manager = CreateRoleManager();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
|
||||
|
||||
var manager1 = CreateRoleManager();
|
||||
var manager2 = CreateRoleManager();
|
||||
var role1 = await manager1.FindByIdAsync(role.Id);
|
||||
var role2 = await manager2.FindByIdAsync(role.Id);
|
||||
Assert.NotNull(role1);
|
||||
Assert.NotNull(role2);
|
||||
Assert.NotSame(role1, role2);
|
||||
role1.Name = Guid.NewGuid().ToString();
|
||||
role2.Name = Guid.NewGuid().ToString();
|
||||
IdentityResultAssert.IsSuccess(await manager1.UpdateAsync(role1));
|
||||
IdentityResultAssert.IsFailure(await manager2.UpdateAsync(role2), new IdentityErrorDescriber().ConcurrencyFailure());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ConcurrentRoleUpdatesWillFailWithDetachedRole()
|
||||
{
|
||||
var role = CreateRole();
|
||||
var manager = CreateRoleManager();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
|
||||
var manager1 = CreateRoleManager();
|
||||
var manager2 = CreateRoleManager();
|
||||
var role2 = await manager2.FindByIdAsync(role.Id);
|
||||
Assert.NotNull(role);
|
||||
Assert.NotNull(role2);
|
||||
Assert.NotSame(role, role2);
|
||||
role.Name = Guid.NewGuid().ToString();
|
||||
role2.Name = Guid.NewGuid().ToString();
|
||||
IdentityResultAssert.IsSuccess(await manager1.UpdateAsync(role));
|
||||
IdentityResultAssert.IsFailure(await manager2.UpdateAsync(role2), new IdentityErrorDescriber().ConcurrencyFailure());
|
||||
}
|
||||
|
||||
private MongoDbIdentityRole CreateRole()
|
||||
{
|
||||
var guid = Guid.NewGuid().ToString();
|
||||
var role = new MongoDbIdentityRole(guid);
|
||||
_fixture.RolesToDelete.Add(role);
|
||||
return role;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteAModifiedRoleWillFail()
|
||||
{
|
||||
var role = CreateRole();
|
||||
var manager = CreateRoleManager();
|
||||
var result = await manager.CreateAsync(role);
|
||||
|
||||
IdentityResultAssert.IsSuccess(result);
|
||||
|
||||
var manager1 = CreateRoleManager();
|
||||
var manager2 = CreateRoleManager(true);
|
||||
var role1 = await manager1.FindByIdAsync(role.Id);
|
||||
var role2 = await manager2.FindByIdAsync(role.Id);
|
||||
Assert.NotNull(role1);
|
||||
Assert.NotNull(role2);
|
||||
Assert.NotSame(role1, role2);
|
||||
role1.Name = Guid.NewGuid().ToString();
|
||||
IdentityResultAssert.IsSuccess(await manager1.UpdateAsync(role1));
|
||||
IdentityResultAssert.IsFailure(await manager2.DeleteAsync(role2), new IdentityErrorDescriber().ConcurrencyFailure());
|
||||
}
|
||||
|
||||
protected override MongoDbIdentityUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "",
|
||||
bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false)
|
||||
{
|
||||
var user = new MongoDbIdentityUser
|
||||
{
|
||||
UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()),
|
||||
Email = email,
|
||||
PhoneNumber = phoneNumber,
|
||||
LockoutEnabled = lockoutEnabled,
|
||||
LockoutEnd = lockoutEnd
|
||||
};
|
||||
_fixture.UsersToDelete.Add(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
protected override MongoDbIdentityRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false)
|
||||
{
|
||||
var roleName = useRoleNamePrefixAsRoleName ? roleNamePrefix : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid());
|
||||
var role = new MongoDbIdentityRole(roleName);
|
||||
_fixture.RolesToDelete.Add(role);
|
||||
return role;
|
||||
}
|
||||
|
||||
protected override void SetUserPasswordHash(MongoDbIdentityUser user, string hashedPassword)
|
||||
{
|
||||
user.PasswordHash = hashedPassword;
|
||||
}
|
||||
|
||||
protected override Expression<Func<MongoDbIdentityUser, bool>> UserNameEqualsPredicate(string userName) => u => u.UserName == userName;
|
||||
|
||||
protected override Expression<Func<MongoDbIdentityRole, bool>> RoleNameEqualsPredicate(string roleName) => r => r.Name == roleName;
|
||||
|
||||
protected override Expression<Func<MongoDbIdentityRole, bool>> RoleNameStartsWithPredicate(string roleName) => r => r.Name.StartsWith(roleName);
|
||||
|
||||
protected override Expression<Func<MongoDbIdentityUser, bool>> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName);
|
||||
|
||||
}
|
||||
|
||||
public class ApplicationUser : MongoIdentityUser { }
|
||||
}
|
||||
+353
@@ -0,0 +1,353 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity.Test;
|
||||
//using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using AspNetCore.Identity.MongoDbCore;
|
||||
using AspNetCore.Identity.MongoDbCore.IntegrationTests.Infrastructure;
|
||||
using MongoDbGenericRepository;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Test
|
||||
{
|
||||
public class UserStoreWithGenericsTest : IdentitySpecificationTestBase<IdentityUserWithGenerics, MyIdentityRole, string>, IClassFixture<MongoDatabaseFixture<IdentityUserWithGenerics, MyIdentityRole, string>>
|
||||
{
|
||||
private readonly MongoDatabaseFixture<IdentityUserWithGenerics, MyIdentityRole, string> _fixture;
|
||||
|
||||
public UserStoreWithGenericsTest(MongoDatabaseFixture<IdentityUserWithGenerics, MyIdentityRole, string> fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
protected override bool ShouldSkipDbTests()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void AddUserStore(IServiceCollection services, object context = null)
|
||||
{
|
||||
services.AddSingleton<IUserStore<IdentityUserWithGenerics>>(new MongoUserStore<IdentityUserWithGenerics>(Container.MongoRepository.Context));
|
||||
//services.AddSingleton<IUserStore<IdentityUserWithGenerics>>(new UserStoreWithGenerics((ContextWithGenerics)context, "TestContext"));
|
||||
}
|
||||
|
||||
protected override void AddRoleStore(IServiceCollection services, object context = null)
|
||||
{
|
||||
services.AddSingleton<IRoleStore<MyIdentityRole>>(new MongoRoleStore<MyIdentityRole>(Container.MongoRepository.Context));
|
||||
//services.AddSingleton<IRoleStore<MyIdentityRole>>(new RoleStoreWithGenerics(Container.MongoRepository.Context, "TestContext"));
|
||||
}
|
||||
|
||||
protected override IdentityUserWithGenerics CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "",
|
||||
bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false)
|
||||
{
|
||||
var user = new IdentityUserWithGenerics
|
||||
{
|
||||
UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()),
|
||||
Email = email,
|
||||
PhoneNumber = phoneNumber,
|
||||
LockoutEnabled = lockoutEnabled,
|
||||
LockoutEnd = lockoutEnd
|
||||
};
|
||||
_fixture.UsersToDelete.Add(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
protected override MyIdentityRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false)
|
||||
{
|
||||
var roleName = useRoleNamePrefixAsRoleName ? roleNamePrefix : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid());
|
||||
var role = new MyIdentityRole(roleName);
|
||||
_fixture.RolesToDelete.Add(role);
|
||||
return role;
|
||||
}
|
||||
|
||||
protected override void SetUserPasswordHash(IdentityUserWithGenerics user, string hashedPassword)
|
||||
{
|
||||
user.PasswordHash = hashedPassword;
|
||||
}
|
||||
|
||||
protected override Expression<Func<IdentityUserWithGenerics, bool>> UserNameEqualsPredicate(string userName) => u => u.UserName == userName;
|
||||
|
||||
protected override Expression<Func<MyIdentityRole, bool>> RoleNameEqualsPredicate(string roleName) => r => r.Name == roleName;
|
||||
|
||||
protected override Expression<Func<IdentityUserWithGenerics, bool>> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName);
|
||||
|
||||
protected override Expression<Func<MyIdentityRole, bool>> RoleNameStartsWithPredicate(string roleName) => r => r.Name.StartsWith(roleName);
|
||||
|
||||
[Fact]
|
||||
public void AddEntityFrameworkStoresWithInvalidUserThrows()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
var builder = services.AddIdentity<object, IdentityRole>();
|
||||
var e = Assert.Throws<InvalidOperationException>(() =>
|
||||
//builder.AddEntityFrameworkStores<ContextWithGenerics>()
|
||||
Throw()
|
||||
);
|
||||
Assert.Contains("AddEntityFrameworkStores", e.Message);
|
||||
}
|
||||
|
||||
private void Throw()
|
||||
{
|
||||
throw new InvalidOperationException("AddEntityFrameworkStores");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddEntityFrameworkStoresWithInvalidRoleThrows()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
var builder = services.AddIdentity<IdentityUser, object>();
|
||||
var e = Assert.Throws<InvalidOperationException>(() => {
|
||||
//builder.AddEntityFrameworkStores<ContextWithGenerics>();
|
||||
Throw();
|
||||
});
|
||||
Assert.Contains("AddEntityFrameworkStores", e.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanAddRemoveUserClaimWithIssuer()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateManager();
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
Claim[] claims = { new Claim("c1", "v1", null, "i1"), new Claim("c2", "v2", null, "i2"), new Claim("c2", "v3", null, "i3") };
|
||||
foreach (Claim c in claims)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, c));
|
||||
}
|
||||
|
||||
var userId = await manager.GetUserIdAsync(user);
|
||||
var userClaims = await manager.GetClaimsAsync(user);
|
||||
Assert.Equal(3, userClaims.Count);
|
||||
Assert.Equal(3, userClaims.Intersect(claims, ClaimEqualityComparer.Default).Count());
|
||||
|
||||
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[0]));
|
||||
userClaims = await manager.GetClaimsAsync(user);
|
||||
Assert.Equal(2, userClaims.Count);
|
||||
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[1]));
|
||||
userClaims = await manager.GetClaimsAsync(user);
|
||||
Assert.Equal(1, userClaims.Count);
|
||||
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[2]));
|
||||
userClaims = await manager.GetClaimsAsync(user);
|
||||
Assert.Equal(0, userClaims.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveClaimWithIssuerOnlyAffectsUser()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateManager();
|
||||
var user = CreateTestUser();
|
||||
var user2 = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user2));
|
||||
Claim[] claims = { new Claim("c", "v", null, "i1"), new Claim("c2", "v2", null, "i2"), new Claim("c2", "v3", null, "i3") };
|
||||
foreach (Claim c in claims)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, c));
|
||||
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user2, c));
|
||||
}
|
||||
var userClaims = await manager.GetClaimsAsync(user);
|
||||
Assert.Equal(3, userClaims.Count);
|
||||
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[0]));
|
||||
userClaims = await manager.GetClaimsAsync(user);
|
||||
Assert.Equal(2, userClaims.Count);
|
||||
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[1]));
|
||||
userClaims = await manager.GetClaimsAsync(user);
|
||||
Assert.Equal(1, userClaims.Count);
|
||||
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[2]));
|
||||
userClaims = await manager.GetClaimsAsync(user);
|
||||
Assert.Equal(0, userClaims.Count);
|
||||
var userClaims2 = await manager.GetClaimsAsync(user2);
|
||||
Assert.Equal(3, userClaims2.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanReplaceUserClaimWithIssuer()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateManager();
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, new Claim("c", "a", "i")));
|
||||
var userClaims = await manager.GetClaimsAsync(user);
|
||||
Assert.Equal(1, userClaims.Count);
|
||||
Claim claim = new Claim("c", "b", "i");
|
||||
Claim oldClaim = userClaims.FirstOrDefault();
|
||||
IdentityResultAssert.IsSuccess(await manager.ReplaceClaimAsync(user, oldClaim, claim));
|
||||
var newUserClaims = await manager.GetClaimsAsync(user);
|
||||
Assert.Equal(1, newUserClaims.Count);
|
||||
Claim newClaim = newUserClaims.FirstOrDefault();
|
||||
Assert.Equal(claim.Type, newClaim.Type);
|
||||
Assert.Equal(claim.Value, newClaim.Value);
|
||||
Assert.Equal(claim.Issuer, newClaim.Issuer);
|
||||
}
|
||||
}
|
||||
|
||||
public class ClaimEqualityComparer : IEqualityComparer<Claim>
|
||||
{
|
||||
public static IEqualityComparer<Claim> Default = new ClaimEqualityComparer();
|
||||
|
||||
public bool Equals(Claim x, Claim y)
|
||||
{
|
||||
return x.Value == y.Value && x.Type == y.Type && x.Issuer == y.Issuer;
|
||||
}
|
||||
|
||||
public int GetHashCode(Claim obj)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Generic Type defintions
|
||||
|
||||
public class IdentityUserWithGenerics : MongoDbIdentityUser
|
||||
{
|
||||
public IdentityUserWithGenerics() : base()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class UserStoreWithGenerics : MongoUserStore<IdentityUserWithGenerics, MyIdentityRole, IMongoDbContext, string, IdentityUserClaimWithIssuer, IdentityUserRoleWithDate, IdentityUserLoginWithContext, IdentityUserTokenWithStuff, IdentityRoleClaimWithIssuer>
|
||||
{
|
||||
public string LoginContext { get; set; }
|
||||
|
||||
public UserStoreWithGenerics(IMongoDbContext context, string loginContext) : base(context)
|
||||
{
|
||||
LoginContext = loginContext;
|
||||
}
|
||||
|
||||
protected override IdentityUserRoleWithDate CreateUserRole(IdentityUserWithGenerics user, MyIdentityRole role)
|
||||
{
|
||||
return new IdentityUserRoleWithDate()
|
||||
{
|
||||
RoleId = role.Id,
|
||||
UserId = user.Id,
|
||||
Created = DateTime.UtcNow
|
||||
};
|
||||
}
|
||||
|
||||
protected override IdentityUserClaimWithIssuer CreateUserClaim(IdentityUserWithGenerics user, Claim claim)
|
||||
{
|
||||
return new IdentityUserClaimWithIssuer { UserId = user.Id, ClaimType = claim.Type, ClaimValue = claim.Value, Issuer = claim.Issuer };
|
||||
}
|
||||
|
||||
protected override IdentityUserLoginWithContext CreateUserLogin(IdentityUserWithGenerics user, UserLoginInfo login)
|
||||
{
|
||||
return new IdentityUserLoginWithContext
|
||||
{
|
||||
UserId = user.Id,
|
||||
ProviderKey = login.ProviderKey,
|
||||
LoginProvider = login.LoginProvider,
|
||||
ProviderDisplayName = login.ProviderDisplayName,
|
||||
Context = LoginContext
|
||||
};
|
||||
}
|
||||
|
||||
protected override IdentityUserTokenWithStuff CreateUserToken(IdentityUserWithGenerics user, string loginProvider, string name, string value)
|
||||
{
|
||||
return new IdentityUserTokenWithStuff
|
||||
{
|
||||
UserId = user.Id,
|
||||
LoginProvider = loginProvider,
|
||||
Name = name,
|
||||
Value = value,
|
||||
Stuff = "stuff"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class RoleStoreWithGenerics : MongoRoleStore<MyIdentityRole, IMongoDbContext, string, IdentityUserRoleWithDate, IdentityRoleClaimWithIssuer>
|
||||
{
|
||||
private string _loginContext;
|
||||
public RoleStoreWithGenerics(IMongoDbContext context, string loginContext) : base(context)
|
||||
{
|
||||
_loginContext = loginContext;
|
||||
}
|
||||
|
||||
protected override IdentityRoleClaimWithIssuer CreateRoleClaim(MyIdentityRole role, Claim claim)
|
||||
{
|
||||
return new IdentityRoleClaimWithIssuer { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value, Issuer = claim.Issuer };
|
||||
}
|
||||
}
|
||||
|
||||
public class IdentityUserClaimWithIssuer : IdentityUserClaim<string>
|
||||
{
|
||||
public string Issuer { get; set; }
|
||||
|
||||
public override Claim ToClaim()
|
||||
{
|
||||
return new Claim(ClaimType, ClaimValue, null, Issuer);
|
||||
}
|
||||
|
||||
public override void InitializeFromClaim(Claim other)
|
||||
{
|
||||
ClaimValue = other.Value;
|
||||
ClaimType = other.Type;
|
||||
Issuer = other.Issuer;
|
||||
}
|
||||
}
|
||||
|
||||
public class IdentityRoleClaimWithIssuer : IdentityRoleClaim<string>
|
||||
{
|
||||
public string Issuer { get; set; }
|
||||
|
||||
public override Claim ToClaim()
|
||||
{
|
||||
return new Claim(ClaimType, ClaimValue, null, Issuer);
|
||||
}
|
||||
|
||||
public override void InitializeFromClaim(Claim other)
|
||||
{
|
||||
ClaimValue = other.Value;
|
||||
ClaimType = other.Type;
|
||||
Issuer = other.Issuer;
|
||||
}
|
||||
}
|
||||
|
||||
public class IdentityUserRoleWithDate : IdentityUserRole<string>
|
||||
{
|
||||
public DateTime Created { get; set; }
|
||||
}
|
||||
|
||||
public class MyIdentityRole : MongoDbIdentityRole
|
||||
{
|
||||
public MyIdentityRole() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public MyIdentityRole(string roleName) : base(roleName)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class IdentityUserTokenWithStuff : IdentityUserToken<string>
|
||||
{
|
||||
public string Stuff { get; set; }
|
||||
}
|
||||
|
||||
public class IdentityUserLoginWithContext : IdentityUserLogin<string>
|
||||
{
|
||||
public string Context { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using MongoDbGenericRepository;
|
||||
using AspNetCore.Identity.MongoDbCore.IntegrationTests.Infrastructure;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using MongoDB.Driver;
|
||||
using MongoDbGenericRepository.Models;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Test
|
||||
{
|
||||
public class MongoDatabaseFixture<TUser, TKey> : IDisposable
|
||||
where TUser : IDocument<TKey>
|
||||
where TKey : IEquatable<TKey>
|
||||
{
|
||||
|
||||
public IMongoDbContext Context;
|
||||
|
||||
public MongoDatabaseFixture()
|
||||
{
|
||||
Context = new MongoDbContext(
|
||||
Container.MongoDbIdentityConfiguration.MongoDbSettings.ConnectionString,
|
||||
Container.MongoDbIdentityConfiguration.MongoDbSettings.DatabaseName);
|
||||
UsersToDelete = new ConcurrentBag<TUser>();
|
||||
}
|
||||
public ConcurrentBag<TUser> UsersToDelete { get; set; }
|
||||
public virtual void Dispose()
|
||||
{
|
||||
var userIds = UsersToDelete.ToList().Select(e => e.Id);
|
||||
if (userIds.Any())
|
||||
{
|
||||
Context.GetCollection<TUser>().DeleteMany(e => userIds.Contains(e.Id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MongoDatabaseFixture<TUser, TRole, TKey> : MongoDatabaseFixture<TUser, TKey>, IDisposable
|
||||
where TUser : IDocument<TKey>
|
||||
where TRole : IDocument<TKey>
|
||||
where TKey : IEquatable<TKey>
|
||||
{
|
||||
|
||||
public MongoDatabaseFixture()
|
||||
{
|
||||
Context = new MongoDbContext(
|
||||
Container.MongoDbIdentityConfiguration.MongoDbSettings.ConnectionString,
|
||||
Container.MongoDbIdentityConfiguration.MongoDbSettings.DatabaseName);
|
||||
UsersToDelete = new ConcurrentBag<TUser>();
|
||||
RolesToDelete = new ConcurrentBag<TRole>();
|
||||
}
|
||||
public ConcurrentBag<TRole> RolesToDelete { get; set; }
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
var userIds = UsersToDelete.ToList().Select(e => e.Id);
|
||||
if (userIds.Any())
|
||||
{
|
||||
Context.GetCollection<TUser>().DeleteMany(e => userIds.Contains(e.Id));
|
||||
}
|
||||
var roleIds = RolesToDelete.ToList().Select(e => e.Id);
|
||||
if (roleIds.Any())
|
||||
{
|
||||
Context.GetCollection<TRole>().DeleteMany(e => roleIds.Contains(e.Id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Data.Common;
|
||||
using System.Data.SqlClient;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.Test.Utilities
|
||||
{
|
||||
//public class SqlServerTestStore : IDisposable
|
||||
//{
|
||||
// public const int CommandTimeout = 90;
|
||||
|
||||
// public static string CreateConnectionString(string name)
|
||||
// {
|
||||
// var connStrBuilder = new SqlConnectionStringBuilder(TestEnvironment.Config["Test:SqlServer:DefaultConnectionString"])
|
||||
// {
|
||||
// InitialCatalog = name
|
||||
// };
|
||||
|
||||
// return connStrBuilder.ConnectionString;
|
||||
// }
|
||||
|
||||
// public static SqlServerTestStore CreateScratch(bool createDatabase = true)
|
||||
// => new SqlServerTestStore(GetScratchDbName()).CreateTransient(createDatabase);
|
||||
|
||||
// private SqlConnection _connection;
|
||||
// private readonly string _name;
|
||||
// private bool _deleteDatabase;
|
||||
|
||||
// private SqlServerTestStore(string name)
|
||||
// {
|
||||
// _name = name;
|
||||
// }
|
||||
|
||||
// private static string GetScratchDbName()
|
||||
// {
|
||||
// string name;
|
||||
// do
|
||||
// {
|
||||
// name = "Scratch_" + Guid.NewGuid();
|
||||
// } while (DatabaseExists(name)
|
||||
// || DatabaseFilesExist(name));
|
||||
|
||||
// return name;
|
||||
// }
|
||||
|
||||
// private static void WaitForExists(SqlConnection connection)
|
||||
// {
|
||||
// var retryCount = 0;
|
||||
// while (true)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// connection.Open();
|
||||
|
||||
// connection.Close();
|
||||
|
||||
// return;
|
||||
// }
|
||||
// catch (SqlException e)
|
||||
// {
|
||||
// if (++retryCount >= 30
|
||||
// || (e.Number != 233 && e.Number != -2 && e.Number != 4060))
|
||||
// {
|
||||
// throw;
|
||||
// }
|
||||
|
||||
// SqlConnection.ClearPool(connection);
|
||||
|
||||
// Thread.Sleep(100);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// private SqlServerTestStore CreateTransient(bool createDatabase)
|
||||
// {
|
||||
// _connection = new SqlConnection(CreateConnectionString(_name));
|
||||
|
||||
// if (createDatabase)
|
||||
// {
|
||||
// using (var master = new SqlConnection(CreateConnectionString("master")))
|
||||
// {
|
||||
// master.Open();
|
||||
// using (var command = master.CreateCommand())
|
||||
// {
|
||||
// command.CommandTimeout = CommandTimeout;
|
||||
// command.CommandText = $"{Environment.NewLine}CREATE DATABASE [{_name}]";
|
||||
|
||||
// command.ExecuteNonQuery();
|
||||
|
||||
// WaitForExists(_connection);
|
||||
// }
|
||||
// }
|
||||
// _connection.Open();
|
||||
// }
|
||||
|
||||
// _deleteDatabase = true;
|
||||
// return this;
|
||||
// }
|
||||
|
||||
// private static bool DatabaseExists(string name)
|
||||
// {
|
||||
// using (var master = new SqlConnection(CreateConnectionString("master")))
|
||||
// {
|
||||
// master.Open();
|
||||
|
||||
// using (var command = master.CreateCommand())
|
||||
// {
|
||||
// command.CommandTimeout = CommandTimeout;
|
||||
// command.CommandText = $@"SELECT COUNT(*) FROM sys.databases WHERE name = N'{name}'";
|
||||
|
||||
// return (int) command.ExecuteScalar() > 0;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// private static bool DatabaseFilesExist(string name)
|
||||
// {
|
||||
// var userFolder = Environment.GetEnvironmentVariable("USERPROFILE") ??
|
||||
// Environment.GetEnvironmentVariable("HOME");
|
||||
// return userFolder != null
|
||||
// && (File.Exists(Path.Combine(userFolder, name + ".mdf"))
|
||||
// || File.Exists(Path.Combine(userFolder, name + "_log.ldf")));
|
||||
// }
|
||||
|
||||
// private void DeleteDatabase(string name)
|
||||
// {
|
||||
// using (var master = new SqlConnection(CreateConnectionString("master")))
|
||||
// {
|
||||
// master.Open();
|
||||
|
||||
// using (var command = master.CreateCommand())
|
||||
// {
|
||||
// command.CommandTimeout = CommandTimeout;
|
||||
// // Query will take a few seconds if (and only if) there are active connections
|
||||
|
||||
// // SET SINGLE_USER will close any open connections that would prevent the drop
|
||||
// command.CommandText
|
||||
// = string.Format(@"IF EXISTS (SELECT * FROM sys.databases WHERE name = N'{0}')
|
||||
// BEGIN
|
||||
// ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
|
||||
// DROP DATABASE [{0}];
|
||||
// END", name);
|
||||
|
||||
// command.ExecuteNonQuery();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// public DbConnection Connection => _connection;
|
||||
|
||||
// public void Dispose()
|
||||
// {
|
||||
// _connection.Dispose();
|
||||
|
||||
// if (_deleteDatabase)
|
||||
// {
|
||||
// DeleteDatabase(_name);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class ApiConsistencyTest : ApiConsistencyTestBase
|
||||
{
|
||||
protected override Assembly TargetAssembly => typeof(IdentityOptions).GetTypeInfo().Assembly;
|
||||
}
|
||||
}
|
||||
+327
@@ -0,0 +1,327 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class IdentityBuilderTest
|
||||
{
|
||||
|
||||
[Fact]
|
||||
public void CanOverrideUserStore()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
services.AddIdentity<TestUser,TestRole>().AddUserStore<MyUberThingy>();
|
||||
var thingy = services.BuildServiceProvider().GetRequiredService<IUserStore<TestUser>>() as MyUberThingy;
|
||||
Assert.NotNull(thingy);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanOverrideRoleStore()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
services.AddIdentity<TestUser,TestRole>().AddRoleStore<MyUberThingy>();
|
||||
var thingy = services.BuildServiceProvider().GetRequiredService<IRoleStore<TestRole>>() as MyUberThingy;
|
||||
Assert.NotNull(thingy);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanOverridePrincipalFactory()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddLogging()
|
||||
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
services.AddIdentity<TestUser, TestRole>()
|
||||
.AddClaimsPrincipalFactory<MyClaimsPrincipalFactory>()
|
||||
.AddUserManager<MyUserManager>()
|
||||
.AddUserStore<NoopUserStore>()
|
||||
.AddRoleStore<NoopRoleStore>();
|
||||
var thingy = services.BuildServiceProvider().GetRequiredService<IUserClaimsPrincipalFactory<TestUser>>() as MyClaimsPrincipalFactory;
|
||||
Assert.NotNull(thingy);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanOverrideRoleValidator()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
services.AddIdentity<TestUser,TestRole>().AddRoleValidator<MyUberThingy>();
|
||||
var thingy = services.BuildServiceProvider().GetRequiredService<IRoleValidator<TestRole>>() as MyUberThingy;
|
||||
Assert.NotNull(thingy);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanOverrideUserValidator()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
services.AddIdentity<TestUser,TestRole>().AddUserValidator<MyUberThingy>();
|
||||
var thingy = services.BuildServiceProvider().GetRequiredService<IUserValidator<TestUser>>() as MyUberThingy;
|
||||
Assert.NotNull(thingy);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanOverridePasswordValidator()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
services.AddIdentity<TestUser,TestRole>().AddPasswordValidator<MyUberThingy>();
|
||||
var thingy = services.BuildServiceProvider().GetRequiredService<IPasswordValidator<TestUser>>() as MyUberThingy;
|
||||
Assert.NotNull(thingy);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanOverrideUserManager()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
services.AddIdentity<TestUser, TestRole>()
|
||||
.AddUserStore<NoopUserStore>()
|
||||
.AddUserManager<MyUserManager>();
|
||||
var myUserManager = services.BuildServiceProvider().GetRequiredService(typeof(UserManager<TestUser>)) as MyUserManager;
|
||||
Assert.NotNull(myUserManager);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanOverrideRoleManager()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
services.AddIdentity<TestUser, TestRole>()
|
||||
.AddRoleStore<NoopRoleStore>()
|
||||
.AddRoleManager<MyRoleManager>();
|
||||
var myRoleManager = services.BuildServiceProvider().GetRequiredService<RoleManager<TestRole>>() as MyRoleManager;
|
||||
Assert.NotNull(myRoleManager);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanOverrideSignInManager()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build())
|
||||
.AddSingleton<IHttpContextAccessor, HttpContextAccessor>()
|
||||
.AddLogging();
|
||||
services.AddIdentity<TestUser, TestRole>()
|
||||
.AddUserStore<NoopUserStore>()
|
||||
.AddRoleStore<NoopRoleStore>()
|
||||
.AddUserManager<MyUserManager>()
|
||||
.AddClaimsPrincipalFactory<MyClaimsPrincipalFactory>()
|
||||
.AddSignInManager<MySignInManager>();
|
||||
var myUserManager = services.BuildServiceProvider().GetRequiredService(typeof(SignInManager<TestUser>)) as MySignInManager;
|
||||
Assert.NotNull(myUserManager);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnsureDefaultServices()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
services.AddIdentity<TestUser,TestRole>();
|
||||
|
||||
var provider = services.BuildServiceProvider();
|
||||
var userValidator = provider.GetRequiredService<IUserValidator<TestUser>>() as UserValidator<TestUser>;
|
||||
Assert.NotNull(userValidator);
|
||||
|
||||
var pwdValidator = provider.GetRequiredService<IPasswordValidator<TestUser>>() as PasswordValidator<TestUser>;
|
||||
Assert.NotNull(pwdValidator);
|
||||
|
||||
var hasher = provider.GetRequiredService<IPasswordHasher<TestUser>>() as PasswordHasher<TestUser>;
|
||||
Assert.NotNull(hasher);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnsureDefaultTokenProviders()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
services.AddIdentity<TestUser,TestRole>().AddDefaultTokenProviders();
|
||||
|
||||
var provider = services.BuildServiceProvider();
|
||||
var tokenProviders = provider.GetRequiredService<IOptions<IdentityOptions>>().Value.Tokens.ProviderMap.Values;
|
||||
Assert.Equal(4, tokenProviders.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddManagerWithWrongTypesThrows()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
var builder = services.AddIdentity<TestUser, TestRole>();
|
||||
Assert.Throws<InvalidOperationException>(() => builder.AddUserManager<object>());
|
||||
Assert.Throws<InvalidOperationException>(() => builder.AddRoleManager<object>());
|
||||
Assert.Throws<InvalidOperationException>(() => builder.AddSignInManager<object>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddTokenProviderWithWrongTypesThrows()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
var builder = services.AddIdentity<TestUser, TestRole>();
|
||||
Assert.Throws<InvalidOperationException>(() => builder.AddTokenProvider<object>("whatevs"));
|
||||
Assert.Throws<InvalidOperationException>(() => builder.AddTokenProvider("whatevs", typeof(object)));
|
||||
}
|
||||
|
||||
private class MyUberThingy : IUserValidator<TestUser>, IPasswordValidator<TestUser>, IRoleValidator<TestRole>, IUserStore<TestUser>, IRoleStore<TestRole>
|
||||
{
|
||||
public Task<IdentityResult> CreateAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IdentityResult> CreateAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IdentityResult> DeleteAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IdentityResult> DeleteAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<TestUser> FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<TestUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<string> GetNormalizedRoleNameAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<string> GetNormalizedUserNameAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<string> GetRoleIdAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<string> GetRoleNameAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<string> GetUserIdAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<string> GetUserNameAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task SetNormalizedRoleNameAsync(TestRole role, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task SetNormalizedUserNameAsync(TestUser user, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task SetRoleNameAsync(TestRole role, string roleName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task SetUserNameAsync(TestUser user, string userName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IdentityResult> UpdateAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IdentityResult> UpdateAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IdentityResult> ValidateAsync(RoleManager<TestRole> manager, TestRole role)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IdentityResult> ValidateAsync(UserManager<TestUser> manager, TestUser user)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IdentityResult> ValidateAsync(UserManager<TestUser> manager, TestUser user, string password)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
Task<TestRole> IRoleStore<TestRole>.FindByIdAsync(string roleId, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
Task<TestRole> IRoleStore<TestRole>.FindByNameAsync(string roleName, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private class MySignInManager : SignInManager<TestUser>
|
||||
{
|
||||
public MySignInManager(UserManager<TestUser> manager, IHttpContextAccessor context, IUserClaimsPrincipalFactory<TestUser> claimsFactory) : base(manager, context, claimsFactory, null, null, null) { }
|
||||
}
|
||||
|
||||
private class MyUserManager : UserManager<TestUser>
|
||||
{
|
||||
public MyUserManager(IUserStore<TestUser> store) : base(store, null, null, null, null, null, null, null, null) { }
|
||||
}
|
||||
|
||||
private class MyClaimsPrincipalFactory : UserClaimsPrincipalFactory<TestUser, TestRole>
|
||||
{
|
||||
public MyClaimsPrincipalFactory(UserManager<TestUser> userManager, RoleManager<TestRole> roleManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class MyRoleManager : RoleManager<TestRole>
|
||||
{
|
||||
public MyRoleManager(IRoleStore<TestRole> store,
|
||||
IEnumerable<IRoleValidator<TestRole>> roleValidators) : base(store, null, null, null, null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class IdentityOptionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void VerifyDefaultOptions()
|
||||
{
|
||||
var options = new IdentityOptions();
|
||||
Assert.True(options.Lockout.AllowedForNewUsers);
|
||||
Assert.Equal(TimeSpan.FromMinutes(5), options.Lockout.DefaultLockoutTimeSpan);
|
||||
Assert.Equal(5, options.Lockout.MaxFailedAccessAttempts);
|
||||
|
||||
Assert.True(options.Password.RequireDigit);
|
||||
Assert.True(options.Password.RequireLowercase);
|
||||
Assert.True(options.Password.RequireNonAlphanumeric);
|
||||
Assert.True(options.Password.RequireUppercase);
|
||||
Assert.Equal(6, options.Password.RequiredLength);
|
||||
Assert.Equal(1, options.Password.RequiredUniqueChars);
|
||||
|
||||
Assert.Equal("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+", options.User.AllowedUserNameCharacters);
|
||||
Assert.False(options.User.RequireUniqueEmail);
|
||||
|
||||
Assert.Equal(ClaimTypes.Role, options.ClaimsIdentity.RoleClaimType);
|
||||
Assert.Equal(ClaimTypes.Name, options.ClaimsIdentity.UserNameClaimType);
|
||||
Assert.Equal(ClaimTypes.NameIdentifier, options.ClaimsIdentity.UserIdClaimType);
|
||||
Assert.Equal("AspNet.Identity.SecurityStamp", options.ClaimsIdentity.SecurityStampClaimType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanCustomizeIdentityOptions()
|
||||
{
|
||||
var services = new ServiceCollection().Configure<IdentityOptions>(options => options.Password.RequiredLength = -1);
|
||||
services.AddIdentity<TestUser,TestRole>();
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
var setup = serviceProvider.GetRequiredService<IConfigureOptions<IdentityOptions>>();
|
||||
Assert.NotNull(setup);
|
||||
var optionsGetter = serviceProvider.GetRequiredService<IOptions<IdentityOptions>>();
|
||||
Assert.NotNull(optionsGetter);
|
||||
var myOptions = optionsGetter.Value;
|
||||
Assert.True(myOptions.Password.RequireLowercase);
|
||||
Assert.True(myOptions.Password.RequireDigit);
|
||||
Assert.True(myOptions.Password.RequireNonAlphanumeric);
|
||||
Assert.True(myOptions.Password.RequireUppercase);
|
||||
Assert.Equal(1, myOptions.Password.RequiredUniqueChars);
|
||||
Assert.Equal(-1, myOptions.Password.RequiredLength);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanSetupIdentityOptions()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddIdentity<TestUser,TestRole>(options => options.User.RequireUniqueEmail = true);
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
var optionsGetter = serviceProvider.GetRequiredService<IOptions<IdentityOptions>>();
|
||||
Assert.NotNull(optionsGetter);
|
||||
|
||||
var myOptions = optionsGetter.Value;
|
||||
Assert.True(myOptions.User.RequireUniqueEmail);
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class IdentityResultTest
|
||||
{
|
||||
[Fact]
|
||||
public void VerifyDefaultConstructor()
|
||||
{
|
||||
var result = new IdentityResult();
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.Empty(result.Errors);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NullFailedUsesEmptyErrors()
|
||||
{
|
||||
var result = IdentityResult.Failed();
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.Empty(result.Errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class NoopRoleStore : IRoleStore<TestRole>
|
||||
{
|
||||
public Task<IdentityResult> CreateAsync(TestRole user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public Task<IdentityResult> UpdateAsync(TestRole user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public Task<string> GetRoleNameAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult<string>(null);
|
||||
}
|
||||
|
||||
public Task SetRoleNameAsync(TestRole role, string roleName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task<TestRole> FindByIdAsync(string roleId, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult<TestRole>(null);
|
||||
}
|
||||
|
||||
public Task<TestRole> FindByNameAsync(string userName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult<TestRole>(null);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public Task<IdentityResult> DeleteAsync(TestRole user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public Task<string> GetRoleIdAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult<string>(null);
|
||||
}
|
||||
|
||||
public Task<string> GetNormalizedRoleNameAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult<string>(null);
|
||||
}
|
||||
|
||||
public Task SetNormalizedRoleNameAsync(TestRole role, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class NoopUserStore : IUserStore<TestUser>
|
||||
{
|
||||
public Task<string> GetUserIdAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(user.Id);
|
||||
}
|
||||
|
||||
public Task<string> GetUserNameAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(user.UserName);
|
||||
}
|
||||
|
||||
public Task SetUserNameAsync(TestUser user, string userName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task<IdentityResult> CreateAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public Task<IdentityResult> UpdateAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public Task<TestUser> FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult<TestUser>(null);
|
||||
}
|
||||
|
||||
public Task<TestUser> FindByNameAsync(string userName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult<TestUser>(null);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public Task<IdentityResult> DeleteAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(IdentityResult.Success);
|
||||
}
|
||||
|
||||
public Task<string> GetNormalizedUserNameAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult<string>(null);
|
||||
}
|
||||
|
||||
public Task SetNormalizedUserNameAsync(TestUser user, string userName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class PasswordHasherTest
|
||||
{
|
||||
[Fact]
|
||||
public void Ctor_InvalidCompatMode_Throws()
|
||||
{
|
||||
// Act & assert
|
||||
var ex = Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
new PasswordHasher(compatMode: (PasswordHasherCompatibilityMode)(-1));
|
||||
});
|
||||
Assert.Equal("The provided PasswordHasherCompatibilityMode is invalid.", ex.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-1)]
|
||||
[InlineData(0)]
|
||||
public void Ctor_InvalidIterCount_Throws(int iterCount)
|
||||
{
|
||||
// Act & assert
|
||||
var ex = Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
new PasswordHasher(iterCount: iterCount);
|
||||
});
|
||||
Assert.Equal("The iteration count must be a positive integer.", ex.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(PasswordHasherCompatibilityMode.IdentityV2)]
|
||||
[InlineData(PasswordHasherCompatibilityMode.IdentityV3)]
|
||||
public void FullRoundTrip(PasswordHasherCompatibilityMode compatMode)
|
||||
{
|
||||
// Arrange
|
||||
var hasher = new PasswordHasher(compatMode: compatMode);
|
||||
|
||||
// Act & assert - success case
|
||||
var hashedPassword = hasher.HashPassword(null, "password 1");
|
||||
var successResult = hasher.VerifyHashedPassword(null, hashedPassword, "password 1");
|
||||
Assert.Equal(PasswordVerificationResult.Success, successResult);
|
||||
|
||||
// Act & assert - failure case
|
||||
var failedResult = hasher.VerifyHashedPassword(null, hashedPassword, "password 2");
|
||||
Assert.Equal(PasswordVerificationResult.Failed, failedResult);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// Version 2 payloads
|
||||
[InlineData("AAABAgMEBQYHCAkKCwwNDg+uAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALtH1uJg==")] // incorrect password
|
||||
[InlineData("AAABAgMEBQYHCAkKCwwNDg+ukCEMDf0yyQ29NYubggE=")] // too short
|
||||
[InlineData("AAABAgMEBQYHCAkKCwwNDg+ukCEMDf0yyQ29NYubggHIVY0sdEUfdyeM+E1LtH1uJgAAAAAAAAAAAAA=")] // extra data at end
|
||||
// Version 3 payloads
|
||||
[InlineData("AQAAAAAAAAD6AAAAEAhftMyfTJyAAAAAAAAAAAAAAAAAAAih5WsjXaR3PA9M")] // incorrect password
|
||||
[InlineData("AQAAAAIAAAAyAAAAEOMwvh3+FZxqkdMBz2ekgGhwQ4A=")] // too short
|
||||
[InlineData("AQAAAAIAAAAyAAAAEOMwvh3+FZxqkdMBz2ekgGhwQ4B6pZWND6zgESBuWiHwAAAAAAAAAAAA")] // extra data at end
|
||||
public void VerifyHashedPassword_FailureCases(string hashedPassword)
|
||||
{
|
||||
// Arrange
|
||||
var hasher = new PasswordHasher();
|
||||
|
||||
// Act
|
||||
var result = hasher.VerifyHashedPassword(null, hashedPassword, "my password");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(PasswordVerificationResult.Failed, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// Version 2 payloads
|
||||
[InlineData("ANXrDknc7fGPpigibZXXZFMX4aoqz44JveK6jQuwY3eH/UyPhvr5xTPeGYEckLxz9A==")] // SHA1, 1000 iterations, 128-bit salt, 256-bit subkey
|
||||
// Version 3 payloads
|
||||
[InlineData("AQAAAAIAAAAyAAAAEOMwvh3+FZxqkdMBz2ekgGhwQ4B6pZWND6zgESBuWiHw")] // SHA512, 50 iterations, 128-bit salt, 128-bit subkey
|
||||
[InlineData("AQAAAAIAAAD6AAAAIJbVi5wbMR+htSfFp8fTw8N8GOS/Sje+S/4YZcgBfU7EQuqv4OkVYmc4VJl9AGZzmRTxSkP7LtVi9IWyUxX8IAAfZ8v+ZfhjCcudtC1YERSqE1OEdXLW9VukPuJWBBjLuw==")] // SHA512, 250 iterations, 256-bit salt, 512-bit subkey
|
||||
[InlineData("AQAAAAAAAAD6AAAAEAhftMyfTJylOlZT+eEotFXd1elee8ih5WsjXaR3PA9M")] // SHA1, 250 iterations, 128-bit salt, 128-bit subkey
|
||||
[InlineData("AQAAAAEAA9CQAAAAIESkQuj2Du8Y+kbc5lcN/W/3NiAZFEm11P27nrSN5/tId+bR1SwV8CO1Jd72r4C08OLvplNlCDc3oQZ8efcW+jQ=")] // SHA256, 250000 iterations, 256-bit salt, 256-bit subkey
|
||||
public void VerifyHashedPassword_Version2CompatMode_SuccessCases(string hashedPassword)
|
||||
{
|
||||
// Arrange
|
||||
var hasher = new PasswordHasher(compatMode: PasswordHasherCompatibilityMode.IdentityV2);
|
||||
|
||||
// Act
|
||||
var result = hasher.VerifyHashedPassword(null, hashedPassword, "my password");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(PasswordVerificationResult.Success, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// Version 2 payloads
|
||||
[InlineData("ANXrDknc7fGPpigibZXXZFMX4aoqz44JveK6jQuwY3eH/UyPhvr5xTPeGYEckLxz9A==", PasswordVerificationResult.SuccessRehashNeeded)] // SHA1, 1000 iterations, 128-bit salt, 256-bit subkey
|
||||
// Version 3 payloads
|
||||
[InlineData("AQAAAAIAAAAyAAAAEOMwvh3+FZxqkdMBz2ekgGhwQ4B6pZWND6zgESBuWiHw", PasswordVerificationResult.SuccessRehashNeeded)] // SHA512, 50 iterations, 128-bit salt, 128-bit subkey
|
||||
[InlineData("AQAAAAIAAAD6AAAAIJbVi5wbMR+htSfFp8fTw8N8GOS/Sje+S/4YZcgBfU7EQuqv4OkVYmc4VJl9AGZzmRTxSkP7LtVi9IWyUxX8IAAfZ8v+ZfhjCcudtC1YERSqE1OEdXLW9VukPuJWBBjLuw==", PasswordVerificationResult.SuccessRehashNeeded)] // SHA512, 250 iterations, 256-bit salt, 512-bit subkey
|
||||
[InlineData("AQAAAAAAAAD6AAAAEAhftMyfTJylOlZT+eEotFXd1elee8ih5WsjXaR3PA9M", PasswordVerificationResult.SuccessRehashNeeded)] // SHA1, 250 iterations, 128-bit salt, 128-bit subkey
|
||||
[InlineData("AQAAAAEAA9CQAAAAIESkQuj2Du8Y+kbc5lcN/W/3NiAZFEm11P27nrSN5/tId+bR1SwV8CO1Jd72r4C08OLvplNlCDc3oQZ8efcW+jQ=", PasswordVerificationResult.Success)] // SHA256, 250000 iterations, 256-bit salt, 256-bit subkey
|
||||
public void VerifyHashedPassword_Version3CompatMode_SuccessCases(string hashedPassword, PasswordVerificationResult expectedResult)
|
||||
{
|
||||
// Arrange
|
||||
var hasher = new PasswordHasher(compatMode: PasswordHasherCompatibilityMode.IdentityV3);
|
||||
|
||||
// Act
|
||||
var actualResult = hasher.VerifyHashedPassword(null, hashedPassword, "my password");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, actualResult);
|
||||
}
|
||||
|
||||
private sealed class PasswordHasher : PasswordHasher<object>
|
||||
{
|
||||
public PasswordHasher(PasswordHasherCompatibilityMode? compatMode = null, int? iterCount = null)
|
||||
: base(BuildOptions(compatMode, iterCount))
|
||||
{
|
||||
}
|
||||
|
||||
private static IOptions<PasswordHasherOptions> BuildOptions(PasswordHasherCompatibilityMode? compatMode, int? iterCount)
|
||||
{
|
||||
var options = new PasswordHasherOptionsAccessor();
|
||||
if (compatMode != null)
|
||||
{
|
||||
options.Value.CompatibilityMode = (PasswordHasherCompatibilityMode)compatMode;
|
||||
}
|
||||
if (iterCount != null)
|
||||
{
|
||||
options.Value.IterationCount = (int)iterCount;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class SequentialRandomNumberGenerator : RandomNumberGenerator
|
||||
{
|
||||
private byte _value;
|
||||
|
||||
public override void GetBytes(byte[] data)
|
||||
{
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
data[i] = _value++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PasswordHasherOptionsAccessor : IOptions<PasswordHasherOptions>
|
||||
{
|
||||
public PasswordHasherOptions Value { get; } = new PasswordHasherOptions();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class PasswordValidatorTest
|
||||
{
|
||||
[Flags]
|
||||
public enum Errors
|
||||
{
|
||||
None = 0,
|
||||
Length = 2,
|
||||
Alpha = 4,
|
||||
Upper = 8,
|
||||
Lower = 16,
|
||||
Digit = 32,
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateThrowsWithNullTest()
|
||||
{
|
||||
// Setup
|
||||
var validator = new PasswordValidator<TestUser>();
|
||||
|
||||
// Act
|
||||
// Assert
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("password", () => validator.ValidateAsync(null, null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("manager", () => validator.ValidateAsync(null, null, "foo"));
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("abc")]
|
||||
[InlineData("abcde")]
|
||||
public async Task FailsIfTooShortTests(string input)
|
||||
{
|
||||
const string error = "Passwords must be at least 6 characters.";
|
||||
var manager = MockHelpers.TestUserManager<TestUser>();
|
||||
var valid = new PasswordValidator<TestUser>();
|
||||
manager.Options.Password.RequireUppercase = false;
|
||||
manager.Options.Password.RequireNonAlphanumeric = false;
|
||||
manager.Options.Password.RequireLowercase = false;
|
||||
manager.Options.Password.RequireDigit = false;
|
||||
IdentityResultAssert.IsFailure(await valid.ValidateAsync(manager, null, input), error);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("abcdef")]
|
||||
[InlineData("aaaaaaaaaaa")]
|
||||
public async Task SuccessIfLongEnoughTests(string input)
|
||||
{
|
||||
var manager = MockHelpers.TestUserManager<TestUser>();
|
||||
var valid = new PasswordValidator<TestUser>();
|
||||
manager.Options.Password.RequireUppercase = false;
|
||||
manager.Options.Password.RequireNonAlphanumeric = false;
|
||||
manager.Options.Password.RequireLowercase = false;
|
||||
manager.Options.Password.RequireDigit = false;
|
||||
IdentityResultAssert.IsSuccess(await valid.ValidateAsync(manager, null, input));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("a")]
|
||||
[InlineData("aaaaaaaaaaa")]
|
||||
public async Task FailsWithoutRequiredNonAlphanumericTests(string input)
|
||||
{
|
||||
var manager = MockHelpers.TestUserManager<TestUser>();
|
||||
var valid = new PasswordValidator<TestUser>();
|
||||
manager.Options.Password.RequireUppercase = false;
|
||||
manager.Options.Password.RequireNonAlphanumeric = true;
|
||||
manager.Options.Password.RequireLowercase = false;
|
||||
manager.Options.Password.RequireDigit = false;
|
||||
manager.Options.Password.RequiredLength = 0;
|
||||
IdentityResultAssert.IsFailure(await valid.ValidateAsync(manager, null, input),
|
||||
"Passwords must have at least one non alphanumeric character.");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("@")]
|
||||
[InlineData("abcd@e!ld!kajfd")]
|
||||
[InlineData("!!!!!!")]
|
||||
public async Task SucceedsWithRequiredNonAlphanumericTests(string input)
|
||||
{
|
||||
var manager = MockHelpers.TestUserManager<TestUser>();
|
||||
var valid = new PasswordValidator<TestUser>();
|
||||
manager.Options.Password.RequireUppercase = false;
|
||||
manager.Options.Password.RequireNonAlphanumeric = true;
|
||||
manager.Options.Password.RequireLowercase = false;
|
||||
manager.Options.Password.RequireDigit = false;
|
||||
manager.Options.Password.RequiredLength = 0;
|
||||
IdentityResultAssert.IsSuccess(await valid.ValidateAsync(manager, null, input));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("a", 2)]
|
||||
[InlineData("aaaaaaaaaaa", 2)]
|
||||
[InlineData("abcdabcdabcdabcdabcdabcdabcd", 5)]
|
||||
public async Task FailsWithoutRequiredUniqueCharsTests(string input, int uniqueChars)
|
||||
{
|
||||
var manager = MockHelpers.TestUserManager<TestUser>();
|
||||
var valid = new PasswordValidator<TestUser>();
|
||||
manager.Options.Password.RequireUppercase = false;
|
||||
manager.Options.Password.RequireNonAlphanumeric = false;
|
||||
manager.Options.Password.RequireLowercase = false;
|
||||
manager.Options.Password.RequireDigit = false;
|
||||
manager.Options.Password.RequiredLength = 0;
|
||||
manager.Options.Password.RequiredUniqueChars = uniqueChars;
|
||||
IdentityResultAssert.IsFailure(await valid.ValidateAsync(manager, null, input),
|
||||
String.Format("Passwords must use at least {0} different characters.", uniqueChars));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("12345", 5)]
|
||||
[InlineData("aAbBc", 5)]
|
||||
[InlineData("aAbBcaAbBcaAbBc", 5)]
|
||||
[InlineData("!@#$%", 5)]
|
||||
[InlineData("a", 1)]
|
||||
[InlineData("this is a long password with many chars", 10)]
|
||||
public async Task SucceedsWithRequiredUniqueCharsTests(string input, int uniqueChars)
|
||||
{
|
||||
var manager = MockHelpers.TestUserManager<TestUser>();
|
||||
var valid = new PasswordValidator<TestUser>();
|
||||
manager.Options.Password.RequireUppercase = false;
|
||||
manager.Options.Password.RequireNonAlphanumeric = false;
|
||||
manager.Options.Password.RequireLowercase = false;
|
||||
manager.Options.Password.RequireDigit = false;
|
||||
manager.Options.Password.RequiredLength = 0;
|
||||
manager.Options.Password.RequiredUniqueChars = uniqueChars;
|
||||
IdentityResultAssert.IsSuccess(await valid.ValidateAsync(manager, null, input));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("abcde", Errors.Length | Errors.Alpha | Errors.Upper | Errors.Digit)]
|
||||
[InlineData("a@B@cd", Errors.Digit)]
|
||||
[InlineData("___", Errors.Length | Errors.Digit | Errors.Lower | Errors.Upper)]
|
||||
[InlineData("a_b9de", Errors.Upper)]
|
||||
[InlineData("abcd@e!ld!kaj9Fd", Errors.None)]
|
||||
[InlineData("aB1@df", Errors.None)]
|
||||
public async Task UberMixedRequiredTests(string input, Errors errorMask)
|
||||
{
|
||||
const string alphaError = "Passwords must have at least one non alphanumeric character.";
|
||||
const string upperError = "Passwords must have at least one uppercase ('A'-'Z').";
|
||||
const string lowerError = "Passwords must have at least one lowercase ('a'-'z').";
|
||||
const string digitError = "Passwords must have at least one digit ('0'-'9').";
|
||||
const string lengthError = "Passwords must be at least 6 characters.";
|
||||
var manager = MockHelpers.TestUserManager<TestUser>();
|
||||
var valid = new PasswordValidator<TestUser>();
|
||||
var errors = new List<string>();
|
||||
if ((errorMask & Errors.Length) != Errors.None)
|
||||
{
|
||||
errors.Add(lengthError);
|
||||
}
|
||||
if ((errorMask & Errors.Alpha) != Errors.None)
|
||||
{
|
||||
errors.Add(alphaError);
|
||||
}
|
||||
if ((errorMask & Errors.Digit) != Errors.None)
|
||||
{
|
||||
errors.Add(digitError);
|
||||
}
|
||||
if ((errorMask & Errors.Lower) != Errors.None)
|
||||
{
|
||||
errors.Add(lowerError);
|
||||
}
|
||||
if ((errorMask & Errors.Upper) != Errors.None)
|
||||
{
|
||||
errors.Add(upperError);
|
||||
}
|
||||
var result = await valid.ValidateAsync(manager, null, input);
|
||||
if (errors.Count == 0)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
IdentityResultAssert.IsFailure(result);
|
||||
foreach (var error in errors)
|
||||
{
|
||||
Assert.Contains(result.Errors, e => e.Description == error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Security.Claims;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class ClaimsIdentityExtensionsTest
|
||||
{
|
||||
public const string ExternalAuthenticationScheme = "TestExternalAuth";
|
||||
|
||||
[Fact]
|
||||
public void IdentityExtensionsFindFirstValueNullIfUnknownTest()
|
||||
{
|
||||
var id = CreateTestExternalIdentity();
|
||||
Assert.Null(id.FindFirstValue("bogus"));
|
||||
}
|
||||
|
||||
private static ClaimsPrincipal CreateTestExternalIdentity()
|
||||
{
|
||||
return new ClaimsPrincipal(new ClaimsIdentity(
|
||||
new[]
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, "NameIdentifier", null, ExternalAuthenticationScheme),
|
||||
new Claim(ClaimTypes.Name, "Name")
|
||||
},
|
||||
ExternalAuthenticationScheme));
|
||||
}
|
||||
}
|
||||
}
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class RoleManagerTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task CreateCallsStore()
|
||||
{
|
||||
// Setup
|
||||
var store = new Mock<IRoleStore<TestRole>>();
|
||||
var role = new TestRole { Name = "Foo" };
|
||||
store.Setup(s => s.CreateAsync(role, CancellationToken.None)).ReturnsAsync(IdentityResult.Success).Verifiable();
|
||||
store.Setup(s => s.GetRoleNameAsync(role, CancellationToken.None)).Returns(Task.FromResult(role.Name)).Verifiable();
|
||||
store.Setup(s => s.SetNormalizedRoleNameAsync(role, role.Name.ToUpperInvariant(), CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
|
||||
var roleManager = MockHelpers.TestRoleManager(store.Object);
|
||||
|
||||
// Act
|
||||
var result = await roleManager.CreateAsync(role);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Succeeded);
|
||||
store.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateCallsStore()
|
||||
{
|
||||
// Setup
|
||||
var store = new Mock<IRoleStore<TestRole>>();
|
||||
var role = new TestRole { Name = "Foo" };
|
||||
store.Setup(s => s.UpdateAsync(role, CancellationToken.None)).ReturnsAsync(IdentityResult.Success).Verifiable();
|
||||
store.Setup(s => s.GetRoleNameAsync(role, CancellationToken.None)).Returns(Task.FromResult(role.Name)).Verifiable();
|
||||
store.Setup(s => s.SetNormalizedRoleNameAsync(role, role.Name.ToUpperInvariant(), CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
|
||||
var roleManager = MockHelpers.TestRoleManager(store.Object);
|
||||
|
||||
// Act
|
||||
var result = await roleManager.UpdateAsync(role);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Succeeded);
|
||||
store.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RolesQueryableFailWhenStoreNotImplemented()
|
||||
{
|
||||
var manager = CreateRoleManager(new NoopRoleStore());
|
||||
Assert.False(manager.SupportsQueryableRoles);
|
||||
Assert.Throws<NotSupportedException>(() => manager.Roles.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FindByNameCallsStoreWithNormalizedName()
|
||||
{
|
||||
// Setup
|
||||
var store = new Mock<IRoleStore<TestRole>>();
|
||||
var role = new TestRole { Name = "Foo" };
|
||||
store.Setup(s => s.FindByNameAsync("FOO", CancellationToken.None)).Returns(Task.FromResult(role)).Verifiable();
|
||||
var manager = MockHelpers.TestRoleManager(store.Object);
|
||||
|
||||
// Act
|
||||
var result = await manager.FindByNameAsync(role.Name);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(role, result);
|
||||
store.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanFindByNameCallsStoreWithoutNormalizedName()
|
||||
{
|
||||
// Setup
|
||||
var store = new Mock<IRoleStore<TestRole>>();
|
||||
var role = new TestRole { Name = "Foo" };
|
||||
store.Setup(s => s.FindByNameAsync(role.Name, CancellationToken.None)).Returns(Task.FromResult(role)).Verifiable();
|
||||
var manager = MockHelpers.TestRoleManager(store.Object);
|
||||
manager.KeyNormalizer = null;
|
||||
|
||||
// Act
|
||||
var result = await manager.FindByNameAsync(role.Name);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(role, result);
|
||||
store.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RoleExistsCallsStoreWithNormalizedName()
|
||||
{
|
||||
// Setup
|
||||
var store = new Mock<IRoleStore<TestRole>>();
|
||||
var role = new TestRole { Name = "Foo" };
|
||||
store.Setup(s => s.FindByNameAsync("FOO", CancellationToken.None)).Returns(Task.FromResult(role)).Verifiable();
|
||||
var manager = MockHelpers.TestRoleManager(store.Object);
|
||||
|
||||
// Act
|
||||
var result = await manager.RoleExistsAsync(role.Name);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
store.VerifyAll();
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void DisposeAfterDisposeDoesNotThrow()
|
||||
{
|
||||
var manager = CreateRoleManager(new NoopRoleStore());
|
||||
manager.Dispose();
|
||||
manager.Dispose();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RoleManagerPublicNullChecks()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>("store",
|
||||
() => new RoleManager<TestRole>(null, null, null, null, null));
|
||||
var manager = CreateRoleManager(new NotImplementedStore());
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("role", async () => await manager.CreateAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("role", async () => await manager.UpdateAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("role", async () => await manager.DeleteAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("roleName", async () => await manager.FindByNameAsync(null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("roleName", async () => await manager.RoleExistsAsync(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RoleStoreMethodsThrowWhenDisposed()
|
||||
{
|
||||
var manager = CreateRoleManager(new NoopRoleStore());
|
||||
manager.Dispose();
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(() => manager.FindByIdAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(() => manager.FindByNameAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(() => manager.RoleExistsAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(() => manager.CreateAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(() => manager.UpdateAsync(null));
|
||||
await Assert.ThrowsAsync<ObjectDisposedException>(() => manager.DeleteAsync(null));
|
||||
}
|
||||
|
||||
private static RoleManager<TestRole> CreateRoleManager(IRoleStore<TestRole> roleStore)
|
||||
{
|
||||
return MockHelpers.TestRoleManager(roleStore);
|
||||
}
|
||||
|
||||
private class NotImplementedStore : IRoleStore<TestRole>
|
||||
{
|
||||
public Task<IdentityResult> CreateAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IdentityResult> UpdateAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IdentityResult> DeleteAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<string> GetRoleIdAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<string> GetRoleNameAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task SetRoleNameAsync(TestRole role, string roleName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<TestRole> FindByIdAsync(string roleId, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<TestRole> FindByNameAsync(string roleName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<string> GetNormalizedRoleNameAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task SetNormalizedRoleNameAsync(TestRole role, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class RoleValidatorTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task ValidateThrowsWithNull()
|
||||
{
|
||||
// Setup
|
||||
var validator = new RoleValidator<TestRole>();
|
||||
var manager = MockHelpers.TestRoleManager<TestRole>();
|
||||
|
||||
// Act
|
||||
// Assert
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("manager", async () => await validator.ValidateAsync(null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("role", async () => await validator.ValidateAsync(manager, null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
public async Task ValidateFailsWithTooShortRoleName(string input)
|
||||
{
|
||||
// Setup
|
||||
var validator = new RoleValidator<TestRole>();
|
||||
var manager = MockHelpers.TestRoleManager<TestRole>();
|
||||
var user = new TestRole {Name = input};
|
||||
|
||||
// Act
|
||||
var result = await validator.ValidateAsync(manager, user);
|
||||
|
||||
// Assert
|
||||
IdentityResultAssert.IsFailure(result, new IdentityErrorDescriber().InvalidRoleName(input));
|
||||
}
|
||||
}
|
||||
}
|
||||
+220
@@ -0,0 +1,220 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class SecurityStampTest
|
||||
{
|
||||
private class NoopHandler : IAuthenticationHandler
|
||||
{
|
||||
public Task<AuthenticateResult> AuthenticateAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task ChallengeAsync(AuthenticationProperties properties)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task ForbidAsync(AuthenticationProperties properties)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<bool> HandleRequestAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task SignOutAsync(AuthenticationProperties properties)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OnValidatePrincipalThrowsWithEmptyServiceCollection()
|
||||
{
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
httpContext.Setup(c => c.RequestServices).Returns(new ServiceCollection().BuildServiceProvider());
|
||||
var id = new ClaimsPrincipal(new ClaimsIdentity(IdentityConstants.ApplicationScheme));
|
||||
var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }, IdentityConstants.ApplicationScheme);
|
||||
var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(IdentityConstants.ApplicationScheme) { HandlerType = typeof(NoopHandler) }.Build(), new CookieAuthenticationOptions(), ticket);
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => SecurityStampValidator.ValidatePrincipalAsync(context));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task OnValidatePrincipalTestSuccess(bool isPersistent)
|
||||
{
|
||||
var user = new TestUser("test");
|
||||
var userManager = MockHelpers.MockUserManager<TestUser>();
|
||||
var claimsManager = new Mock<IUserClaimsPrincipalFactory<TestUser>>();
|
||||
var identityOptions = new Mock<IOptions<IdentityOptions>>();
|
||||
identityOptions.Setup(a => a.Value).Returns(new IdentityOptions());
|
||||
var options = new Mock<IOptions<SecurityStampValidatorOptions>>();
|
||||
options.Setup(a => a.Value).Returns(new SecurityStampValidatorOptions { ValidationInterval = TimeSpan.Zero });
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object);
|
||||
var id = new ClaimsIdentity(IdentityConstants.ApplicationScheme);
|
||||
id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));
|
||||
var principal = new ClaimsPrincipal(id);
|
||||
|
||||
var properties = new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow.AddSeconds(-1), IsPersistent = isPersistent };
|
||||
var signInManager = new Mock<SignInManager<TestUser>>(userManager.Object,
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny<ClaimsPrincipal>())).ReturnsAsync(user).Verifiable();
|
||||
signInManager.Setup(s => s.CreateUserPrincipalAsync(user)).ReturnsAsync(principal).Verifiable();
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton(options.Object);
|
||||
services.AddSingleton(signInManager.Object);
|
||||
services.AddSingleton<ISecurityStampValidator>(new SecurityStampValidator<TestUser>(options.Object, signInManager.Object, new SystemClock()));
|
||||
httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider());
|
||||
|
||||
var ticket = new AuthenticationTicket(principal,
|
||||
properties,
|
||||
IdentityConstants.ApplicationScheme);
|
||||
var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(IdentityConstants.ApplicationScheme) { HandlerType = typeof(NoopHandler) }.Build(), new CookieAuthenticationOptions(), ticket);
|
||||
Assert.NotNull(context.Properties);
|
||||
Assert.NotNull(context.Options);
|
||||
Assert.NotNull(context.Principal);
|
||||
await
|
||||
SecurityStampValidator.ValidatePrincipalAsync(context);
|
||||
Assert.NotNull(context.Principal);
|
||||
signInManager.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OnValidateIdentityRejectsWhenValidateSecurityStampFails()
|
||||
{
|
||||
var user = new TestUser("test");
|
||||
var userManager = MockHelpers.MockUserManager<TestUser>();
|
||||
var claimsManager = new Mock<IUserClaimsPrincipalFactory<TestUser>>();
|
||||
var identityOptions = new Mock<IOptions<IdentityOptions>>();
|
||||
identityOptions.Setup(a => a.Value).Returns(new IdentityOptions());
|
||||
var options = new Mock<IOptions<SecurityStampValidatorOptions>>();
|
||||
options.Setup(a => a.Value).Returns(new SecurityStampValidatorOptions { ValidationInterval = TimeSpan.Zero });
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object);
|
||||
var signInManager = new Mock<SignInManager<TestUser>>(userManager.Object,
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny<ClaimsPrincipal>())).ReturnsAsync(default(TestUser)).Verifiable();
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton(options.Object);
|
||||
services.AddSingleton(signInManager.Object);
|
||||
services.AddSingleton<ISecurityStampValidator>(new SecurityStampValidator<TestUser>(options.Object, signInManager.Object, new SystemClock()));
|
||||
httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider());
|
||||
var id = new ClaimsIdentity(IdentityConstants.ApplicationScheme);
|
||||
id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));
|
||||
|
||||
var ticket = new AuthenticationTicket(new ClaimsPrincipal(id),
|
||||
new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow.AddSeconds(-1) },
|
||||
IdentityConstants.ApplicationScheme);
|
||||
var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(IdentityConstants.ApplicationScheme) { HandlerType = typeof(NoopHandler) }.Build(), new CookieAuthenticationOptions(), ticket);
|
||||
Assert.NotNull(context.Properties);
|
||||
Assert.NotNull(context.Options);
|
||||
Assert.NotNull(context.Principal);
|
||||
await SecurityStampValidator.ValidatePrincipalAsync(context);
|
||||
Assert.Null(context.Principal);
|
||||
signInManager.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OnValidateIdentityRejectsWhenNoIssuedUtc()
|
||||
{
|
||||
var user = new TestUser("test");
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
var userManager = MockHelpers.MockUserManager<TestUser>();
|
||||
var identityOptions = new Mock<IOptions<IdentityOptions>>();
|
||||
identityOptions.Setup(a => a.Value).Returns(new IdentityOptions());
|
||||
var claimsManager = new Mock<IUserClaimsPrincipalFactory<TestUser>>();
|
||||
var options = new Mock<IOptions<SecurityStampValidatorOptions>>();
|
||||
options.Setup(a => a.Value).Returns(new SecurityStampValidatorOptions { ValidationInterval = TimeSpan.Zero });
|
||||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object);
|
||||
var signInManager = new Mock<SignInManager<TestUser>>(userManager.Object,
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny<ClaimsPrincipal>())).ReturnsAsync(default(TestUser)).Verifiable();
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton(options.Object);
|
||||
services.AddSingleton(signInManager.Object);
|
||||
services.AddSingleton<ISecurityStampValidator>(new SecurityStampValidator<TestUser>(options.Object, signInManager.Object, new SystemClock()));
|
||||
httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider());
|
||||
var id = new ClaimsIdentity(IdentityConstants.ApplicationScheme);
|
||||
id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));
|
||||
|
||||
var ticket = new AuthenticationTicket(new ClaimsPrincipal(id),
|
||||
new AuthenticationProperties(),
|
||||
IdentityConstants.ApplicationScheme);
|
||||
var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(IdentityConstants.ApplicationScheme) { HandlerType = typeof(NoopHandler) }.Build(), new CookieAuthenticationOptions(), ticket);
|
||||
Assert.NotNull(context.Properties);
|
||||
Assert.NotNull(context.Options);
|
||||
Assert.NotNull(context.Principal);
|
||||
await SecurityStampValidator.ValidatePrincipalAsync(context);
|
||||
Assert.Null(context.Principal);
|
||||
signInManager.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OnValidateIdentityDoesNotRejectsWhenNotExpired()
|
||||
{
|
||||
var user = new TestUser("test");
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
var userManager = MockHelpers.MockUserManager<TestUser>();
|
||||
var identityOptions = new Mock<IOptions<IdentityOptions>>();
|
||||
identityOptions.Setup(a => a.Value).Returns(new IdentityOptions());
|
||||
var claimsManager = new Mock<IUserClaimsPrincipalFactory<TestUser>>();
|
||||
var options = new Mock<IOptions<SecurityStampValidatorOptions>>();
|
||||
options.Setup(a => a.Value).Returns(new SecurityStampValidatorOptions { ValidationInterval = TimeSpan.FromDays(1) });
|
||||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object);
|
||||
var signInManager = new Mock<SignInManager<TestUser>>(userManager.Object,
|
||||
contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny<ClaimsPrincipal>())).Throws(new Exception("Shouldn't be called"));
|
||||
signInManager.Setup(s => s.SignInAsync(user, false, null)).Throws(new Exception("Shouldn't be called"));
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton(options.Object);
|
||||
services.AddSingleton(signInManager.Object);
|
||||
services.AddSingleton<ISecurityStampValidator>(new SecurityStampValidator<TestUser>(options.Object, signInManager.Object, new SystemClock()));
|
||||
httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider());
|
||||
var id = new ClaimsIdentity(IdentityConstants.ApplicationScheme);
|
||||
id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));
|
||||
|
||||
var ticket = new AuthenticationTicket(new ClaimsPrincipal(id),
|
||||
new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow },
|
||||
IdentityConstants.ApplicationScheme);
|
||||
var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(IdentityConstants.ApplicationScheme) { HandlerType = typeof(NoopHandler) }.Build(), new CookieAuthenticationOptions(), ticket);
|
||||
Assert.NotNull(context.Properties);
|
||||
Assert.NotNull(context.Options);
|
||||
Assert.NotNull(context.Principal);
|
||||
await SecurityStampValidator.ValidatePrincipalAsync(context);
|
||||
Assert.NotNull(context.Principal);
|
||||
}
|
||||
}
|
||||
}
|
||||
+866
@@ -0,0 +1,866 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class SignManagerInTest
|
||||
{
|
||||
//[Theory]
|
||||
//[InlineData(true)]
|
||||
//[InlineData(false)]
|
||||
//public async Task VerifyAccountControllerSignInFunctional(bool isPersistent)
|
||||
//{
|
||||
// var app = new ApplicationBuilder(new ServiceCollection().BuildServiceProvider());
|
||||
// app.UseCookieAuthentication(new CookieAuthenticationOptions
|
||||
// {
|
||||
// AuthenticationScheme = ClaimsIdentityOptions.DefaultAuthenticationScheme
|
||||
// });
|
||||
|
||||
// TODO: how to functionally test context?
|
||||
// var context = new DefaultHttpContext(new FeatureCollection());
|
||||
// var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
// contextAccessor.Setup(a => a.Value).Returns(context);
|
||||
// app.UseServices(services =>
|
||||
// {
|
||||
// services.AddSingleton(contextAccessor.Object);
|
||||
// services.AddSingleton<Ilogger>(new Nulllogger());
|
||||
// services.AddIdentity<ApplicationUser, IdentityRole>(s =>
|
||||
// {
|
||||
// s.AddUserStore(() => new InMemoryUserStore<ApplicationUser>());
|
||||
// s.AddUserManager<ApplicationUserManager>();
|
||||
// s.AddRoleStore(() => new InMemoryRoleStore<IdentityRole>());
|
||||
// s.AddRoleManager<ApplicationRoleManager>();
|
||||
// });
|
||||
// services.AddTransient<ApplicationHttpSignInManager>();
|
||||
// });
|
||||
|
||||
// // Act
|
||||
// var user = new ApplicationUser
|
||||
// {
|
||||
// UserName = "Yolo"
|
||||
// };
|
||||
// const string password = "Yol0Sw@g!";
|
||||
// var userManager = app.ApplicationServices.GetRequiredService<ApplicationUserManager>();
|
||||
// var HttpSignInManager = app.ApplicationServices.GetRequiredService<ApplicationHttpSignInManager>();
|
||||
|
||||
// IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user, password));
|
||||
// var result = await HttpSignInManager.PasswordSignInAsync(user.UserName, password, isPersistent, false);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal(SignInStatus.Success, result);
|
||||
// contextAccessor.Verify();
|
||||
//}
|
||||
|
||||
[Fact]
|
||||
public void ConstructorNullChecks()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>("userManager", () => new SignInManager<TestUser>(null, null, null, null, null, null));
|
||||
var userManager = MockHelpers.MockUserManager<TestUser>().Object;
|
||||
Assert.Throws<ArgumentNullException>("contextAccessor", () => new SignInManager<TestUser>(userManager, null, null, null, null, null));
|
||||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
var context = new Mock<HttpContext>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(context.Object);
|
||||
Assert.Throws<ArgumentNullException>("claimsFactory", () => new SignInManager<TestUser>(userManager, contextAccessor.Object, null, null, null, null));
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
//public async Task EnsureClaimsPrincipalFactoryCreateIdentityCalled()
|
||||
//{
|
||||
// // Setup
|
||||
// var user = new TestUser { UserName = "Foo" };
|
||||
// var userManager = MockHelpers.TestUserManager<TestUser>();
|
||||
// var identityFactory = new Mock<IUserClaimsPrincipalFactory<TestUser>>();
|
||||
// const string authType = "Test";
|
||||
// var testIdentity = new ClaimsPrincipal();
|
||||
// identityFactory.Setup(s => s.CreateAsync(user)).ReturnsAsync(testIdentity).Verifiable();
|
||||
// var context = new Mock<HttpContext>();
|
||||
// var response = new Mock<HttpResponse>();
|
||||
// context.Setup(c => c.Response).Returns(response.Object).Verifiable();
|
||||
// response.Setup(r => r.SignIn(testIdentity, It.IsAny<AuthenticationProperties>())).Verifiable();
|
||||
// var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
// contextAccessor.Setup(a => a.Value).Returns(context.Object);
|
||||
// var helper = new HttpAuthenticationManager(contextAccessor.Object);
|
||||
|
||||
// // Act
|
||||
// helper.SignIn(user, false);
|
||||
|
||||
// // Assert
|
||||
// identityFactory.Verify();
|
||||
// context.Verify();
|
||||
// contextAccessor.Verify();
|
||||
// response.Verify();
|
||||
//}
|
||||
|
||||
[Fact]
|
||||
public async Task PasswordSignInReturnsLockedOutWhenLockedOut()
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = SetupUserManager(user);
|
||||
manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable();
|
||||
manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(true).Verifiable();
|
||||
|
||||
var context = new Mock<HttpContext>();
|
||||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(context.Object);
|
||||
var roleManager = MockHelpers.MockRoleManager<TestRole>();
|
||||
var identityOptions = new IdentityOptions();
|
||||
var options = new Mock<IOptions<IdentityOptions>>();
|
||||
options.Setup(a => a.Value).Returns(identityOptions);
|
||||
var claimsFactory = new UserClaimsPrincipalFactory<TestUser, TestRole>(manager.Object, roleManager.Object, options.Object);
|
||||
var logStore = new StringBuilder();
|
||||
var logger = MockHelpers.MockILogger<SignInManager<TestUser>>(logStore);
|
||||
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory, options.Object, logger.Object, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.True(result.IsLockedOut);
|
||||
Assert.Contains($"User {user.Id} is currently locked out.", logStore.ToString());
|
||||
manager.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CheckPasswordSignInReturnsLockedOutWhenLockedOut()
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = SetupUserManager(user);
|
||||
manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable();
|
||||
manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(true).Verifiable();
|
||||
|
||||
var context = new Mock<HttpContext>();
|
||||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(context.Object);
|
||||
var roleManager = MockHelpers.MockRoleManager<TestRole>();
|
||||
var identityOptions = new IdentityOptions();
|
||||
var options = new Mock<IOptions<IdentityOptions>>();
|
||||
options.Setup(a => a.Value).Returns(identityOptions);
|
||||
var claimsFactory = new UserClaimsPrincipalFactory<TestUser, TestRole>(manager.Object, roleManager.Object, options.Object);
|
||||
var logStore = new StringBuilder();
|
||||
var logger = MockHelpers.MockILogger<SignInManager<TestUser>>(logStore);
|
||||
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory, options.Object, logger.Object, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
|
||||
// Act
|
||||
var result = await helper.CheckPasswordSignInAsync(user, "bogus", false);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.True(result.IsLockedOut);
|
||||
Assert.Contains($"User {user.Id} is currently locked out.", logStore.ToString());
|
||||
manager.Verify();
|
||||
}
|
||||
|
||||
private static Mock<UserManager<TestUser>> SetupUserManager(TestUser user)
|
||||
{
|
||||
var manager = MockHelpers.MockUserManager<TestUser>();
|
||||
manager.Setup(m => m.FindByNameAsync(user.UserName)).ReturnsAsync(user);
|
||||
manager.Setup(m => m.FindByIdAsync(user.Id)).ReturnsAsync(user);
|
||||
manager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id.ToString());
|
||||
manager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName);
|
||||
return manager;
|
||||
}
|
||||
|
||||
private static SignInManager<TestUser> SetupSignInManager(UserManager<TestUser> manager, HttpContext context, StringBuilder logStore = null, IdentityOptions identityOptions = null)
|
||||
{
|
||||
var contextAccessor = new Mock<IHttpContextAccessor>();
|
||||
contextAccessor.Setup(a => a.HttpContext).Returns(context);
|
||||
var roleManager = MockHelpers.MockRoleManager<TestRole>();
|
||||
identityOptions = identityOptions ?? new IdentityOptions();
|
||||
var options = new Mock<IOptions<IdentityOptions>>();
|
||||
options.Setup(a => a.Value).Returns(identityOptions);
|
||||
var claimsFactory = new UserClaimsPrincipalFactory<TestUser, TestRole>(manager, roleManager.Object, options.Object);
|
||||
var sm = new SignInManager<TestUser>(manager, contextAccessor.Object, claimsFactory, options.Object, null, new Mock<IAuthenticationSchemeProvider>().Object);
|
||||
sm.Logger = MockHelpers.MockILogger<SignInManager<TestUser>>(logStore ?? new StringBuilder()).Object;
|
||||
return sm;
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task CanPasswordSignIn(bool isPersistent)
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = SetupUserManager(user);
|
||||
manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable();
|
||||
manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable();
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable();
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
var auth = MockAuth(context);
|
||||
SetupSignIn(context, auth, user.Id, isPersistent);
|
||||
var helper = SetupSignInManager(manager.Object, context);
|
||||
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync(user.UserName, "password", isPersistent, false);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Succeeded);
|
||||
manager.Verify();
|
||||
auth.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanPasswordSignInWithNoLogger()
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = SetupUserManager(user);
|
||||
manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable();
|
||||
manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable();
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable();
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
var auth = MockAuth(context);
|
||||
SetupSignIn(context, auth, user.Id, false);
|
||||
var helper = SetupSignInManager(manager.Object, context);
|
||||
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync(user.UserName, "password", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Succeeded);
|
||||
manager.Verify();
|
||||
auth.Verify();
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task PasswordSignInWorksWithNonTwoFactorStore()
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = SetupUserManager(user);
|
||||
manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable();
|
||||
manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable();
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable();
|
||||
manager.Setup(m => m.ResetAccessFailedCountAsync(user)).ReturnsAsync(IdentityResult.Success).Verifiable();
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
var auth = MockAuth(context);
|
||||
SetupSignIn(context, auth);
|
||||
var helper = SetupSignInManager(manager.Object, context);
|
||||
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync(user.UserName, "password", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Succeeded);
|
||||
manager.Verify();
|
||||
auth.Verify();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task PasswordSignInRequiresVerification(bool supportsLockout)
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = SetupUserManager(user);
|
||||
manager.Setup(m => m.SupportsUserLockout).Returns(supportsLockout).Verifiable();
|
||||
if (supportsLockout)
|
||||
{
|
||||
manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable();
|
||||
}
|
||||
IList<string> providers = new List<string>();
|
||||
providers.Add("PhoneNumber");
|
||||
manager.Setup(m => m.GetValidTwoFactorProvidersAsync(user)).Returns(Task.FromResult(providers)).Verifiable();
|
||||
manager.Setup(m => m.SupportsUserTwoFactor).Returns(true).Verifiable();
|
||||
manager.Setup(m => m.GetTwoFactorEnabledAsync(user)).ReturnsAsync(true).Verifiable();
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable();
|
||||
if (supportsLockout)
|
||||
{
|
||||
manager.Setup(m => m.ResetAccessFailedCountAsync(user)).ReturnsAsync(IdentityResult.Success).Verifiable();
|
||||
}
|
||||
var context = new DefaultHttpContext();
|
||||
var helper = SetupSignInManager(manager.Object, context);
|
||||
var auth = MockAuth(context);
|
||||
auth.Setup(a => a.SignInAsync(context, IdentityConstants.TwoFactorUserIdScheme,
|
||||
It.Is<ClaimsPrincipal>(id => id.FindFirstValue(ClaimTypes.Name) == user.Id),
|
||||
It.IsAny<AuthenticationProperties>())).Returns(Task.FromResult(0)).Verifiable();
|
||||
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync(user.UserName, "password", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.True(result.RequiresTwoFactor);
|
||||
manager.Verify();
|
||||
auth.Verify();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task ExternalSignInRequiresVerificationIfNotBypassed(bool bypass)
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
const string loginProvider = "login";
|
||||
const string providerKey = "fookey";
|
||||
var manager = SetupUserManager(user);
|
||||
manager.Setup(m => m.SupportsUserLockout).Returns(false).Verifiable();
|
||||
manager.Setup(m => m.FindByLoginAsync(loginProvider, providerKey)).ReturnsAsync(user).Verifiable();
|
||||
if (!bypass)
|
||||
{
|
||||
IList<string> providers = new List<string>();
|
||||
providers.Add("PhoneNumber");
|
||||
manager.Setup(m => m.GetValidTwoFactorProvidersAsync(user)).Returns(Task.FromResult(providers)).Verifiable();
|
||||
manager.Setup(m => m.SupportsUserTwoFactor).Returns(true).Verifiable();
|
||||
manager.Setup(m => m.GetTwoFactorEnabledAsync(user)).ReturnsAsync(true).Verifiable();
|
||||
}
|
||||
var context = new DefaultHttpContext();
|
||||
var auth = MockAuth(context);
|
||||
var helper = SetupSignInManager(manager.Object, context);
|
||||
|
||||
if (bypass)
|
||||
{
|
||||
SetupSignIn(context, auth, user.Id, false, loginProvider);
|
||||
}
|
||||
else
|
||||
{
|
||||
auth.Setup(a => a.SignInAsync(context, IdentityConstants.TwoFactorUserIdScheme,
|
||||
It.Is<ClaimsPrincipal>(id => id.FindFirstValue(ClaimTypes.Name) == user.Id),
|
||||
It.IsAny<AuthenticationProperties>())).Returns(Task.FromResult(0)).Verifiable();
|
||||
}
|
||||
|
||||
// Act
|
||||
var result = await helper.ExternalLoginSignInAsync(loginProvider, providerKey, isPersistent: false, bypassTwoFactor: bypass);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(bypass, result.Succeeded);
|
||||
Assert.Equal(!bypass, result.RequiresTwoFactor);
|
||||
manager.Verify();
|
||||
auth.Verify();
|
||||
}
|
||||
|
||||
private class GoodTokenProvider : AuthenticatorTokenProvider<TestUser>
|
||||
{
|
||||
public override Task<bool> ValidateAsync(string purpose, string token, UserManager<TestUser> manager, TestUser user)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//[Theory]
|
||||
//[InlineData(null, true, true)]
|
||||
//[InlineData("Authenticator", false, true)]
|
||||
//[InlineData("Gooblygook", true, false)]
|
||||
//[InlineData("--", false, false)]
|
||||
//public async Task CanTwoFactorAuthenticatorSignIn(string providerName, bool isPersistent, bool rememberClient)
|
||||
//{
|
||||
// // Setup
|
||||
// var user = new TestUser { UserName = "Foo" };
|
||||
// const string code = "3123";
|
||||
// var manager = SetupUserManager(user);
|
||||
// manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable();
|
||||
// manager.Setup(m => m.VerifyTwoFactorTokenAsync(user, providerName ?? TokenOptions.DefaultAuthenticatorProvider, code)).ReturnsAsync(true).Verifiable();
|
||||
// manager.Setup(m => m.ResetAccessFailedCountAsync(user)).ReturnsAsync(IdentityResult.Success).Verifiable();
|
||||
|
||||
// var context = new DefaultHttpContext();
|
||||
// var auth = MockAuth(context);
|
||||
// var helper = SetupSignInManager(manager.Object, context);
|
||||
// var twoFactorInfo = new SignInManager<TestUser>.TwoFactorAuthenticationInfo { UserId = user.Id };
|
||||
// if (providerName != null)
|
||||
// {
|
||||
// helper.Options.Tokens.AuthenticatorTokenProvider = providerName;
|
||||
// }
|
||||
// var id = helper.StoreTwoFactorInfo(user.Id, null);
|
||||
// SetupSignIn(context, auth, user.Id, isPersistent);
|
||||
// auth.Setup(a => a.AuthenticateAsync(context, IdentityConstants.TwoFactorUserIdScheme))
|
||||
// .ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(id, null, IdentityConstants.TwoFactorUserIdScheme))).Verifiable();
|
||||
// if (rememberClient)
|
||||
// {
|
||||
// auth.Setup(a => a.SignInAsync(context,
|
||||
// IdentityConstants.TwoFactorRememberMeScheme,
|
||||
// It.Is<ClaimsPrincipal>(i => i.FindFirstValue(ClaimTypes.Name) == user.Id
|
||||
// && i.Identities.First().AuthenticationType == IdentityConstants.TwoFactorRememberMeScheme),
|
||||
// It.IsAny<AuthenticationProperties>())).Returns(Task.FromResult(0)).Verifiable();
|
||||
// }
|
||||
|
||||
// // Act
|
||||
// var result = await helper.TwoFactorAuthenticatorSignInAsync(code, isPersistent, rememberClient);
|
||||
|
||||
// // Assert
|
||||
// Assert.True(result.Succeeded);
|
||||
// manager.Verify();
|
||||
// auth.Verify();
|
||||
//}
|
||||
|
||||
//[Theory]
|
||||
//[InlineData(true, true)]
|
||||
//[InlineData(true, false)]
|
||||
//[InlineData(false, true)]
|
||||
//[InlineData(false, false)]
|
||||
//public async Task CanTwoFactorRecoveryCodeSignIn(bool supportsLockout, bool externalLogin)
|
||||
//{
|
||||
// // Setup
|
||||
// var user = new TestUser { UserName = "Foo" };
|
||||
// const string bypassCode = "someCode";
|
||||
// var manager = SetupUserManager(user);
|
||||
// manager.Setup(m => m.SupportsUserLockout).Returns(supportsLockout).Verifiable();
|
||||
// manager.Setup(m => m.RedeemTwoFactorRecoveryCodeAsync(user, bypassCode)).ReturnsAsync(IdentityResult.Success).Verifiable();
|
||||
// if (supportsLockout)
|
||||
// {
|
||||
// manager.Setup(m => m.ResetAccessFailedCountAsync(user)).ReturnsAsync(IdentityResult.Success).Verifiable();
|
||||
// }
|
||||
// var context = new DefaultHttpContext();
|
||||
// var auth = MockAuth(context);
|
||||
// var helper = SetupSignInManager(manager.Object, context);
|
||||
// var twoFactorInfo = new SignInManager<TestUser>.TwoFactorAuthenticationInfo { UserId = user.Id };
|
||||
// var loginProvider = "loginprovider";
|
||||
// var id = helper.StoreTwoFactorInfo(user.Id, externalLogin ? loginProvider : null);
|
||||
// if (externalLogin)
|
||||
// {
|
||||
// auth.Setup(a => a.SignInAsync(context,
|
||||
// IdentityConstants.ApplicationScheme,
|
||||
// It.Is<ClaimsPrincipal>(i => i.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider
|
||||
// && i.FindFirstValue(ClaimTypes.NameIdentifier) == user.Id),
|
||||
// It.IsAny<AuthenticationProperties>())).Returns(Task.FromResult(0)).Verifiable();
|
||||
// auth.Setup(a => a.SignOutAsync(context, IdentityConstants.ExternalScheme, It.IsAny<AuthenticationProperties>())).Returns(Task.FromResult(0)).Verifiable();
|
||||
// auth.Setup(a => a.SignOutAsync(context, IdentityConstants.TwoFactorUserIdScheme, It.IsAny<AuthenticationProperties>())).Returns(Task.FromResult(0)).Verifiable();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// SetupSignIn(context, auth, user.Id);
|
||||
// }
|
||||
// auth.Setup(a => a.AuthenticateAsync(context, IdentityConstants.TwoFactorUserIdScheme))
|
||||
// .ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(id, null, IdentityConstants.TwoFactorUserIdScheme))).Verifiable();
|
||||
|
||||
// // Act
|
||||
// var result = await helper.TwoFactorRecoveryCodeSignInAsync(bypassCode);
|
||||
|
||||
// // Assert
|
||||
// Assert.True(result.Succeeded);
|
||||
// manager.Verify();
|
||||
// auth.Verify();
|
||||
//}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true, true)]
|
||||
[InlineData(true, false)]
|
||||
[InlineData(false, true)]
|
||||
[InlineData(false, false)]
|
||||
public async Task CanExternalSignIn(bool isPersistent, bool supportsLockout)
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
const string loginProvider = "login";
|
||||
const string providerKey = "fookey";
|
||||
var manager = SetupUserManager(user);
|
||||
manager.Setup(m => m.SupportsUserLockout).Returns(supportsLockout).Verifiable();
|
||||
if (supportsLockout)
|
||||
{
|
||||
manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable();
|
||||
}
|
||||
manager.Setup(m => m.FindByLoginAsync(loginProvider, providerKey)).ReturnsAsync(user).Verifiable();
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
var auth = MockAuth(context);
|
||||
var helper = SetupSignInManager(manager.Object, context);
|
||||
SetupSignIn(context, auth, user.Id, isPersistent, loginProvider);
|
||||
|
||||
// Act
|
||||
var result = await helper.ExternalLoginSignInAsync(loginProvider, providerKey, isPersistent);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Succeeded);
|
||||
manager.Verify();
|
||||
auth.Verify();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task CanResignIn(bool externalLogin)
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var context = new DefaultHttpContext();
|
||||
var auth = MockAuth(context);
|
||||
var loginProvider = "loginprovider";
|
||||
var id = new ClaimsIdentity();
|
||||
if (externalLogin)
|
||||
{
|
||||
id.AddClaim(new Claim(ClaimTypes.AuthenticationMethod, loginProvider));
|
||||
}
|
||||
// REVIEW: auth changes we lost the ability to mock is persistent
|
||||
//var properties = new AuthenticationProperties { IsPersistent = isPersistent };
|
||||
var authResult = AuthenticateResult.NoResult();
|
||||
auth.Setup(a => a.AuthenticateAsync(context, IdentityConstants.ApplicationScheme))
|
||||
.Returns(Task.FromResult(authResult)).Verifiable();
|
||||
var manager = SetupUserManager(user);
|
||||
var signInManager = new Mock<SignInManager<TestUser>>(manager.Object,
|
||||
new HttpContextAccessor { HttpContext = context },
|
||||
new Mock<IUserClaimsPrincipalFactory<TestUser>>().Object,
|
||||
null, null, new Mock<IAuthenticationSchemeProvider>().Object)
|
||||
{ CallBase = true };
|
||||
//signInManager.Setup(s => s.SignInAsync(user, It.Is<AuthenticationProperties>(p => p.IsPersistent == isPersistent),
|
||||
//externalLogin? loginProvider : null)).Returns(Task.FromResult(0)).Verifiable();
|
||||
signInManager.Setup(s => s.SignInAsync(user, It.IsAny<AuthenticationProperties>(), null)).Returns(Task.FromResult(0)).Verifiable();
|
||||
signInManager.Object.Context = context;
|
||||
|
||||
// Act
|
||||
await signInManager.Object.RefreshSignInAsync(user);
|
||||
|
||||
// Assert
|
||||
auth.Verify();
|
||||
signInManager.Verify();
|
||||
}
|
||||
|
||||
//[Theory]
|
||||
//[InlineData(true, true, true, true)]
|
||||
//[InlineData(true, true, false, true)]
|
||||
//[InlineData(true, false, true, true)]
|
||||
//[InlineData(true, false, false, true)]
|
||||
//[InlineData(false, true, true, true)]
|
||||
//[InlineData(false, true, false, true)]
|
||||
//[InlineData(false, false, true, true)]
|
||||
//[InlineData(false, false, false, true)]
|
||||
//[InlineData(true, true, true, false)]
|
||||
//[InlineData(true, true, false, false)]
|
||||
//[InlineData(true, false, true, false)]
|
||||
//[InlineData(true, false, false, false)]
|
||||
//[InlineData(false, true, true, false)]
|
||||
//[InlineData(false, true, false, false)]
|
||||
//[InlineData(false, false, true, false)]
|
||||
//[InlineData(false, false, false, false)]
|
||||
//public async Task CanTwoFactorSignIn(bool isPersistent, bool supportsLockout, bool externalLogin, bool rememberClient)
|
||||
//{
|
||||
// // Setup
|
||||
// var user = new TestUser { UserName = "Foo" };
|
||||
// var manager = SetupUserManager(user);
|
||||
// var provider = "twofactorprovider";
|
||||
// var code = "123456";
|
||||
// manager.Setup(m => m.SupportsUserLockout).Returns(supportsLockout).Verifiable();
|
||||
// if (supportsLockout)
|
||||
// {
|
||||
// manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable();
|
||||
// manager.Setup(m => m.ResetAccessFailedCountAsync(user)).ReturnsAsync(IdentityResult.Success).Verifiable();
|
||||
// }
|
||||
// manager.Setup(m => m.VerifyTwoFactorTokenAsync(user, provider, code)).ReturnsAsync(true).Verifiable();
|
||||
// var context = new DefaultHttpContext();
|
||||
// var auth = MockAuth(context);
|
||||
// var helper = SetupSignInManager(manager.Object, context);
|
||||
// var twoFactorInfo = new SignInManager<TestUser>.TwoFactorAuthenticationInfo { UserId = user.Id };
|
||||
// var loginProvider = "loginprovider";
|
||||
// var id = helper.StoreTwoFactorInfo(user.Id, externalLogin ? loginProvider : null);
|
||||
// if (externalLogin)
|
||||
// {
|
||||
// auth.Setup(a => a.SignInAsync(context,
|
||||
// IdentityConstants.ApplicationScheme,
|
||||
// It.Is<ClaimsPrincipal>(i => i.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider
|
||||
// && i.FindFirstValue(ClaimTypes.NameIdentifier) == user.Id),
|
||||
// It.IsAny<AuthenticationProperties>())).Returns(Task.FromResult(0)).Verifiable();
|
||||
// // REVIEW: restore ability to test is persistent
|
||||
// //It.Is<AuthenticationProperties>(v => v.IsPersistent == isPersistent))).Verifiable();
|
||||
// auth.Setup(a => a.SignOutAsync(context, IdentityConstants.ExternalScheme, It.IsAny<AuthenticationProperties>())).Returns(Task.FromResult(0)).Verifiable();
|
||||
// auth.Setup(a => a.SignOutAsync(context, IdentityConstants.TwoFactorUserIdScheme, It.IsAny<AuthenticationProperties>())).Returns(Task.FromResult(0)).Verifiable();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// SetupSignIn(context, auth, user.Id);
|
||||
// }
|
||||
// if (rememberClient)
|
||||
// {
|
||||
// auth.Setup(a => a.SignInAsync(context,
|
||||
// IdentityConstants.TwoFactorRememberMeScheme,
|
||||
// It.Is<ClaimsPrincipal>(i => i.FindFirstValue(ClaimTypes.Name) == user.Id
|
||||
// && i.Identities.First().AuthenticationType == IdentityConstants.TwoFactorRememberMeScheme),
|
||||
// It.IsAny<AuthenticationProperties>())).Returns(Task.FromResult(0)).Verifiable();
|
||||
// //It.Is<AuthenticationProperties>(v => v.IsPersistent == true))).Returns(Task.FromResult(0)).Verifiable();
|
||||
// }
|
||||
// auth.Setup(a => a.AuthenticateAsync(context, IdentityConstants.TwoFactorUserIdScheme))
|
||||
// .ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(id, null, IdentityConstants.TwoFactorUserIdScheme))).Verifiable();
|
||||
|
||||
// // Act
|
||||
// var result = await helper.TwoFactorSignInAsync(provider, code, isPersistent, rememberClient);
|
||||
|
||||
// // Assert
|
||||
// Assert.True(result.Succeeded);
|
||||
// manager.Verify();
|
||||
// auth.Verify();
|
||||
//}
|
||||
|
||||
[Fact]
|
||||
public async Task RememberClientStoresUserId()
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = SetupUserManager(user);
|
||||
var context = new DefaultHttpContext();
|
||||
var auth = MockAuth(context);
|
||||
var helper = SetupSignInManager(manager.Object, context);
|
||||
auth.Setup(a => a.SignInAsync(
|
||||
context,
|
||||
IdentityConstants.TwoFactorRememberMeScheme,
|
||||
It.Is<ClaimsPrincipal>(i => i.FindFirstValue(ClaimTypes.Name) == user.Id
|
||||
&& i.Identities.First().AuthenticationType == IdentityConstants.TwoFactorRememberMeScheme),
|
||||
It.Is<AuthenticationProperties>(v => v.IsPersistent == true))).Returns(Task.FromResult(0)).Verifiable();
|
||||
|
||||
|
||||
// Act
|
||||
await helper.RememberTwoFactorClientAsync(user);
|
||||
|
||||
// Assert
|
||||
manager.Verify();
|
||||
auth.Verify();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task RememberBrowserSkipsTwoFactorVerificationSignIn(bool isPersistent)
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = SetupUserManager(user);
|
||||
manager.Setup(m => m.GetTwoFactorEnabledAsync(user)).ReturnsAsync(true).Verifiable();
|
||||
IList<string> providers = new List<string>();
|
||||
providers.Add("PhoneNumber");
|
||||
manager.Setup(m => m.GetValidTwoFactorProvidersAsync(user)).Returns(Task.FromResult(providers)).Verifiable();
|
||||
manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable();
|
||||
manager.Setup(m => m.SupportsUserTwoFactor).Returns(true).Verifiable();
|
||||
manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable();
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable();
|
||||
var context = new DefaultHttpContext();
|
||||
var auth = MockAuth(context);
|
||||
SetupSignIn(context, auth);
|
||||
var id = new ClaimsIdentity(IdentityConstants.TwoFactorRememberMeScheme);
|
||||
id.AddClaim(new Claim(ClaimTypes.Name, user.Id));
|
||||
auth.Setup(a => a.AuthenticateAsync(context, IdentityConstants.TwoFactorRememberMeScheme))
|
||||
.ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(id), null, IdentityConstants.TwoFactorRememberMeScheme))).Verifiable();
|
||||
var helper = SetupSignInManager(manager.Object, context);
|
||||
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync(user.UserName, "password", isPersistent, false);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Succeeded);
|
||||
manager.Verify();
|
||||
auth.Verify();
|
||||
}
|
||||
|
||||
private Mock<IAuthenticationService> MockAuth(HttpContext context)
|
||||
{
|
||||
var auth = new Mock<IAuthenticationService>();
|
||||
context.RequestServices = new ServiceCollection().AddSingleton(auth.Object).BuildServiceProvider();
|
||||
return auth;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SignOutCallsContextResponseSignOut()
|
||||
{
|
||||
// Setup
|
||||
var manager = MockHelpers.TestUserManager<TestUser>();
|
||||
var context = new DefaultHttpContext();
|
||||
var auth = MockAuth(context);
|
||||
auth.Setup(a => a.SignOutAsync(context, IdentityConstants.ApplicationScheme, It.IsAny<AuthenticationProperties>())).Returns(Task.FromResult(0)).Verifiable();
|
||||
auth.Setup(a => a.SignOutAsync(context, IdentityConstants.TwoFactorUserIdScheme, It.IsAny<AuthenticationProperties>())).Returns(Task.FromResult(0)).Verifiable();
|
||||
auth.Setup(a => a.SignOutAsync(context, IdentityConstants.ExternalScheme, It.IsAny<AuthenticationProperties>())).Returns(Task.FromResult(0)).Verifiable();
|
||||
var helper = SetupSignInManager(manager, context, null, manager.Options);
|
||||
|
||||
// Act
|
||||
await helper.SignOutAsync();
|
||||
|
||||
// Assert
|
||||
auth.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PasswordSignInFailsWithWrongPassword()
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = SetupUserManager(user);
|
||||
manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable();
|
||||
manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable();
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "bogus")).ReturnsAsync(false).Verifiable();
|
||||
var context = new Mock<HttpContext>();
|
||||
var logStore = new StringBuilder();
|
||||
var helper = SetupSignInManager(manager.Object, context.Object, logStore);
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, false);
|
||||
var checkResult = await helper.CheckPasswordSignInAsync(user, "bogus", false);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.False(checkResult.Succeeded);
|
||||
Assert.True(logStore.ToString().Contains($"User {user.Id} failed to provide the correct password."));
|
||||
manager.Verify();
|
||||
context.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PasswordSignInFailsWithUnknownUser()
|
||||
{
|
||||
// Setup
|
||||
var manager = MockHelpers.MockUserManager<TestUser>();
|
||||
manager.Setup(m => m.FindByNameAsync("bogus")).ReturnsAsync(default(TestUser)).Verifiable();
|
||||
var context = new Mock<HttpContext>();
|
||||
var helper = SetupSignInManager(manager.Object, context.Object);
|
||||
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync("bogus", "bogus", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Succeeded);
|
||||
manager.Verify();
|
||||
context.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PasswordSignInFailsWithWrongPasswordCanAccessFailedAndLockout()
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = SetupUserManager(user);
|
||||
var lockedout = false;
|
||||
manager.Setup(m => m.AccessFailedAsync(user)).Returns(() =>
|
||||
{
|
||||
lockedout = true;
|
||||
return Task.FromResult(IdentityResult.Success);
|
||||
}).Verifiable();
|
||||
manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable();
|
||||
manager.Setup(m => m.IsLockedOutAsync(user)).Returns(() => Task.FromResult(lockedout));
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "bogus")).ReturnsAsync(false).Verifiable();
|
||||
var context = new Mock<HttpContext>();
|
||||
var helper = SetupSignInManager(manager.Object, context.Object);
|
||||
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, true);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.True(result.IsLockedOut);
|
||||
manager.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CheckPasswordSignInFailsWithWrongPasswordCanAccessFailedAndLockout()
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = SetupUserManager(user);
|
||||
var lockedout = false;
|
||||
manager.Setup(m => m.AccessFailedAsync(user)).Returns(() =>
|
||||
{
|
||||
lockedout = true;
|
||||
return Task.FromResult(IdentityResult.Success);
|
||||
}).Verifiable();
|
||||
manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable();
|
||||
manager.Setup(m => m.IsLockedOutAsync(user)).Returns(() => Task.FromResult(lockedout));
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "bogus")).ReturnsAsync(false).Verifiable();
|
||||
var context = new Mock<HttpContext>();
|
||||
var helper = SetupSignInManager(manager.Object, context.Object);
|
||||
|
||||
// Act
|
||||
var result = await helper.CheckPasswordSignInAsync(user, "bogus", true);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.True(result.IsLockedOut);
|
||||
manager.Verify();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task CanRequireConfirmedEmailForPasswordSignIn(bool confirmed)
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = SetupUserManager(user);
|
||||
manager.Setup(m => m.IsEmailConfirmedAsync(user)).ReturnsAsync(confirmed).Verifiable();
|
||||
if (confirmed)
|
||||
{
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable();
|
||||
}
|
||||
var context = new DefaultHttpContext();
|
||||
var auth = MockAuth(context);
|
||||
if (confirmed)
|
||||
{
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable();
|
||||
SetupSignIn(context, auth);
|
||||
}
|
||||
var identityOptions = new IdentityOptions();
|
||||
identityOptions.SignIn.RequireConfirmedEmail = true;
|
||||
var logStore = new StringBuilder();
|
||||
var helper = SetupSignInManager(manager.Object, context, logStore, identityOptions);
|
||||
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync(user, "password", false, false);
|
||||
|
||||
// Assert
|
||||
|
||||
Assert.Equal(confirmed, result.Succeeded);
|
||||
Assert.NotEqual(confirmed, result.IsNotAllowed);
|
||||
Assert.Equal(confirmed, !logStore.ToString().Contains($"User {user.Id} cannot sign in without a confirmed email."));
|
||||
|
||||
manager.Verify();
|
||||
auth.Verify();
|
||||
}
|
||||
|
||||
private static void SetupSignIn(HttpContext context, Mock<IAuthenticationService> auth, string userId = null, bool? isPersistent = null, string loginProvider = null)
|
||||
{
|
||||
auth.Setup(a => a.SignInAsync(context,
|
||||
IdentityConstants.ApplicationScheme,
|
||||
It.Is<ClaimsPrincipal>(id =>
|
||||
(userId == null || id.FindFirstValue(ClaimTypes.NameIdentifier) == userId) &&
|
||||
(loginProvider == null || id.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider)),
|
||||
It.Is<AuthenticationProperties>(v => isPersistent == null || v.IsPersistent == isPersistent))).Returns(Task.FromResult(0)).Verifiable();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task CanRequireConfirmedPhoneNumberForPasswordSignIn(bool confirmed)
|
||||
{
|
||||
// Setup
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
var manager = SetupUserManager(user);
|
||||
manager.Setup(m => m.IsPhoneNumberConfirmedAsync(user)).ReturnsAsync(confirmed).Verifiable();
|
||||
var context = new DefaultHttpContext();
|
||||
var auth = MockAuth(context);
|
||||
if (confirmed)
|
||||
{
|
||||
manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable();
|
||||
SetupSignIn(context, auth);
|
||||
}
|
||||
|
||||
var identityOptions = new IdentityOptions();
|
||||
identityOptions.SignIn.RequireConfirmedPhoneNumber = true;
|
||||
var logStore = new StringBuilder();
|
||||
var helper = SetupSignInManager(manager.Object, context, logStore, identityOptions);
|
||||
|
||||
// Act
|
||||
var result = await helper.PasswordSignInAsync(user, "password", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(confirmed, result.Succeeded);
|
||||
Assert.NotEqual(confirmed, result.IsNotAllowed);
|
||||
Assert.Equal(confirmed, !logStore.ToString().Contains($"User {user.Id} cannot sign in without a confirmed phone number."));
|
||||
manager.Verify();
|
||||
auth.Verify();
|
||||
}
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class UserClaimsPrincipalFactoryTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task CreateIdentityNullChecks()
|
||||
{
|
||||
var userManager = MockHelpers.MockUserManager<TestUser>().Object;
|
||||
var roleManager = MockHelpers.MockRoleManager<TestRole>().Object;
|
||||
var options = new Mock<IOptions<IdentityOptions>>();
|
||||
Assert.Throws<ArgumentNullException>("optionsAccessor",
|
||||
() => new UserClaimsPrincipalFactory<TestUser, TestRole>(userManager, roleManager, options.Object));
|
||||
var identityOptions = new IdentityOptions();
|
||||
options.Setup(a => a.Value).Returns(identityOptions);
|
||||
var factory = new UserClaimsPrincipalFactory<TestUser, TestRole>(userManager, roleManager, options.Object);
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user",
|
||||
async () => await factory.CreateAsync(null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false, false, false)]
|
||||
[InlineData(false, true, false)]
|
||||
[InlineData(true, false, false)]
|
||||
[InlineData(true, true, false)]
|
||||
[InlineData(true, false, true)]
|
||||
[InlineData(true, true, true)]
|
||||
public async Task EnsureClaimsIdentityHasExpectedClaims(bool supportRoles, bool supportClaims, bool supportRoleClaims)
|
||||
{
|
||||
// Setup
|
||||
var userManager = MockHelpers.MockUserManager<TestUser>();
|
||||
var roleManager = MockHelpers.MockRoleManager<TestRole>();
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
userManager.Setup(m => m.SupportsUserClaim).Returns(supportClaims);
|
||||
userManager.Setup(m => m.SupportsUserRole).Returns(supportRoles);
|
||||
userManager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.Id);
|
||||
userManager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName);
|
||||
var roleClaims = new[] { "Admin", "Local" };
|
||||
if (supportRoles)
|
||||
{
|
||||
userManager.Setup(m => m.GetRolesAsync(user)).ReturnsAsync(roleClaims);
|
||||
roleManager.Setup(m => m.SupportsRoleClaims).Returns(supportRoleClaims);
|
||||
}
|
||||
var userClaims = new[] { new Claim("Whatever", "Value"), new Claim("Whatever2", "Value2") };
|
||||
if (supportClaims)
|
||||
{
|
||||
userManager.Setup(m => m.GetClaimsAsync(user)).ReturnsAsync(userClaims);
|
||||
}
|
||||
userManager.Object.Options = new IdentityOptions();
|
||||
|
||||
var admin = new TestRole() { Name = "Admin" };
|
||||
var local = new TestRole() { Name = "Local" };
|
||||
var adminClaims = new[] { new Claim("AdminClaim1", "Value1"), new Claim("AdminClaim2", "Value2") };
|
||||
var localClaims = new[] { new Claim("LocalClaim1", "Value1"), new Claim("LocalClaim2", "Value2") };
|
||||
if (supportRoleClaims)
|
||||
{
|
||||
roleManager.Setup(m => m.FindByNameAsync("Admin")).ReturnsAsync(admin);
|
||||
roleManager.Setup(m => m.FindByNameAsync("Local")).ReturnsAsync(local);
|
||||
roleManager.Setup(m => m.GetClaimsAsync(admin)).ReturnsAsync(adminClaims);
|
||||
roleManager.Setup(m => m.GetClaimsAsync(local)).ReturnsAsync(localClaims);
|
||||
}
|
||||
|
||||
var options = new Mock<IOptions<IdentityOptions>>();
|
||||
var identityOptions = new IdentityOptions();
|
||||
options.Setup(a => a.Value).Returns(identityOptions);
|
||||
var factory = new UserClaimsPrincipalFactory<TestUser, TestRole>(userManager.Object, roleManager.Object, options.Object);
|
||||
|
||||
// Act
|
||||
var principal = await factory.CreateAsync(user);
|
||||
var identity = principal.Identities.First();
|
||||
|
||||
// Assert
|
||||
var manager = userManager.Object;
|
||||
Assert.NotNull(identity);
|
||||
Assert.Single(principal.Identities);
|
||||
Assert.Equal(IdentityConstants.ApplicationScheme, identity.AuthenticationType);
|
||||
var claims = identity.Claims.ToList();
|
||||
Assert.NotNull(claims);
|
||||
Assert.Contains(claims, c => c.Type == manager.Options.ClaimsIdentity.UserNameClaimType && c.Value == user.UserName);
|
||||
Assert.Contains(claims, c => c.Type == manager.Options.ClaimsIdentity.UserIdClaimType && c.Value == user.Id);
|
||||
Assert.Equal(supportRoles, claims.Any(c => c.Type == manager.Options.ClaimsIdentity.RoleClaimType && c.Value == "Admin"));
|
||||
Assert.Equal(supportRoles, claims.Any(c => c.Type == manager.Options.ClaimsIdentity.RoleClaimType && c.Value == "Local"));
|
||||
foreach (var cl in userClaims)
|
||||
{
|
||||
Assert.Equal(supportClaims, claims.Any(c => c.Type == cl.Type && c.Value == cl.Value));
|
||||
}
|
||||
foreach (var cl in adminClaims)
|
||||
{
|
||||
Assert.Equal(supportRoleClaims, claims.Any(c => c.Type == cl.Type && c.Value == cl.Value));
|
||||
}
|
||||
foreach (var cl in localClaims)
|
||||
{
|
||||
Assert.Equal(supportRoleClaims, claims.Any(c => c.Type == cl.Type && c.Value == cl.Value));
|
||||
}
|
||||
userManager.VerifyAll();
|
||||
roleManager.VerifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
+1595
File diff suppressed because it is too large
Load Diff
+99
@@ -0,0 +1,99 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public class UserValidatorTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task ValidateThrowsWithNull()
|
||||
{
|
||||
// Setup
|
||||
var manager = MockHelpers.TestUserManager(new NoopUserStore());
|
||||
var validator = new UserValidator<TestUser>();
|
||||
|
||||
// Act
|
||||
// Assert
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("manager", () => validator.ValidateAsync(null, null));
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("user", () => validator.ValidateAsync(manager, null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
public async Task ValidateFailsWithTooShortUserNames(string input)
|
||||
{
|
||||
// Setup
|
||||
var manager = MockHelpers.TestUserManager(new NoopUserStore());
|
||||
var validator = new UserValidator<TestUser>();
|
||||
var user = new TestUser {UserName = input};
|
||||
|
||||
// Act
|
||||
var result = await validator.ValidateAsync(manager, user);
|
||||
|
||||
// Assert
|
||||
IdentityResultAssert.IsFailure(result, new IdentityErrorDescriber().InvalidUserName(input));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("test_email@foo.com", true)]
|
||||
[InlineData("hao", true)]
|
||||
[InlineData("test123", true)]
|
||||
[InlineData("hyphen-yes@foo-bar.com", true)]
|
||||
[InlineData("+plus+yes+@foo-bar.com", true)]
|
||||
[InlineData("!noway", false)]
|
||||
[InlineData("foo@boz#.com", false)]
|
||||
public async Task DefaultAlphaNumericOnlyUserNameValidation(string userName, bool expectSuccess)
|
||||
{
|
||||
// Setup
|
||||
var manager = MockHelpers.TestUserManager(new NoopUserStore());
|
||||
var validator = new UserValidator<TestUser>();
|
||||
var user = new TestUser {UserName = userName};
|
||||
|
||||
// Act
|
||||
var result = await validator.ValidateAsync(manager, user);
|
||||
|
||||
// Assert
|
||||
if (expectSuccess)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
IdentityResultAssert.IsFailure(result);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("test_email@foo.com", true)]
|
||||
[InlineData("hao", true)]
|
||||
[InlineData("test123", true)]
|
||||
[InlineData("!noway", true)]
|
||||
[InlineData("foo@boz#.com", true)]
|
||||
public async Task CanAllowNonAlphaNumericUserName(string userName, bool expectSuccess)
|
||||
{
|
||||
// Setup
|
||||
var manager = MockHelpers.TestUserManager(new NoopUserStore());
|
||||
manager.Options.User.AllowedUserNameCharacters = null;
|
||||
var validator = new UserValidator<TestUser>();
|
||||
var user = new TestUser {UserName = userName};
|
||||
|
||||
// Act
|
||||
var result = await validator.ValidateAsync(manager, user);
|
||||
|
||||
// Assert
|
||||
if (expectSuccess)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
IdentityResultAssert.IsFailure(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using AspNetCore.Identity.MongoDbCore.Extensions;
|
||||
using AspNetCore.Identity.MongoDbCore.Infrastructure;
|
||||
using System;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.IntegrationTests.Infrastructure
|
||||
{
|
||||
public static class Locks
|
||||
{
|
||||
public static object MongoInitLock = new object();
|
||||
public static object RolesLock = new object();
|
||||
}
|
||||
|
||||
public static class Container
|
||||
{
|
||||
public static MongoDbIdentityConfiguration MongoDbIdentityConfiguration = new MongoDbIdentityConfiguration
|
||||
{
|
||||
MongoDbSettings = new MongoDbSettings
|
||||
{
|
||||
ConnectionString = "mongodb://localhost:27017",
|
||||
DatabaseName = "MongoDbTests"
|
||||
},
|
||||
IdentityOptionsAction = options =>
|
||||
{
|
||||
options.Password.RequireDigit = false;
|
||||
options.Password.RequireLowercase = false;
|
||||
options.Password.RequireNonAlphanumeric = false;
|
||||
options.Password.RequireUppercase = false;
|
||||
options.User.AllowedUserNameCharacters = null;
|
||||
}
|
||||
};
|
||||
|
||||
public static IServiceProvider Instance { get; set; }
|
||||
|
||||
const string connectionString = "mongodb://localhost:27017";
|
||||
private static readonly IMongoRepository _mongoDbRepository;
|
||||
|
||||
private static readonly IMongoRepository _mongoDbRepository2;
|
||||
|
||||
static Container()
|
||||
{
|
||||
lock (Locks.MongoInitLock)
|
||||
{
|
||||
_mongoDbRepository = new MongoRepository(
|
||||
MongoDbIdentityConfiguration.MongoDbSettings.ConnectionString,
|
||||
MongoDbIdentityConfiguration.MongoDbSettings.DatabaseName);
|
||||
_mongoDbRepository2 = new MongoRepository(
|
||||
MongoDbIdentityConfiguration.MongoDbSettings.ConnectionString,
|
||||
MongoDbIdentityConfiguration.MongoDbSettings.DatabaseName);
|
||||
}
|
||||
}
|
||||
|
||||
public static IMongoRepository MongoRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
return _mongoDbRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public static IMongoRepository MongoRepositoryConcurrent
|
||||
{
|
||||
get
|
||||
{
|
||||
return _mongoDbRepository2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using System;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.IntegrationTests.Infrastructure
|
||||
{
|
||||
public class TestMongoIdentityRole : MongoIdentityRole<Guid>
|
||||
{
|
||||
public TestMongoIdentityRole() : base ()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
public TestMongoIdentityRole(string roleName) : base(roleName)
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using System;
|
||||
|
||||
namespace AspNetCore.Identity.MongoDbCore.IntegrationTests.Infrastructure
|
||||
{
|
||||
public class TestMongoIdentityUser : MongoIdentityUser<Guid>
|
||||
{
|
||||
public TestMongoIdentityUser() : base()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
public TestMongoIdentityUser(string userName) : base(userName)
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
public TestMongoIdentityUser(string userName, string email) : base(userName, email)
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
public string CustomContent { get; set; }
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public abstract class ApiConsistencyTestBase
|
||||
{
|
||||
[Fact]
|
||||
public void Public_inheritable_apis_should_be_virtual()
|
||||
{
|
||||
var nonVirtualMethods
|
||||
= (from type in GetAllTypes(TargetAssembly.DefinedTypes)
|
||||
where type.IsVisible
|
||||
&& !type.IsSealed
|
||||
&& type.DeclaredConstructors.Any(c => c.IsPublic || c.IsFamily || c.IsFamilyOrAssembly)
|
||||
&& type.Namespace != null
|
||||
&& !type.Namespace.EndsWith(".Compiled")
|
||||
from method in type.DeclaredMethods.Where(m => m.IsPublic && !m.IsStatic)
|
||||
where GetBasestTypeInAssembly(method.DeclaringType) == type
|
||||
&& !(method.IsVirtual && !method.IsFinal)
|
||||
&& !method.Name.StartsWith("get_")
|
||||
&& !method.Name.StartsWith("set_")
|
||||
&& !method.Name.Equals("Dispose")
|
||||
select type.Name + "." + method.Name)
|
||||
.ToList();
|
||||
|
||||
Assert.False(
|
||||
nonVirtualMethods.Any(),
|
||||
"\r\n-- Missing virtual APIs --\r\n" + string.Join("\r\n", nonVirtualMethods));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Async_methods_should_end_with_async_suffix()
|
||||
{
|
||||
var asyncMethods
|
||||
= (from type in GetAllTypes(TargetAssembly.DefinedTypes)
|
||||
where type.IsVisible
|
||||
from method in type.DeclaredMethods.Where(m => m.IsPublic)
|
||||
where GetBasestTypeInAssembly(method.DeclaringType) == type
|
||||
where typeof(Task).IsAssignableFrom(method.ReturnType)
|
||||
select method).ToList();
|
||||
|
||||
var missingSuffixMethods
|
||||
= asyncMethods
|
||||
.Where(method => !method.Name.EndsWith("Async"))
|
||||
.Select(method => method.DeclaringType.Name + "." + method.Name)
|
||||
.Except(GetAsyncSuffixExceptions())
|
||||
.ToList();
|
||||
|
||||
Assert.False(
|
||||
missingSuffixMethods.Any(),
|
||||
"\r\n-- Missing async suffix --\r\n" + string.Join("\r\n", missingSuffixMethods));
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<string> GetCancellationTokenExceptions()
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<string> GetAsyncSuffixExceptions()
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
protected abstract Assembly TargetAssembly { get; }
|
||||
|
||||
protected virtual IEnumerable<TypeInfo> GetAllTypes(IEnumerable<TypeInfo> types)
|
||||
{
|
||||
foreach (var type in types)
|
||||
{
|
||||
yield return type;
|
||||
|
||||
foreach (var nestedType in GetAllTypes(type.DeclaredNestedTypes))
|
||||
{
|
||||
yield return nestedType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected TypeInfo GetBasestTypeInAssembly(Type type)
|
||||
{
|
||||
while (type.GetTypeInfo()?.BaseType?.GetTypeInfo()?.Assembly == type.GetTypeInfo().Assembly)
|
||||
{
|
||||
type = type.GetTypeInfo().BaseType;
|
||||
}
|
||||
|
||||
return type.GetTypeInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
public static class MockHelpers
|
||||
{
|
||||
public static StringBuilder LogMessage = new StringBuilder();
|
||||
|
||||
public static Mock<UserManager<TUser>> MockUserManager<TUser>() where TUser : class
|
||||
{
|
||||
var store = new Mock<IUserStore<TUser>>();
|
||||
var mgr = new Mock<UserManager<TUser>>(store.Object, null, null, null, null, null, null, null, null);
|
||||
mgr.Object.UserValidators.Add(new UserValidator<TUser>());
|
||||
mgr.Object.PasswordValidators.Add(new PasswordValidator<TUser>());
|
||||
return mgr;
|
||||
}
|
||||
|
||||
public static Mock<RoleManager<TRole>> MockRoleManager<TRole>(IRoleStore<TRole> store = null) where TRole : class
|
||||
{
|
||||
store = store ?? new Mock<IRoleStore<TRole>>().Object;
|
||||
var roles = new List<IRoleValidator<TRole>>();
|
||||
roles.Add(new RoleValidator<TRole>());
|
||||
return new Mock<RoleManager<TRole>>(store, roles, new UpperInvariantLookupNormalizer(),
|
||||
new IdentityErrorDescriber(), null);
|
||||
}
|
||||
|
||||
public static Mock<ILogger<T>> MockILogger<T>(StringBuilder logStore = null) where T : class
|
||||
{
|
||||
logStore = logStore ?? LogMessage;
|
||||
var logger = new Mock<ILogger<T>>();
|
||||
logger.Setup(x => x.Log(It.IsAny<LogLevel>(), It.IsAny<EventId>(), It.IsAny<object>(),
|
||||
It.IsAny<Exception>(), It.IsAny<Func<object, Exception, string>>()))
|
||||
.Callback((LogLevel logLevel, EventId eventId, object state, Exception exception, Func<object, Exception, string> formatter) =>
|
||||
{
|
||||
if (formatter == null)
|
||||
{
|
||||
logStore.Append(state.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
logStore.Append(formatter(state, exception));
|
||||
}
|
||||
logStore.Append(" ");
|
||||
});
|
||||
logger.Setup(x => x.BeginScope(It.IsAny<object>())).Callback((object state) =>
|
||||
{
|
||||
logStore.Append(state.ToString());
|
||||
logStore.Append(" ");
|
||||
});
|
||||
logger.Setup(x => x.IsEnabled(LogLevel.Debug)).Returns(true);
|
||||
logger.Setup(x => x.IsEnabled(LogLevel.Warning)).Returns(true);
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
public static UserManager<TUser> TestUserManager<TUser>(IUserStore<TUser> store = null) where TUser : class
|
||||
{
|
||||
store = store ?? new Mock<IUserStore<TUser>>().Object;
|
||||
var options = new Mock<IOptions<IdentityOptions>>();
|
||||
var idOptions = new IdentityOptions();
|
||||
idOptions.Lockout.AllowedForNewUsers = false;
|
||||
options.Setup(o => o.Value).Returns(idOptions);
|
||||
var userValidators = new List<IUserValidator<TUser>>();
|
||||
var validator = new Mock<IUserValidator<TUser>>();
|
||||
userValidators.Add(validator.Object);
|
||||
var pwdValidators = new List<PasswordValidator<TUser>>();
|
||||
pwdValidators.Add(new PasswordValidator<TUser>());
|
||||
var userManager = new UserManager<TUser>(store, options.Object, new PasswordHasher<TUser>(),
|
||||
userValidators, pwdValidators, new UpperInvariantLookupNormalizer(),
|
||||
new IdentityErrorDescriber(), null,
|
||||
new Mock<ILogger<UserManager<TUser>>>().Object);
|
||||
validator.Setup(v => v.ValidateAsync(userManager, It.IsAny<TUser>()))
|
||||
.Returns(Task.FromResult(IdentityResult.Success)).Verifiable();
|
||||
return userManager;
|
||||
}
|
||||
|
||||
public static RoleManager<TRole> TestRoleManager<TRole>(IRoleStore<TRole> store = null) where TRole : class
|
||||
{
|
||||
store = store ?? new Mock<IRoleStore<TRole>>().Object;
|
||||
var roles = new List<IRoleValidator<TRole>>();
|
||||
roles.Add(new RoleValidator<TRole>());
|
||||
return new AspNetRoleManager<TRole>(store, roles,
|
||||
new UpperInvariantLookupNormalizer(),
|
||||
new IdentityErrorDescriber(),
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
|
||||
/// <summary>
|
||||
/// Test priority
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||||
public class TestPriorityAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
/// <param name="priority"></param>
|
||||
public TestPriorityAttribute(int priority)
|
||||
{
|
||||
Priority = priority;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Priority
|
||||
/// </summary>
|
||||
public int Priority { get; private set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to run tests in order.
|
||||
/// </summary>
|
||||
public class PriorityOrderer : ITestCaseOrderer
|
||||
{
|
||||
/// <summary>
|
||||
/// Orders tests cases
|
||||
/// </summary>
|
||||
/// <typeparam name="XunitTestCase"></typeparam>
|
||||
/// <param name="testCases"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<XunitTestCase> OrderTestCases<XunitTestCase>(IEnumerable<XunitTestCase> testCases) where XunitTestCase : ITestCase
|
||||
{
|
||||
var sortedMethods = new SortedDictionary<int, List<XunitTestCase>>();
|
||||
|
||||
foreach (XunitTestCase testCase in testCases)
|
||||
{
|
||||
int priority = 0;
|
||||
|
||||
foreach (IAttributeInfo attr in testCase.TestMethod.Method.GetCustomAttributes((typeof(TestPriorityAttribute)).AssemblyQualifiedName))
|
||||
priority = attr.GetNamedArgument<int>("Priority");
|
||||
|
||||
GetOrCreate(sortedMethods, priority).Add(testCase);
|
||||
}
|
||||
|
||||
foreach (var list in sortedMethods.Keys.Select(priority => sortedMethods[priority]))
|
||||
{
|
||||
list.Sort((x, y) => StringComparer.OrdinalIgnoreCase.Compare(x.TestMethod.Method.Name, y.TestMethod.Method.Name));
|
||||
foreach (XunitTestCase testCase in list)
|
||||
yield return testCase;
|
||||
}
|
||||
}
|
||||
|
||||
static TValue GetOrCreate<TKey, TValue>(IDictionary<TKey, TValue> dictionary, TKey key) where TValue : new()
|
||||
{
|
||||
TValue result;
|
||||
|
||||
if (dictionary.TryGetValue(key, out result)) return result;
|
||||
|
||||
result = new TValue();
|
||||
dictionary[key] = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a Role entity
|
||||
/// </summary>
|
||||
public class TestRole : TestRole<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public TestRole()
|
||||
{
|
||||
Id = Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="roleName"></param>
|
||||
public TestRole(string roleName) : this()
|
||||
{
|
||||
Name = roleName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Role entity
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
public class TestRole<TKey> where TKey : IEquatable<TKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public TestRole() { }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="roleName"></param>
|
||||
public TestRole(string roleName) : this()
|
||||
{
|
||||
Name = roleName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Role id
|
||||
/// </summary>
|
||||
public virtual TKey Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Navigation property for claims in the role
|
||||
/// </summary>
|
||||
public virtual ICollection<TestRoleClaim<TKey>> Claims { get; private set; } = new List<TestRoleClaim<TKey>>();
|
||||
|
||||
/// <summary>
|
||||
/// Role name
|
||||
/// </summary>
|
||||
public virtual string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Normalized name used for equality
|
||||
/// </summary>
|
||||
public virtual string NormalizedName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A random value that should change whenever a role is persisted to the store
|
||||
/// </summary>
|
||||
public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
/// <summary>
|
||||
/// EntityType that represents one specific role claim
|
||||
/// </summary>
|
||||
public class TestRoleClaim : TestRoleClaim<string> { }
|
||||
|
||||
/// <summary>
|
||||
/// EntityType that represents one specific role claim
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
public class TestRoleClaim<TKey> where TKey : IEquatable<TKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// Primary key
|
||||
/// </summary>
|
||||
public virtual int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User Id for the role this claim belongs to
|
||||
/// </summary>
|
||||
public virtual TKey RoleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Claim type
|
||||
/// </summary>
|
||||
public virtual string ClaimType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Claim value
|
||||
/// </summary>
|
||||
public virtual string ClaimValue { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
/// <summary>
|
||||
/// Test user class
|
||||
/// </summary>
|
||||
public class TestUser : TestUser<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Ctor
|
||||
/// </summary>
|
||||
public TestUser()
|
||||
{
|
||||
Id = Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ctor
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
public TestUser(string userName) : this()
|
||||
{
|
||||
UserName = userName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test user
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
public class TestUser<TKey> where TKey : IEquatable<TKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
public TestUser() { }
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
public TestUser(string userName) : this()
|
||||
{
|
||||
UserName = userName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public virtual TKey Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name
|
||||
/// </summary>
|
||||
public virtual string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// normalized user name
|
||||
/// </summary>
|
||||
public virtual string NormalizedUserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Email
|
||||
/// </summary>
|
||||
public virtual string Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// normalized email
|
||||
/// </summary>
|
||||
public virtual string NormalizedEmail { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the email is confirmed, default is false
|
||||
/// </summary>
|
||||
public virtual bool EmailConfirmed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The salted/hashed form of the user password
|
||||
/// </summary>
|
||||
public virtual string PasswordHash { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A random value that should change whenever a users credentials change (password changed, login removed)
|
||||
/// </summary>
|
||||
public virtual string SecurityStamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A random value that should change whenever a user is persisted to the store
|
||||
/// </summary>
|
||||
public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString();
|
||||
|
||||
/// <summary>
|
||||
/// PhoneNumber for the user
|
||||
/// </summary>
|
||||
public virtual string PhoneNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the phone number is confirmed, default is false
|
||||
/// </summary>
|
||||
public virtual bool PhoneNumberConfirmed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is two factor enabled for the user
|
||||
/// </summary>
|
||||
public virtual bool TwoFactorEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DateTime in UTC when lockout ends, any time in the past is considered not locked out.
|
||||
/// </summary>
|
||||
public virtual DateTimeOffset? LockoutEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is lockout enabled for this user
|
||||
/// </summary>
|
||||
public virtual bool LockoutEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to record failures for the purposes of lockout
|
||||
/// </summary>
|
||||
public virtual int AccessFailedCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Navigation property
|
||||
/// </summary>
|
||||
public virtual ICollection<TestUserRole<TKey>> Roles { get; private set; } = new List<TestUserRole<TKey>>();
|
||||
/// <summary>
|
||||
/// Navigation property
|
||||
/// </summary>
|
||||
public virtual ICollection<TestUserClaim<TKey>> Claims { get; private set; } = new List<TestUserClaim<TKey>>();
|
||||
/// <summary>
|
||||
/// Navigation property
|
||||
/// </summary>
|
||||
public virtual ICollection<TestUserLogin<TKey>> Logins { get; private set; } = new List<TestUserLogin<TKey>>();
|
||||
/// <summary>
|
||||
/// Navigation property
|
||||
/// </summary>
|
||||
public virtual ICollection<TestUserToken<TKey>> Tokens { get; private set; } = new List<TestUserToken<TKey>>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
/// <summary>
|
||||
/// EntityType that represents one specific user claim
|
||||
/// </summary>
|
||||
public class TestUserClaim : TestUserClaim<string> { }
|
||||
|
||||
/// <summary>
|
||||
/// EntityType that represents one specific user claim
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
public class TestUserClaim<TKey> where TKey : IEquatable<TKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// Primary key
|
||||
/// </summary>
|
||||
public virtual int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User Id for the user who owns this claim
|
||||
/// </summary>
|
||||
public virtual TKey UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Claim type
|
||||
/// </summary>
|
||||
public virtual string ClaimType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Claim value
|
||||
/// </summary>
|
||||
public virtual string ClaimValue { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity type for a user's login (i.e. facebook, google)
|
||||
/// </summary>
|
||||
public class TestUserLogin : TestUserLogin<string> { }
|
||||
|
||||
/// <summary>
|
||||
/// Entity type for a user's login (i.e. facebook, google)
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
public class TestUserLogin<TKey> where TKey : IEquatable<TKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// The login provider for the login (i.e. facebook, google)
|
||||
/// </summary>
|
||||
public virtual string LoginProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Key representing the login for the provider
|
||||
/// </summary>
|
||||
public virtual string ProviderKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Display name for the login
|
||||
/// </summary>
|
||||
public virtual string ProviderDisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User Id for the user who owns this login
|
||||
/// </summary>
|
||||
public virtual TKey UserId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
/// <summary>
|
||||
/// EntityType that represents a user belonging to a role
|
||||
/// </summary>
|
||||
public class TestUserRole : TestUserRole<string> { }
|
||||
|
||||
/// <summary>
|
||||
/// EntityType that represents a user belonging to a role
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
public class TestUserRole<TKey> where TKey : IEquatable<TKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// UserId for the user that is in the role
|
||||
/// </summary>
|
||||
public virtual TKey UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RoleId for the role
|
||||
/// </summary>
|
||||
public virtual TKey RoleId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity type for a user's token
|
||||
/// </summary>
|
||||
public class TestUserToken : TestUserToken<string> { }
|
||||
|
||||
/// <summary>
|
||||
/// Entity type for a user's token
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
public class TestUserToken<TKey> where TKey : IEquatable<TKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// The login provider for the login (i.e. facebook, google)
|
||||
/// </summary>
|
||||
public virtual string LoginProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Key representing the login for the provider
|
||||
/// </summary>
|
||||
public virtual string TokenName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Display name for the login
|
||||
/// </summary>
|
||||
public virtual string TokenValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User Id for the user who owns this login
|
||||
/// </summary>
|
||||
public virtual TKey UserId { get; set; }
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper for tests to validate identity results.
|
||||
/// </summary>
|
||||
public static class IdentityResultAssert
|
||||
{
|
||||
/// <summary>
|
||||
/// Asserts that the result has Succeeded.
|
||||
/// </summary>
|
||||
/// <param name="result"></param>
|
||||
public static void IsSuccess(IdentityResult result)
|
||||
{
|
||||
Assert.NotNull(result);
|
||||
Assert.True(result.Succeeded);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asserts that the result has not Succeeded.
|
||||
/// </summary>
|
||||
public static void IsFailure(IdentityResult result)
|
||||
{
|
||||
Assert.NotNull(result);
|
||||
Assert.False(result.Succeeded);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asserts that the result has not Succeeded and that error is the first Error's Description.
|
||||
/// </summary>
|
||||
public static void IsFailure(IdentityResult result, string error)
|
||||
{
|
||||
Assert.NotNull(result);
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.Equal(error, result.Errors.First().Description);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asserts that the result has not Succeeded and that first error matches error's code and Description.
|
||||
/// </summary>
|
||||
public static void IsFailure(IdentityResult result, IdentityError error)
|
||||
{
|
||||
Assert.NotNull(result);
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.Equal(error.Description, result.Errors.First().Description);
|
||||
Assert.Equal(error.Code, result.Errors.First().Code);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asserts that the logger contains the expectedLog.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger to inspect.</param>
|
||||
/// <param name="expectedLog">The expected log message.</param>
|
||||
public static void VerifyLogMessage(ILogger logger, string expectedLog)
|
||||
{
|
||||
var testlogger = logger as ITestLogger;
|
||||
if (testlogger != null)
|
||||
{
|
||||
Assert.Contains(expectedLog, testlogger.LogMessages);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.False(true, "No logger registered");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+717
@@ -0,0 +1,717 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Xunit;
|
||||
using AspNetCore.Identity.MongoDbCore.Models;
|
||||
using AspNetCore.Identity.MongoDbCore.Extensions;
|
||||
using AspNetCore.Identity.MongoDbCore.Infrastructure;
|
||||
using AspNetCore.Identity.MongoDbCore.IntegrationTests.Infrastructure;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
/// <summary>
|
||||
/// Common functionality tests that all verifies user manager functionality regardless of store implementation
|
||||
/// </summary>
|
||||
/// <typeparam name="TUser">The type of the user.</typeparam>
|
||||
/// <typeparam name="TRole">The type of the role.</typeparam>
|
||||
public abstract class IdentitySpecificationTestBase<TUser, TRole> : IdentitySpecificationTestBase<TUser, TRole, string>
|
||||
where TUser : MongoDbIdentityUser, new()
|
||||
where TRole : MongoDbIdentityRole, new()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Base class for tests that exercise basic identity functionality that all stores should support.
|
||||
/// </summary>
|
||||
/// <typeparam name="TUser">The type of the user.</typeparam>
|
||||
/// <typeparam name="TRole">The type of the role.</typeparam>
|
||||
/// <typeparam name="TKey">The primary key type.</typeparam>
|
||||
public abstract class IdentitySpecificationTestBase<TUser, TRole, TKey> : UserManagerSpecificationTestBase<TUser, TKey>
|
||||
where TUser : MongoIdentityUser<TKey>, new()
|
||||
where TRole : MongoIdentityRole<TKey>, new()
|
||||
where TKey : IEquatable<TKey>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Configure the service collection used for tests.
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="mongoRepository"></param>
|
||||
protected override void SetupIdentityServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
services.ConfigureMongoDbIdentity<TUser, TRole, TKey>(Container.MongoDbIdentityConfiguration, Container.MongoRepository.Context);
|
||||
services.AddLogging();
|
||||
services.AddSingleton<ILogger<UserManager<TUser>>>(new TestLogger<UserManager<TUser>>());
|
||||
services.AddSingleton<ILogger<RoleManager<TRole>>>(new TestLogger<RoleManager<TRole>>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure the service collection used for tests.
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="mongoRepository"></param>
|
||||
protected void SetupIdentityServices(IServiceCollection services, bool concurrentSetup = false)
|
||||
{
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
if (concurrentSetup)
|
||||
{
|
||||
services.ConfigureMongoDbIdentity<TUser, TRole, TKey>(Container.MongoDbIdentityConfiguration, Container.MongoRepositoryConcurrent.Context);
|
||||
}
|
||||
else
|
||||
{
|
||||
services.ConfigureMongoDbIdentity<TUser, TRole, TKey>(Container.MongoDbIdentityConfiguration, Container.MongoRepository.Context);
|
||||
}
|
||||
|
||||
services.AddLogging();
|
||||
services.AddSingleton<ILogger<UserManager<TUser>>>(new TestLogger<UserManager<TUser>>());
|
||||
services.AddSingleton<ILogger<RoleManager<TRole>>>(new TestLogger<RoleManager<TRole>>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Setup the IdentityBuilder
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
protected override IServiceCollection SetupBuilder(IServiceCollection services)
|
||||
{
|
||||
var builder = base.SetupBuilder(services);
|
||||
//builder.AddRoles<TRole>();
|
||||
//AddRoleStore(services, context);
|
||||
services.AddSingleton<ILogger<RoleManager<TRole>>>(new TestLogger<RoleManager<TRole>>());
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the role manager for tests.
|
||||
/// </summary>
|
||||
/// <param name="context">The context that will be passed into the store, typically a db context.</param>
|
||||
/// <param name="services">The service collection to use, optional.</param>
|
||||
/// <returns></returns>
|
||||
protected virtual RoleManager<TRole> CreateRoleManager(object context = null, IServiceCollection services = null)
|
||||
{
|
||||
if (services == null)
|
||||
{
|
||||
services = new ServiceCollection();
|
||||
}
|
||||
|
||||
if(context == null)
|
||||
{
|
||||
SetupIdentityServices(services);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupIdentityServices(services, true);
|
||||
}
|
||||
|
||||
return services.BuildServiceProvider().GetService<RoleManager<TRole>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an IRoleStore to services for the test.
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection to add to.</param>
|
||||
/// <param name="context">The context for the store to use, optional.</param>
|
||||
protected abstract void AddRoleStore(IServiceCollection services, object context = null);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new test role instance.
|
||||
/// </summary>
|
||||
/// <param name="roleNamePrefix">Optional name prefix, name will be randomized.</param>
|
||||
/// <param name="useRoleNamePrefixAsRoleName">If true, the prefix should be used as the rolename without a random pad.</param>
|
||||
/// <returns></returns>
|
||||
protected abstract TRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false);
|
||||
|
||||
/// <summary>
|
||||
/// Query used to do name equality checks.
|
||||
/// </summary>
|
||||
/// <param name="roleName">The role name to match.</param>
|
||||
/// <returns>The query to use.</returns>
|
||||
protected abstract Expression<Func<TRole, bool>> RoleNameEqualsPredicate(string roleName);
|
||||
|
||||
/// <summary>
|
||||
/// Query used to do user name prefix matching.
|
||||
/// </summary>
|
||||
/// <param name="roleName">The role name to match.</param>
|
||||
/// <returns>The query to use.</returns>
|
||||
protected abstract Expression<Func<TRole, bool>> RoleNameStartsWithPredicate(string roleName);
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanCreateRoleTest()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateRoleManager();
|
||||
var roleName = "create" + Guid.NewGuid().ToString();
|
||||
var role = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
Assert.False(await manager.RoleExistsAsync(roleName));
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
|
||||
Assert.True(await manager.RoleExistsAsync(roleName));
|
||||
}
|
||||
|
||||
private class AlwaysBadValidator : IUserValidator<TUser>, IRoleValidator<TRole>,
|
||||
IPasswordValidator<TUser>
|
||||
{
|
||||
public static readonly IdentityError ErrorMessage = new IdentityError { Description = "I'm Bad.", Code = "BadValidator" };
|
||||
|
||||
public Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user, string password)
|
||||
{
|
||||
return Task.FromResult(IdentityResult.Failed(ErrorMessage));
|
||||
}
|
||||
|
||||
public Task<IdentityResult> ValidateAsync(RoleManager<TRole> manager, TRole role)
|
||||
{
|
||||
return Task.FromResult(IdentityResult.Failed(ErrorMessage));
|
||||
}
|
||||
|
||||
public Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user)
|
||||
{
|
||||
return Task.FromResult(IdentityResult.Failed(ErrorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task BadValidatorBlocksCreateRole()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateRoleManager();
|
||||
manager.RoleValidators.Clear();
|
||||
manager.RoleValidators.Add(new AlwaysBadValidator());
|
||||
var role = CreateTestRole("blocked");
|
||||
IdentityResultAssert.IsFailure(await manager.CreateAsync(role),
|
||||
AlwaysBadValidator.ErrorMessage);
|
||||
IdentityResultAssert.VerifyLogMessage(manager.Logger, $"Role {await manager.GetRoleIdAsync(role) ?? NullValue} validation failed: {AlwaysBadValidator.ErrorMessage.Code}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanChainRoleValidators()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateRoleManager();
|
||||
manager.RoleValidators.Clear();
|
||||
manager.RoleValidators.Add(new AlwaysBadValidator());
|
||||
manager.RoleValidators.Add(new AlwaysBadValidator());
|
||||
var role = CreateTestRole("blocked");
|
||||
var result = await manager.CreateAsync(role);
|
||||
IdentityResultAssert.IsFailure(result, AlwaysBadValidator.ErrorMessage);
|
||||
IdentityResultAssert.VerifyLogMessage(manager.Logger, $"Role {await manager.GetRoleIdAsync(role) ?? NullValue} validation failed: {AlwaysBadValidator.ErrorMessage.Code};{AlwaysBadValidator.ErrorMessage.Code}.");
|
||||
Assert.Equal(2, result.Errors.Count());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task BadValidatorBlocksRoleUpdate()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateRoleManager();
|
||||
var role = CreateTestRole("poorguy");
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
|
||||
var error = AlwaysBadValidator.ErrorMessage;
|
||||
manager.RoleValidators.Clear();
|
||||
manager.RoleValidators.Add(new AlwaysBadValidator());
|
||||
IdentityResultAssert.IsFailure(await manager.UpdateAsync(role), error);
|
||||
IdentityResultAssert.VerifyLogMessage(manager.Logger, $"Role {await manager.GetRoleIdAsync(role) ?? NullValue} validation failed: {AlwaysBadValidator.ErrorMessage.Code}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanDeleteRole()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateRoleManager();
|
||||
var roleName = "delete" + Guid.NewGuid().ToString();
|
||||
var role = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
Assert.False(await manager.RoleExistsAsync(roleName));
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
|
||||
Assert.True(await manager.RoleExistsAsync(roleName));
|
||||
IdentityResultAssert.IsSuccess(await manager.DeleteAsync(role));
|
||||
Assert.False(await manager.RoleExistsAsync(roleName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanAddRemoveRoleClaim()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateRoleManager();
|
||||
var role = CreateTestRole("ClaimsAddRemove");
|
||||
var roleSafe = CreateTestRole("ClaimsAdd");
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(roleSafe));
|
||||
Claim[] claims = { new Claim("c", "v"), new Claim("c2", "v2"), new Claim("c2", "v3") };
|
||||
foreach (Claim c in claims)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(role, c));
|
||||
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(roleSafe, c));
|
||||
}
|
||||
var roleClaims = await manager.GetClaimsAsync(role);
|
||||
var safeRoleClaims = await manager.GetClaimsAsync(roleSafe);
|
||||
Assert.Equal(3, roleClaims.Count);
|
||||
Assert.Equal(3, safeRoleClaims.Count);
|
||||
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(role, claims[0]));
|
||||
roleClaims = await manager.GetClaimsAsync(role);
|
||||
safeRoleClaims = await manager.GetClaimsAsync(roleSafe);
|
||||
Assert.Equal(2, roleClaims.Count);
|
||||
Assert.Equal(3, safeRoleClaims.Count);
|
||||
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(role, claims[1]));
|
||||
roleClaims = await manager.GetClaimsAsync(role);
|
||||
safeRoleClaims = await manager.GetClaimsAsync(roleSafe);
|
||||
Assert.Equal(1, roleClaims.Count);
|
||||
Assert.Equal(3, safeRoleClaims.Count);
|
||||
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(role, claims[2]));
|
||||
roleClaims = await manager.GetClaimsAsync(role);
|
||||
safeRoleClaims = await manager.GetClaimsAsync(roleSafe);
|
||||
Assert.Equal(0, roleClaims.Count);
|
||||
Assert.Equal(3, safeRoleClaims.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanRoleFindById()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateRoleManager();
|
||||
var role = CreateTestRole("FindByIdAsync");
|
||||
Assert.Null(await manager.FindByIdAsync(await manager.GetRoleIdAsync(role)));
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
|
||||
Assert.Equal(role.Id, (await manager.FindByIdAsync(await manager.GetRoleIdAsync(role))).Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanRoleFindByName()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateRoleManager();
|
||||
var roleName = "FindByNameAsync" + Guid.NewGuid().ToString();
|
||||
var role = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
Assert.Null(await manager.FindByNameAsync(roleName));
|
||||
Assert.False(await manager.RoleExistsAsync(roleName));
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
|
||||
Assert.Equal(role.Id, (await manager.FindByNameAsync(roleName)).Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanUpdateRoleName()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateRoleManager();
|
||||
var roleName = "update" + Guid.NewGuid().ToString();
|
||||
var changedRoleName = "Changed" + Guid.NewGuid().ToString();
|
||||
var role = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
Assert.False(await manager.RoleExistsAsync(roleName));
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
|
||||
Assert.True(await manager.RoleExistsAsync(roleName));
|
||||
IdentityResultAssert.IsSuccess(await manager.SetRoleNameAsync(role, changedRoleName));
|
||||
IdentityResultAssert.IsSuccess(await manager.UpdateAsync(role));
|
||||
Assert.False(await manager.RoleExistsAsync(roleName));
|
||||
Assert.Equal(role.Id, (await manager.FindByNameAsync(changedRoleName)).Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanQueryableRoles()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateRoleManager();
|
||||
if (manager.SupportsQueryableRoles)
|
||||
{
|
||||
var guidName = "CanQuerableRolesTest" + Guid.NewGuid().ToString("n");
|
||||
var roles = GenerateRoles(guidName, 4);
|
||||
foreach (var r in roles)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(r));
|
||||
}
|
||||
Expression<Func<TRole, bool>> func = RoleNameStartsWithPredicate(guidName);
|
||||
Assert.Equal(roles.Count, manager.Roles.Count(func));
|
||||
func = RoleNameEqualsPredicate("bogus");
|
||||
Assert.Null(manager.Roles.FirstOrDefault(func));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CreateRoleFailsIfExists()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateRoleManager();
|
||||
var roleName = "dupeRole" + Guid.NewGuid().ToString();
|
||||
var role = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
Assert.False(await manager.RoleExistsAsync(roleName));
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
|
||||
Assert.True(await manager.RoleExistsAsync(roleName));
|
||||
var role2 = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
IdentityResultAssert.IsFailure(await manager.CreateAsync(role2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanAddUsersToRole()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateManager();
|
||||
var roleManager = CreateRoleManager();
|
||||
var roleName = "AddUserTest" + Guid.NewGuid().ToString();
|
||||
var role = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
IdentityResultAssert.IsSuccess(await roleManager.CreateAsync(role));
|
||||
TUser[] users =
|
||||
{
|
||||
CreateTestUser("1"),CreateTestUser("2"),CreateTestUser("3"),CreateTestUser("4"),
|
||||
};
|
||||
foreach (var u in users)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(u));
|
||||
IdentityResultAssert.IsSuccess(await manager.AddToRoleAsync(u, roleName));
|
||||
Assert.True(await manager.IsInRoleAsync(u, roleName));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanGetRolesForUser()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var userManager = CreateManager();
|
||||
var roleManager = CreateRoleManager();
|
||||
var guid = Guid.NewGuid().ToString("n");
|
||||
var users = GenerateUsers(guid + "CanGetRolesForUser", 4);
|
||||
var roles = GenerateRoles(guid + "CanGetRolesForUserRole", 4);
|
||||
foreach (var u in users)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await userManager.CreateAsync(u));
|
||||
}
|
||||
foreach (var r in roles)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await roleManager.CreateAsync(r));
|
||||
foreach (var u in users)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await userManager.AddToRoleAsync(u, await roleManager.GetRoleNameAsync(r)));
|
||||
Assert.True(await userManager.IsInRoleAsync(u, await roleManager.GetRoleNameAsync(r)));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var u in users)
|
||||
{
|
||||
var rs = await userManager.GetRolesAsync(u);
|
||||
Assert.Equal(roles.Count, rs.Count);
|
||||
foreach (var r in roles)
|
||||
{
|
||||
var expectedRoleName = await roleManager.GetRoleNameAsync(r);
|
||||
Assert.True(rs.Any(role => role == expectedRoleName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task RemoveUserFromRoleWithMultipleRoles()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var userManager = CreateManager();
|
||||
var roleManager = CreateRoleManager();
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user));
|
||||
var guidName = "RemoveUserFromRoleWithMultipleRoles" + Guid.NewGuid().ToString("n");
|
||||
var roles = GenerateRoles(guidName, 4);
|
||||
foreach (var r in roles)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await roleManager.CreateAsync(r));
|
||||
IdentityResultAssert.IsSuccess(await userManager.AddToRoleAsync(user, await roleManager.GetRoleNameAsync(r)));
|
||||
Assert.True(await userManager.IsInRoleAsync(user, await roleManager.GetRoleNameAsync(r)));
|
||||
}
|
||||
IdentityResultAssert.IsSuccess(await userManager.RemoveFromRoleAsync(user, await roleManager.GetRoleNameAsync(roles[2])));
|
||||
Assert.False(await userManager.IsInRoleAsync(user, await roleManager.GetRoleNameAsync(roles[2])));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanRemoveUsersFromRole()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var userManager = CreateManager();
|
||||
var roleManager = CreateRoleManager();
|
||||
var guid = Guid.NewGuid().ToString("n");
|
||||
var users = GenerateUsers(guid + "CanRemoveUsersFromRole", 4);
|
||||
foreach (var u in users)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await userManager.CreateAsync(u));
|
||||
}
|
||||
var r = CreateTestRole(guid + "r1");
|
||||
var roleName = await roleManager.GetRoleNameAsync(r);
|
||||
IdentityResultAssert.IsSuccess(await roleManager.CreateAsync(r));
|
||||
foreach (var u in users)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await userManager.AddToRoleAsync(u, roleName));
|
||||
Assert.True(await userManager.IsInRoleAsync(u, roleName));
|
||||
}
|
||||
foreach (var u in users)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await userManager.RemoveFromRoleAsync(u, roleName));
|
||||
Assert.False(await userManager.IsInRoleAsync(u, roleName));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task RemoveUserNotInRoleFails()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var userMgr = CreateManager();
|
||||
var roleMgr = CreateRoleManager();
|
||||
var roleName = "addUserDupeTest" + Guid.NewGuid().ToString();
|
||||
var role = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await userMgr.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await roleMgr.CreateAsync(role));
|
||||
var result = await userMgr.RemoveFromRoleAsync(user, roleName);
|
||||
IdentityResultAssert.IsFailure(result, _errorDescriber.UserNotInRole(roleName));
|
||||
IdentityResultAssert.VerifyLogMessage(userMgr.Logger, $"User {await userMgr.GetUserIdAsync(user)} is not in role {roleName}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task AddUserToRoleFailsIfAlreadyInRole()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var userMgr = CreateManager();
|
||||
var roleMgr = CreateRoleManager();
|
||||
var roleName = "addUserDupeTest" + Guid.NewGuid().ToString();
|
||||
var role = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await userMgr.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await roleMgr.CreateAsync(role));
|
||||
IdentityResultAssert.IsSuccess(await userMgr.AddToRoleAsync(user, roleName));
|
||||
Assert.True(await userMgr.IsInRoleAsync(user, roleName));
|
||||
IdentityResultAssert.IsFailure(await userMgr.AddToRoleAsync(user, roleName), _errorDescriber.UserAlreadyInRole(roleName));
|
||||
IdentityResultAssert.VerifyLogMessage(userMgr.Logger, $"User {await userMgr.GetUserIdAsync(user)} is already in role {roleName}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task AddUserToRolesIgnoresDuplicates()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var userMgr = CreateManager();
|
||||
var roleMgr = CreateRoleManager();
|
||||
var roleName = "addUserDupeTest" + Guid.NewGuid().ToString();
|
||||
var role = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await userMgr.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await roleMgr.CreateAsync(role));
|
||||
Assert.False(await userMgr.IsInRoleAsync(user, roleName));
|
||||
IdentityResultAssert.IsSuccess(await userMgr.AddToRolesAsync(user, new[] { roleName, roleName }));
|
||||
Assert.True(await userMgr.IsInRoleAsync(user, roleName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanFindRoleByNameWithManager()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var roleMgr = CreateRoleManager();
|
||||
var roleName = "findRoleByNameTest" + Guid.NewGuid().ToString();
|
||||
var role = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
IdentityResultAssert.IsSuccess(await roleMgr.CreateAsync(role));
|
||||
Assert.NotNull(await roleMgr.FindByNameAsync(roleName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanFindRoleWithManager()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var roleMgr = CreateRoleManager();
|
||||
var roleName = "findRoleTest" + Guid.NewGuid().ToString();
|
||||
var role = CreateTestRole(roleName, useRoleNamePrefixAsRoleName: true);
|
||||
IdentityResultAssert.IsSuccess(await roleMgr.CreateAsync(role));
|
||||
Assert.Equal(roleName, await roleMgr.GetRoleNameAsync(await roleMgr.FindByNameAsync(roleName)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public async Task CanGetUsersInRole()
|
||||
{
|
||||
if (ShouldSkipDbTests())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var manager = CreateManager();
|
||||
var roleManager = CreateRoleManager();
|
||||
var guidName = Guid.NewGuid().ToString("n") + "UsersInRole";
|
||||
var roles = GenerateRoles(guidName, 4);
|
||||
var roleNameList = new List<string>();
|
||||
|
||||
foreach (var role in roles)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await roleManager.CreateAsync(role));
|
||||
roleNameList.Add(await roleManager.GetRoleNameAsync(role));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
var user = CreateTestUser();
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
|
||||
if ((i % 2) == 0)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await manager.AddToRolesAsync(user, roleNameList));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var role in roles)
|
||||
{
|
||||
Assert.Equal(3, (await manager.GetUsersInRoleAsync(await roleManager.GetRoleNameAsync(role))).Count);
|
||||
}
|
||||
|
||||
Assert.Equal(0, (await manager.GetUsersInRoleAsync("123456")).Count);
|
||||
}
|
||||
|
||||
private List<TRole> GenerateRoles(string namePrefix, int count)
|
||||
{
|
||||
var roles = new List<TRole>(count);
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
roles.Add(CreateTestRole(namePrefix + i));
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
/// <summary>
|
||||
/// test logger.
|
||||
/// </summary>
|
||||
public interface ITestLogger
|
||||
{
|
||||
/// <summary>
|
||||
/// log messages.
|
||||
/// </summary>
|
||||
IList<string> LogMessages { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test logger.
|
||||
/// </summary>
|
||||
/// <typeparam name="TName"></typeparam>
|
||||
public class TestLogger<TName> : ILogger<TName>, ITestLogger
|
||||
{
|
||||
/// <summary>
|
||||
/// log messages.
|
||||
/// </summary>
|
||||
public IList<string> LogMessages { get; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <typeparam name="TState"></typeparam>
|
||||
/// <param name="state"></param>
|
||||
/// <returns></returns>
|
||||
public IDisposable BeginScope<TState>(TState state)
|
||||
{
|
||||
LogMessages.Add(state?.ToString());
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="logLevel"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TState"></typeparam>
|
||||
/// <param name="logLevel"></param>
|
||||
/// <param name="eventId"></param>
|
||||
/// <param name="state"></param>
|
||||
/// <param name="exception"></param>
|
||||
/// <param name="formatter"></param>
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
{
|
||||
if (formatter == null)
|
||||
{
|
||||
LogMessages.Add(state.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMessages.Add(formatter(state, exception));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2116
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user