From 42a4c12782cb5ddcc251d8e6a60fc4e991cb999f Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Tue, 16 May 2017 18:22:08 +0500 Subject: [PATCH 1/8] VS 2017 migration --- LinqToDB.Identity.sln | 15 +++-- global.json | 3 - .../IdentitySample.Mvc.csproj | 57 ++++++++++++++++++ .../IdentitySample.Mvc.xproj | 18 ------ samples/IdentitySample.Mvc/project.json | 59 ------------------- .../LinqToDB.Identity.csproj | 47 +++++++++++++++ src/LinqToDB.Identity/LinqToDB.Identity.xproj | 17 ------ src/LinqToDB.Identity/TaskTools.cs | 28 +++++++++ src/LinqToDB.Identity/project.json | 47 --------------- ...y.EntityFrameworkCore.InMemory.Test.csproj | 48 +++++++++++++++ ...ty.EntityFrameworkCore.InMemory.Test.xproj | 20 ------- .../project.json | 33 ----------- ...e.Identity.EntityFrameworkCore.Test.csproj | 56 ++++++++++++++++++ ...re.Identity.EntityFrameworkCore.Test.xproj | 20 ------- .../project.json | 46 --------------- 15 files changed, 243 insertions(+), 271 deletions(-) delete mode 100644 global.json create mode 100644 samples/IdentitySample.Mvc/IdentitySample.Mvc.csproj delete mode 100644 samples/IdentitySample.Mvc/IdentitySample.Mvc.xproj delete mode 100644 samples/IdentitySample.Mvc/project.json create mode 100644 src/LinqToDB.Identity/LinqToDB.Identity.csproj delete mode 100644 src/LinqToDB.Identity/LinqToDB.Identity.xproj create mode 100644 src/LinqToDB.Identity/TaskTools.cs delete mode 100644 src/LinqToDB.Identity/project.json create mode 100644 test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.csproj delete mode 100644 test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.xproj delete mode 100644 test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/project.json create mode 100644 test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.csproj delete mode 100644 test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.xproj delete mode 100644 test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/project.json diff --git a/LinqToDB.Identity.sln b/LinqToDB.Identity.sln index 5c8552b34..604af4f06 100644 --- a/LinqToDB.Identity.sln +++ b/LinqToDB.Identity.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.26403.7 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0F647068-6602-4E24-B1DC-8ED91481A50A}" EndProject @@ -8,22 +8,21 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{52D59F18-6 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{58D94A0E-C2B7-43A7-8826-99ECBB1E0A50}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "IdentitySample.Mvc", "samples\IdentitySample.Mvc\IdentitySample.Mvc.xproj", "{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{970CAB07-F853-4712-AA12-BD8961C8E430}" ProjectSection(SolutionItems) = preProject appveyor.yml = appveyor.yml build.cmd = build.cmd build.ps1 = build.ps1 - global.json = global.json NuGet.config = NuGet.config EndProjectSection EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test", "test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.xproj", "{37236EA3-915D-46D5-997C-DF513C500E4B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IdentitySample.Mvc", "samples\IdentitySample.Mvc\IdentitySample.Mvc.csproj", "{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test", "test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.csproj", "{37236EA3-915D-46D5-997C-DF513C500E4B}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test", "test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.xproj", "{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test", "test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.csproj", "{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "LinqToDB.Identity", "src\LinqToDB.Identity\LinqToDB.Identity.xproj", "{4490894C-3572-4E63-86F1-EE5105CE8A06}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinqToDB.Identity", "src\LinqToDB.Identity\LinqToDB.Identity.csproj", "{4490894C-3572-4E63-86F1-EE5105CE8A06}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/global.json b/global.json deleted file mode 100644 index 983ba0401..000000000 --- a/global.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "projects": ["src"] -} diff --git a/samples/IdentitySample.Mvc/IdentitySample.Mvc.csproj b/samples/IdentitySample.Mvc/IdentitySample.Mvc.csproj new file mode 100644 index 000000000..7bfc545e8 --- /dev/null +++ b/samples/IdentitySample.Mvc/IdentitySample.Mvc.csproj @@ -0,0 +1,57 @@ + + + + Identity sample MVC application on ASP.NET Core + 1.1.0 + Microsoft + net451;netcoreapp1.1 + true + IdentitySample.Mvc + Exe + IdentitySample.Mvc + 1.1.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/IdentitySample.Mvc/IdentitySample.Mvc.xproj b/samples/IdentitySample.Mvc/IdentitySample.Mvc.xproj deleted file mode 100644 index 5f83d0d09..000000000 --- a/samples/IdentitySample.Mvc/IdentitySample.Mvc.xproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - e1bfa023-cffd-49ce-8466-1c28dd2ec1f6 - .\obj - .\bin\ - - - 2.0 - 41532 - - - \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/project.json b/samples/IdentitySample.Mvc/project.json deleted file mode 100644 index 9111a0216..000000000 --- a/samples/IdentitySample.Mvc/project.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "authors": [ - "Microsoft" - ], - "description": "Identity sample MVC application on ASP.NET Core", - "version": "1.1.0-*", - "dependencies": { - "Microsoft.AspNetCore.Authentication.Cookies": "1.1.0-*", - "Microsoft.AspNetCore.Authentication.Facebook": "1.1.0-*", - "Microsoft.AspNetCore.Authentication.Google": "1.1.0-*", - "Microsoft.AspNetCore.Authentication.Twitter": "1.1.0-*", - "Microsoft.AspNetCore.Authorization": "1.1.0-*", - "Microsoft.AspNetCore.DataProtection.Extensions": "1.1.0-*", - "Microsoft.AspNetCore.Diagnostics": "1.1.0-*", - "Microsoft.AspNetCore.Identity": "1.1.0-*", - "Microsoft.AspNetCore.Mvc": "1.1.0-*", - "Microsoft.AspNetCore.Mvc.TagHelpers": "1.1.0-*", - "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-*", - "Microsoft.AspNetCore.StaticFiles": "1.1.0-*", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0-*", - "Microsoft.Extensions.Configuration.Json": "1.1.0-*", - "Microsoft.Extensions.Configuration.UserSecrets": "1.1.0-*", - "Microsoft.Extensions.Logging.Console": "1.1.0-*", - "Microsoft.Extensions.Logging.Debug": "1.1.0-*", - - "LinqToDB.Identity": "1.1.0-*" - }, - "buildOptions": { - "emitEntryPoint": true, - "preserveCompilationContext": true, - "compile": { - "exclude": [ - "./Data/Migrations/*.cs" - ] - } - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.1.0-*", - "type": "platform" - } - } - } - }, - "tools": { - "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-*", - "Microsoft.EntityFrameworkCore.Tools.DotNet": "1.0.0-*" - }, - "publishOptions": { - "include": [ - "appsettings.json", - "web.config" - ] - } -} \ No newline at end of file diff --git a/src/LinqToDB.Identity/LinqToDB.Identity.csproj b/src/LinqToDB.Identity/LinqToDB.Identity.csproj new file mode 100644 index 000000000..34fb69419 --- /dev/null +++ b/src/LinqToDB.Identity/LinqToDB.Identity.csproj @@ -0,0 +1,47 @@ + + + + ASP.NET Core Identity provider that uses LinqToDB. + 1.1.0 + Ilya Chudin + netstandard1.6;net451; + true + true + LinqToDB.Identity + ../../tools/newkey.snk + true + true + LinqToDB.Identity + aspnetcore;linq2db;identity;membership;LinqToDB + http://www.gravatar.com/avatar/fc2e509b6ed116b9aa29a7988fdb8990?s=320 + https://github.com/ili/LinqToDB.Identity + https://opensource.org/licenses/MIT + git + git://github.com/ili/LinqToDB.Identity + 1.6.1 + false + false + false + false + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/LinqToDB.Identity/LinqToDB.Identity.xproj b/src/LinqToDB.Identity/LinqToDB.Identity.xproj deleted file mode 100644 index b920c8a85..000000000 --- a/src/LinqToDB.Identity/LinqToDB.Identity.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 4490894c-3572-4e63-86f1-ee5105ce8a06 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/LinqToDB.Identity/TaskTools.cs b/src/LinqToDB.Identity/TaskTools.cs new file mode 100644 index 000000000..18153af9e --- /dev/null +++ b/src/LinqToDB.Identity/TaskTools.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace LinqToDB.Identity +{ + internal static class TaskCache + { + /// + /// Gets a completed with the value of default(T). + /// + public static Task DefaultCompletedTask { get; } = Task.FromResult(default(T)); + } + + internal static class TaskCache + { + /// + /// A that's already completed successfully. + /// + /// + /// We're caching this in a static readonly field to make it more inlinable and avoid the volatile lookup done + /// by Task.CompletedTask. + /// + public static readonly Task CompletedTask = Task.FromResult(0); + } + +} diff --git a/src/LinqToDB.Identity/project.json b/src/LinqToDB.Identity/project.json deleted file mode 100644 index b2efabb05..000000000 --- a/src/LinqToDB.Identity/project.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "description": "ASP.NET Core Identity provider that uses LinqToDB.", - "authors": ["Ilya Chudin"], - "version": "1.1.0-*", - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/newkey.snk", - "xmlDoc": true, - "embed": [ "**/*.resx" ] - }, - "packOptions": { - "licenseUrl": "https://opensource.org/licenses/MIT", - "projectUrl": "https://github.com/ili/LinqToDB.Identity", - "iconUrl": "http://www.gravatar.com/avatar/fc2e509b6ed116b9aa29a7988fdb8990?s=320", - - "requireLicenseAcceptance": false, - "repository": { - "type": "git", - "url": "git://github.com/ili/LinqToDB.Identity" - }, - "tags": [ - "aspnetcore", - "linq2db", - "identity", - "membership", - "LinqToDB" - ] - }, - "dependencies": { - "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.1.0-*", - "type": "build" - }, - "Microsoft.AspNetCore.Identity": "1.1.0-preview1-final", - "NETStandard.Library": "1.6.1-*", - "linq2db.core": "1.7.5-*", - "Microsoft.Extensions.DependencyInjection": "1.1.0-preview1-final" - }, - "frameworks": { - "netstandard1.6": { - "dependencies": { - "System.ComponentModel.TypeConverter": "4.3.0" - } - }, - "net451": {} - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.csproj b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.csproj new file mode 100644 index 000000000..ce4d118ab --- /dev/null +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.csproj @@ -0,0 +1,48 @@ + + + + netcoreapp1.0 + true + Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test + ../../tools/Key.snk + true + true + Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test + true + 1.0.4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.xproj b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.xproj deleted file mode 100644 index 5ad5dbce5..000000000 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - ea7eb28f-53b8-4009-9c6b-74db090ca8dd - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/project.json b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/project.json deleted file mode 100644 index 8ce369ab3..000000000 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/project.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "compile": { - "include": "../Shared/*.cs" - } - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Hosting": "1.1.0-preview1-final", - "Microsoft.AspNetCore.Http": "1.1.0-preview1-final", - "Microsoft.AspNetCore.Identity": "1.1.0-preview1-final", - "LinqToDB.Identity": "1.1.0", - "Microsoft.AspNetCore.Testing": "1.1.0-*", - "Moq": "4.6.36-*", - "xunit": "2.2.0-*", - "Microsoft.Data.SQLite": "1.0.0" - }, - "frameworks": { - "netcoreapp1.0": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" - }, - "System.Diagnostics.TraceSource": "4.3.0" - } - }, - "net451": {} - }, - "testRunner": "xunit" -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.csproj b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.csproj new file mode 100644 index 000000000..ad796fa8c --- /dev/null +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.csproj @@ -0,0 +1,56 @@ + + + + netcoreapp1.0 + true + Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test + ../../tools/Key.snk + true + true + Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test + true + 1.0.4 + + + + + + PreserveNewest + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.xproj b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.xproj deleted file mode 100644 index 5a7ba5926..000000000 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 37236ea3-915d-46d5-997c-df513c500e4b - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/project.json b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/project.json deleted file mode 100644 index cc1b0cb89..000000000 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/project.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "copyToOutput": { - "include": "config.json" - }, - "compile": { - "include": "../Shared/*.cs" - } - }, - "publishOptions": { - "include": [ - "config.json" - ] - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Hosting": "1.1.0-preview1-final", - "Microsoft.AspNetCore.Http": "1.1.0-preview1-final", - "Microsoft.AspNetCore.Identity": "1.1.0-preview1-final", - "LinqToDB.Identity": "1.1.0", - "Microsoft.AspNetCore.TestHost": "1.1.0-preview1-final", - "Microsoft.AspNetCore.Testing": "1.1.0-*", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0-preview1-final", - "Microsoft.Extensions.Configuration.FileExtensions": "1.1.0-preview1-final", - "Microsoft.Extensions.Configuration.Json": "1.1.0-preview1-final", - "Moq": "4.6.36-*", - "xunit": "2.2.0-*", - - "Microsoft.Data.SQLite": "1.0.0" - }, - "frameworks": { - "netcoreapp1.0": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" - }, - "System.Diagnostics.TraceSource": "4.3.0" - } - }, - "net451": {} - }, - "testRunner": "xunit" -} \ No newline at end of file From cba9bd09f668856155fa7a8273c22d92317d3648 Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Tue, 16 May 2017 18:43:06 +0500 Subject: [PATCH 2/8] new appveyor configuration new package name (linq2db.Identity) --- LinqToDB.Identity.sln | 1 + README.md | 28 ++++++++++++++----- appveyor.yml | 10 ++++--- .../LinqToDB.Identity.csproj | 2 +- 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/LinqToDB.Identity.sln b/LinqToDB.Identity.sln index 604af4f06..1fb384c5b 100644 --- a/LinqToDB.Identity.sln +++ b/LinqToDB.Identity.sln @@ -14,6 +14,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution build.cmd = build.cmd build.ps1 = build.ps1 NuGet.config = NuGet.config + README.md = README.md EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IdentitySample.Mvc", "samples\IdentitySample.Mvc\IdentitySample.Mvc.csproj", "{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}" diff --git a/README.md b/README.md index 8ba333f75..04a05a340 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,31 @@ [LinqToDB](https://github.com/linq2db/linq2db) Identity store provider for [ASP.NET Core Identity](https://github.com/aspnet/Identity) === -AppVeyor last build: [![Build status](https://ci.appveyor.com/api/projects/status/x15cyc688w9247oj?svg=true)](https://ci.appveyor.com/project/ili/linqtodb-identity) +* Current build status [![Build status](https://ci.appveyor.com/api/projects/status/2d8k9n1x5ggsuv3f?svg=true)](https://ci.appveyor.com/project/igor-tkachev/linqtodb-identity) +* Master build status [![Build status](https://ci.appveyor.com/api/projects/status/2d8k9n1x5ggsuv3f/branch/master?svg=true)](https://ci.appveyor.com/project/igor-tkachev/linqtodb-identity/branch/master) -AppVeyor master build: [![Build status](https://ci.appveyor.com/api/projects/status/x15cyc688w9247oj/branch/master?svg=true)](https://ci.appveyor.com/project/ili/linqtodb-identity/branch/master) - -## NuGet -* [NuGet.org](https://www.nuget.org/packages/LinqToDB.Identity/) -* [MyGet.org](https://www.myget.org/feed/ili/package/nuget/LinqToDB.Identity) feed: https://www.myget.org/F/ili/api/v3/index.json +## Feeds +* Release builds can be found on [NuGet](https://www.nuget.org/packages?q=linq2db) +* [MyGet](https://www.myget.org/gallery/linq2db) + * V2 `https://www.myget.org/F/linq2db/api/v2` + * V3 `https://www.myget.org/F/linq2db/api/v3/index.json` ## Usage -In general this is the same as for Entity Framework, just call `AddLinqToDBStores` instead of `AddEntityFrameworkStores` in your `Startup.cs` like [here](https://github.com/ili/LinqToDB.Identity/blob/master/samples/IdentitySample.Mvc/Startup.cs#L62) +Install package: + +`PM> Install-Package linq2db.Identity` + +In general this is the same as for Entity Framework, just call `AddLinqToDBStores` instead of `AddEntityFrameworkStores` in your `Startup.cs` like [here](https://github.com/linq2db/LinqToDB.Identity/blob/master/samples/IdentitySample.Mvc/Startup.cs#L62): +```cs +services.AddIdentity(options => { + options.Cookies.ApplicationCookie.AuthenticationScheme = "ApplicationCookie"; + options.Cookies.ApplicationCookie.CookieName = "Interop"; + options.Cookies.ApplicationCookie.DataProtectionProvider = DataProtectionProvider.Create(new DirectoryInfo("C:\\Github\\Identity\\artifacts")); +}) + .AddLinqToDBStores(new DefaultConnectionFactory()) //here + .AddDefaultTokenProviders(); +``` The main difference with Entity Framework Core storage provider are: * We do not use hardcoded classes - interfaces like `IIdentityUser` are used (but yes, we do have default implementation) diff --git a/appveyor.yml b/appveyor.yml index 9116c1ccd..9d3a9f482 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -58,14 +58,16 @@ artifacts: deploy: - provider: NuGet - server: https://www.myget.org/F/ili/api/v2 + server: https://www.myget.org/F/linq2db/api/v2 api_key: - secure: pFvgey1/w68ZvVHFN/GWZdDFjSABpBRfb0XfLnW3wvhlfyEUiSyfr3dAUcbmlpsk + secure: LDw0jeA1Yo3R4/TKv2kmlgJR8dTT6Wun2MONq3uDvtVQJG4LOU9LjvVTAc7IgRfm skip_symbols: true + on: + branch: master - provider: NuGet api_key: - secure: 9BjFlmIycM3Q3tpwlQRsoC9SPL+BqIoqHKkHihvfR9TvTpYLd9jLcnLnh8eRSmfV + secure: oTYw2IwTnz4qMD8c/MR/6mo+Nx3wa5Pp8MYfsKBCKCVuU6QCHlj+6QMXpnQses8G skip_symbols: false on: - branch: master \ No newline at end of file + branch: release \ No newline at end of file diff --git a/src/LinqToDB.Identity/LinqToDB.Identity.csproj b/src/LinqToDB.Identity/LinqToDB.Identity.csproj index 34fb69419..59052432c 100644 --- a/src/LinqToDB.Identity/LinqToDB.Identity.csproj +++ b/src/LinqToDB.Identity/LinqToDB.Identity.csproj @@ -11,7 +11,7 @@ ../../tools/newkey.snk true true - LinqToDB.Identity + linq2db.Identity aspnetcore;linq2db;identity;membership;LinqToDB http://www.gravatar.com/avatar/fc2e509b6ed116b9aa29a7988fdb8990?s=320 https://github.com/ili/LinqToDB.Identity From 406b7c284f89419295a9fe9e997134f77e299dd1 Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Wed, 17 May 2017 15:17:41 +0500 Subject: [PATCH 3/8] migrating to Cake build --- .gitignore | 3 +- LinqToDB.Identity.sln | 3 +- tools/Key.snk => Tests.snk | Bin appveyor.yml | 52 ++--- build.cake | 135 +++++++++++ build.cmd | 2 - build.ps1 | 218 ++++++++++++++---- build.sh | 133 +++++++---- linq2db.snk | Bin 0 -> 596 bytes .../LinqToDB.Identity.csproj | 2 +- ...y.EntityFrameworkCore.InMemory.Test.csproj | 2 +- ...e.Identity.EntityFrameworkCore.Test.csproj | 2 +- tools/newkey.snk | Bin 596 -> 0 bytes 13 files changed, 419 insertions(+), 133 deletions(-) rename tools/Key.snk => Tests.snk (100%) create mode 100644 build.cake delete mode 100644 build.cmd create mode 100644 linq2db.snk delete mode 100644 tools/newkey.snk diff --git a/.gitignore b/.gitignore index 0fb89cd89..03fa9e40a 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,5 @@ nuget.exe project.lock.json .vs .build/ -.testPublish/ \ No newline at end of file +.testPublish/ +tools/* diff --git a/LinqToDB.Identity.sln b/LinqToDB.Identity.sln index 1fb384c5b..922309590 100644 --- a/LinqToDB.Identity.sln +++ b/LinqToDB.Identity.sln @@ -11,8 +11,9 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{970CAB07-F853-4712-AA12-BD8961C8E430}" ProjectSection(SolutionItems) = preProject appveyor.yml = appveyor.yml - build.cmd = build.cmd + build.cake = build.cake build.ps1 = build.ps1 + linq2db.snk = linq2db.snk NuGet.config = NuGet.config README.md = README.md EndProjectSection diff --git a/tools/Key.snk b/Tests.snk similarity index 100% rename from tools/Key.snk rename to Tests.snk diff --git a/appveyor.yml b/appveyor.yml index 9d3a9f482..7a673913d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,60 +1,34 @@ init: - git config --global core.autocrlf true - -version: 1.1.0.{build} - -configuration: Release +- ps: | + [Environment]::SetEnvironmentVariable("Test:SqlServer:DefaultConnectionString", "Server=(local)\SQL2012SP1;Database=master;Integrated Security=true", "Machine") + [Environment]::SetEnvironmentVariable("Test:SqlServer:DefaultConnectionString", "Server=(local)\SQL2012SP1;Database=master;Integrated Security=true") cache: - packages -> **\packages.config - '%USERPROFILE%\.nuget\packages -> **\project.json' +environment: + nugetVersion: 1.0.0 -assembly_info: - patch: true - file: '**\AssemblyInfo.*' - assembly_version: '{version}' - assembly_file_version: '{version}' - assembly_informational_version: '{version}' +version: $(nugetVersion).{build} + +build_script: +- ps: .\build.ps1 +test: off + +artifacts: +- path: artifacts/packages/*.nupkg services: - mssql2012sp1 #- mysql #- postgresql -before_build: -- cmd: dotnet restore - build: project: LinqToDB.Identity.sln verbosity: minimal -after_build: -- cmd: dotnet pack --no-build src/LinqToDB.Identity/project.json --version-suffix=preview1-final -c=Release - -before_test: -- ps: | - [Environment]::SetEnvironmentVariable("Test:SqlServer:DefaultConnectionString", "Server=(local)\SQL2012SP1;Database=master;Integrated Security=true", "Machine") - [Environment]::SetEnvironmentVariable("Test:SqlServer:DefaultConnectionString", "Server=(local)\SQL2012SP1;Database=master;Integrated Security=true") - -test_script: -- ps: | - Write-Host "Connection string" - Write-Host $([Environment]::GetEnvironmentVariable("Test:SqlServer:DefaultConnectionString")) - dotnet test test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test -c Release -f netcoreapp1.0 - $test1res = $LASTEXITCODE - # upload results to AppVeyor - #$wc = New-Object 'System.Net.WebClient' - #$wc.UploadFile("https://ci.appveyor.com/api/testresults/xunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\TestResult.xml)) - dotnet test test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test -c Release -f netcoreapp1.0 - $test2res = $LASTEXITCODE - # upload results to AppVeyor - #$wc = New-Object 'System.Net.WebClient' - #$wc.UploadFile("https://ci.appveyor.com/api/testresults/xunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\TestResult.xml)) - IF ($test1res -ne 0 -or $test2res -ne 0) { exit -1 } - -artifacts: -- path: src\**\*.nupkg deploy: - provider: NuGet diff --git a/build.cake b/build.cake new file mode 100644 index 000000000..870e5937a --- /dev/null +++ b/build.cake @@ -0,0 +1,135 @@ +#addin "MagicChunks" + +var target = Argument("target", "Default"); +var configuration = Argument("configuration", "Release"); + +/////////////////////////////////////////////////////////////////////////////// +// GLOBAL VARIABLES +/////////////////////////////////////////////////////////////////////////////// +var isLocalBuild = !AppVeyor.IsRunningOnAppVeyor; +var packPath = Directory("./src/LinqToDB.Identity"); +var sourcePath = Directory("./src"); +var testsPath = Directory("test"); +var buildArtifacts = Directory("./artifacts/packages"); +var solutionName = "./LinqToDB.Identity.sln"; +var envPackageVersion = EnvironmentVariable("nugetVersion"); +var argRelease = Argument("Release", null); + +var packageSuffix = ""; +var packageVersion = ""; +var fullPackageVersion = ""; + +Task("Build") + .IsDependentOn("Clean") + .IsDependentOn("Restore") + .Does(() => +{ + + // Patch Version for CI builds + if (!isLocalBuild || envPackageVersion != null) + { + packageVersion = envPackageVersion; + var assemblyVersion = packageVersion + ".0"; + + if (AppVeyor.Environment.Repository.Branch.ToLower() != "release" && argRelease == null) + { + packageSuffix = "rc" + AppVeyor.Environment.Build.Number.ToString(); + fullPackageVersion = packageVersion + "-" + packageSuffix; + } + + Console.WriteLine("Package Version: {0}", packageVersion); + Console.WriteLine("Package Suffix : {0}", packageSuffix); + Console.WriteLine("Assembly Version: {0}", assemblyVersion); + + + TransformConfig("./src/LinqToDB.Identity/LinqToDB.Identity.csproj", "./src/LinqToDB.Identity/LinqToDB.Identity.csproj", + new TransformationCollection { + { "Project/PropertyGroup/Version", fullPackageVersion }, + { "Project/PropertyGroup/VersionPrefix", packageVersion }, + { "Project/PropertyGroup/VersionSuffix", packageSuffix }, + { "Project/PropertyGroup/AssemblyVersion", assemblyVersion }, + { "Project/PropertyGroup/FileVersion", assemblyVersion }, + }); + + } + + var settings = new DotNetCoreBuildSettings + { + Configuration = configuration + // Runtime = IsRunningOnWindows() ? null : "unix-x64" + }; + + DotNetCoreBuild(solutionName, settings); +}); + +Task("RunTests") + .IsDependentOn("Restore") + .IsDependentOn("Clean") + .Does(() => +{ + var projects = GetFiles("./test/**/*.csproj"); + + foreach(var project in projects) + { + var settings = new DotNetCoreTestSettings + { + Configuration = configuration, + NoBuild = true + }; + + Console.WriteLine(project.FullPath); + + DotNetCoreTest(project.FullPath, settings); + } +}); + +Task("Pack") + .IsDependentOn("Restore") + .IsDependentOn("Clean") + .Does(() => +{ + var settings = new DotNetCorePackSettings + { + Configuration = configuration, + OutputDirectory = buildArtifacts, + NoBuild = true, + VersionSuffix = packageSuffix + }; + +/* + if (!string.IsNullOrEmpty(packageVersion)) + settings.ArgumentCustomization = b => + { + Console.WriteLine("Package Version: {0}", packageVersion); + + b.Append(" /p:VersionSuffix=" + "rc10"); + return b; + }; +*/ + + DotNetCorePack(packPath, settings); +}); + +Task("Clean") + .Does(() => +{ + CleanDirectories(new DirectoryPath[] { buildArtifacts }); +}); + +Task("Restore") + .Does(() => +{ + var settings = new DotNetCoreRestoreSettings + { + //Sources = new [] { "https://api.nuget.org/v3/index.json" } + }; + + DotNetCoreRestore(solutionName, settings); +}); + +Task("Default") + .IsDependentOn("Build") + .IsDependentOn("RunTests") + .IsDependentOn("Pack"); + +RunTarget(target); \ No newline at end of file diff --git a/build.cmd b/build.cmd deleted file mode 100644 index 7d4894cb4..000000000 --- a/build.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 787f63ac0..44de57932 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,67 +1,189 @@ -$ErrorActionPreference = "Stop" +########################################################################## +# This is the Cake bootstrapper script for PowerShell. +# This file was downloaded from https://github.com/cake-build/resources +# Feel free to change this file to fit your needs. +########################################################################## -function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) +<# + +.SYNOPSIS +This is a Powershell script to bootstrap a Cake build. + +.DESCRIPTION +This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) +and execute your Cake build script with the parameters you provide. + +.PARAMETER Script +The build script to execute. +.PARAMETER Target +The build script target to run. +.PARAMETER Configuration +The build configuration to use. +.PARAMETER Verbosity +Specifies the amount of information to be displayed. +.PARAMETER Experimental +Tells Cake to use the latest Roslyn release. +.PARAMETER WhatIf +Performs a dry run of the build script. +No tasks will be executed. +.PARAMETER Mono +Tells Cake to use the Mono scripting engine. +.PARAMETER SkipToolPackageRestore +Skips restoring of packages. +.PARAMETER ScriptArgs +Remaining arguments are added here. + +.LINK +http://cakebuild.net + +#> + +[CmdletBinding()] +Param( + [string]$Script = "build.cake", + [string]$Target = "Default", + [ValidateSet("Release", "Debug")] + [string]$Configuration = "Release", + [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] + [string]$Verbosity = "Verbose", + [switch]$Experimental, + [Alias("DryRun","Noop")] + [switch]$WhatIf, + [switch]$Mono, + [switch]$SkipToolPackageRestore, + [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] + [string[]]$ScriptArgs +) + +[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null +function MD5HashFile([string] $filePath) { - while($true) + if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) { - try - { - Invoke-WebRequest $url -OutFile $downloadLocation - break - } - catch + return $null + } + + [System.IO.Stream] $file = $null; + [System.Security.Cryptography.MD5] $md5 = $null; + try + { + $md5 = [System.Security.Cryptography.MD5]::Create() + $file = [System.IO.File]::OpenRead($filePath) + return [System.BitConverter]::ToString($md5.ComputeHash($file)) + } + finally + { + if ($file -ne $null) { - $exceptionMessage = $_.Exception.Message - Write-Host "Failed to download '$url': $exceptionMessage" - if ($retries -gt 0) { - $retries-- - Write-Host "Waiting 10 seconds before retrying. Retries left: $retries" - Start-Sleep -Seconds 10 - - } - else - { - $exception = $_.Exception - throw $exception - } + $file.Dispose() } } } -cd $PSScriptRoot +Write-Host "Preparing to run build script..." -$repoFolder = $PSScriptRoot -$env:REPO_FOLDER = $repoFolder +if(!$PSScriptRoot){ + $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent +} -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0-preview1.zip" -if ($env:KOREBUILD_ZIP) -{ - $koreBuildZip=$env:KOREBUILD_ZIP +$TOOLS_DIR = Join-Path $PSScriptRoot "tools" +$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" +$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" +$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" +$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" +$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" + +# Should we use mono? +$UseMono = ""; +if($Mono.IsPresent) { + Write-Verbose -Message "Using the Mono based scripting engine." + $UseMono = "-mono" } -$buildFolder = ".build" -$buildFile="$buildFolder\KoreBuild.ps1" +# Should we use the new Roslyn? +$UseExperimental = ""; +if($Experimental.IsPresent -and !($Mono.IsPresent)) { + Write-Verbose -Message "Using experimental version of Roslyn." + $UseExperimental = "-experimental" +} -if (!(Test-Path $buildFolder)) { - Write-Host "Downloading KoreBuild from $koreBuildZip" - - $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() - New-Item -Path "$tempFolder" -Type directory | Out-Null +# Is this a dry run? +$UseDryRun = ""; +if($WhatIf.IsPresent) { + $UseDryRun = "-dryrun" +} - $localZipFile="$tempFolder\korebuild.zip" - - DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 +# Make sure tools folder exists +if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { + Write-Verbose -Message "Creating tools directory..." + New-Item -Path $TOOLS_DIR -Type directory | out-null +} + +# Make sure that packages.config exist. +if (!(Test-Path $PACKAGES_CONFIG)) { + Write-Verbose -Message "Downloading packages.config..." + try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { + Throw "Could not download packages.config." + } +} + +# Try find NuGet.exe in path if not exists +if (!(Test-Path $NUGET_EXE)) { + Write-Verbose -Message "Trying to find nuget.exe in PATH..." + $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_) } + $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 + if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { + Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." + $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName + } +} + +# Try download NuGet.exe if not exists +if (!(Test-Path $NUGET_EXE)) { + Write-Verbose -Message "Downloading NuGet.exe..." + try { + (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE) + } catch { + Throw "Could not download NuGet.exe." + } +} + +# Save nuget.exe path to environment to be available to child processed +$ENV:NUGET_EXE = $NUGET_EXE + +# Restore tools from NuGet? +if(-Not $SkipToolPackageRestore.IsPresent) { + Push-Location + Set-Location $TOOLS_DIR + + # Check for changes in packages.config and remove installed tools if true. + [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) + if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or + ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { + Write-Verbose -Message "Missing or changed package.config hash..." + Remove-Item * -Recurse -Exclude packages.config,nuget.exe + } - Add-Type -AssemblyName System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) - - New-Item -Path "$buildFolder" -Type directory | Out-Null - copy-item "$tempFolder\**\build\*" $buildFolder -Recurse + Write-Verbose -Message "Restoring tools from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" - # Cleanup - if (Test-Path $tempFolder) { - Remove-Item -Recurse -Force $tempFolder + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring NuGet tools." } + else + { + $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" + } + Write-Verbose -Message ($NuGetOutput | out-string) + Pop-Location +} + +# Make sure that Cake has been installed. +if (!(Test-Path $CAKE_EXE)) { + Throw "Could not find Cake.exe at $CAKE_EXE" } -&"$buildFile" $args \ No newline at end of file +# Start Cake +Write-Host "Running build script..." +Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs" +exit $LASTEXITCODE \ No newline at end of file diff --git a/build.sh b/build.sh index 355c68285..6e8f207c8 100755 --- a/build.sh +++ b/build.sh @@ -1,46 +1,101 @@ #!/usr/bin/env bash -repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.1.0-preview1.zip" -if [ ! -z $KOREBUILD_ZIP ]; then - koreBuildZip=$KOREBUILD_ZIP +########################################################################## +# This is the Cake bootstrapper script for Linux and OS X. +# This file was downloaded from https://github.com/cake-build/resources +# Feel free to change this file to fit your needs. +########################################################################## + +# Define directories. +SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +TOOLS_DIR=$SCRIPT_DIR/tools +NUGET_EXE=$TOOLS_DIR/nuget.exe +CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe +PACKAGES_CONFIG=$TOOLS_DIR/packages.config +PACKAGES_CONFIG_MD5=$TOOLS_DIR/packages.config.md5sum + +# Define md5sum or md5 depending on Linux/OSX +MD5_EXE= +if [[ "$(uname -s)" == "Darwin" ]]; then + MD5_EXE="md5 -r" +else + MD5_EXE="md5sum" +fi + +# Define default arguments. +SCRIPT="build.cake" +TARGET="Default" +CONFIGURATION="Release" +VERBOSITY="verbose" +DRYRUN= +SHOW_VERSION=false +SCRIPT_ARGUMENTS=() + +# Parse arguments. +for i in "$@"; do + case $1 in + -s|--script) SCRIPT="$2"; shift ;; + -t|--target) TARGET="$2"; shift ;; + -c|--configuration) CONFIGURATION="$2"; shift ;; + -v|--verbosity) VERBOSITY="$2"; shift ;; + -d|--dryrun) DRYRUN="-dryrun" ;; + --version) SHOW_VERSION=true ;; + --) shift; SCRIPT_ARGUMENTS+=("$@"); break ;; + *) SCRIPT_ARGUMENTS+=("$1") ;; + esac + shift +done + +# Make sure the tools folder exist. +if [ ! -d "$TOOLS_DIR" ]; then + mkdir "$TOOLS_DIR" +fi + +# Make sure that packages.config exist. +if [ ! -f "$TOOLS_DIR/packages.config" ]; then + echo "Downloading packages.config..." + curl -Lsfo "$TOOLS_DIR/packages.config" http://cakebuild.net/download/bootstrapper/packages + if [ $? -ne 0 ]; then + echo "An error occured while downloading packages.config." + exit 1 + fi fi -buildFolder=".build" -buildFile="$buildFolder/KoreBuild.sh" - -if test ! -d $buildFolder; then - echo "Downloading KoreBuild from $koreBuildZip" - - tempFolder="/tmp/KoreBuild-$(uuidgen)" - mkdir $tempFolder - - localZipFile="$tempFolder/korebuild.zip" - - retries=6 - until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) - do - echo "Failed to download '$koreBuildZip'" - if [ "$retries" -le 0 ]; then - exit 1 - fi - retries=$((retries - 1)) - echo "Waiting 10 seconds before retrying. Retries left: $retries" - sleep 10s - done - - unzip -q -d $tempFolder $localZipFile - - mkdir $buildFolder - cp -r $tempFolder/**/build/** $buildFolder - - chmod +x $buildFile - - # Cleanup - if test ! -d $tempFolder; then - rm -rf $tempFolder +# Download NuGet if it does not exist. +if [ ! -f "$NUGET_EXE" ]; then + echo "Downloading NuGet..." + curl -Lsfo "$NUGET_EXE" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe + if [ $? -ne 0 ]; then + echo "An error occured while downloading nuget.exe." + exit 1 fi fi -$buildFile -r $repoFolder "$@" \ No newline at end of file +# Restore tools from NuGet. +pushd "$TOOLS_DIR" >/dev/null +if [ ! -f $PACKAGES_CONFIG_MD5 ] || [ "$( cat $PACKAGES_CONFIG_MD5 | sed 's/\r$//' )" != "$( $MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' )" ]; then + find . -type d ! -name . | xargs rm -rf +fi + +mono "$NUGET_EXE" install -ExcludeVersion +if [ $? -ne 0 ]; then + echo "Could not restore NuGet packages." + exit 1 +fi + +$MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' >| $PACKAGES_CONFIG_MD5 + +popd >/dev/null + +# Make sure that Cake has been installed. +if [ ! -f "$CAKE_EXE" ]; then + echo "Could not find Cake.exe at '$CAKE_EXE'." + exit 1 +fi + +# Start Cake +if $SHOW_VERSION; then + exec mono "$CAKE_EXE" -version +else + exec mono "$CAKE_EXE" $SCRIPT -verbosity=$VERBOSITY -configuration=$CONFIGURATION -target=$TARGET $DRYRUN "${SCRIPT_ARGUMENTS[@]}" +fi \ No newline at end of file diff --git a/linq2db.snk b/linq2db.snk new file mode 100644 index 0000000000000000000000000000000000000000..774bb0a9abbc205e6d9889970ab5562f48d85c6c GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa500971>7<@|%^N8&F=^aQ zBkf&MK&#uesq#nLnAvnX*xz5Q*;&8s$4_0o1MY%qu_ozq0;nJmaccmN!00T4W)=%H z-x+vm&GSbu5dHfpN>16lnk3|lwV8p0x~YwDep2XERIpt{KwvG{t&=@##bLtq77}h_ z+fF2|EX1cJ5I}l`e|+dIjr*F6aO>ZVlBHnry$Ok2X-r`!W)&LEXia#Y*@pf>KiUfR z&@8Zjw04I03N(epB_LwgGCKkp8Wpwy8*(mPwxA&y0$dF=@tWar&F-(Rqiz^A7}Jc#*p-wf=3{~MJwpmy?%vY{JJ6 zd=(N#;?yjG=Zqb0s9S)HXubh?o!J(E8>}ojl+3W`JI=ij+&aw5_6^2(?@d4`kf1A` z$s8e%Q8HljiMjg_?$g!WCyqt6=M~;$3gjSQ(m$|KOvN(PB#>({o@9}S*^|uVCYazI iG6q0fhX`CYjipz@YHH{)H29u6y!ykg!LTK!h^3yEXCOQP literal 0 HcmV?d00001 diff --git a/src/LinqToDB.Identity/LinqToDB.Identity.csproj b/src/LinqToDB.Identity/LinqToDB.Identity.csproj index 59052432c..eb6779336 100644 --- a/src/LinqToDB.Identity/LinqToDB.Identity.csproj +++ b/src/LinqToDB.Identity/LinqToDB.Identity.csproj @@ -8,7 +8,7 @@ true true LinqToDB.Identity - ../../tools/newkey.snk + $(SolutionDir)linq2db.snk true true linq2db.Identity diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.csproj b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.csproj index ce4d118ab..e50d6c756 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.csproj +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.csproj @@ -4,7 +4,7 @@ netcoreapp1.0 true Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test - ../../tools/Key.snk + $(SolutionDir)Tests.snk true true Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.csproj b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.csproj index ad796fa8c..2c2cc2774 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.csproj +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.csproj @@ -4,7 +4,7 @@ netcoreapp1.0 true Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test - ../../tools/Key.snk + $(SolutionDir)Tests.snk true true Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test diff --git a/tools/newkey.snk b/tools/newkey.snk deleted file mode 100644 index 2e1bc24bd8ad1fd69ccde3f68f3c3a0ecad92c0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50096u3^)ak4y8^%Ao+ZDG8f zKoLi_eV>@K3h^`H$Tdt(&C6Y3x|$|x&L>OXk-cnt9o^kDXJ5?8FI$5Mk5%JpkIv*b z-X|GIBvqdE8w`BY0*K1RRCv1zWqkKZ&>oi6E!Z9JN86{aVl}sA zj%NB@V^Rv<&&c%wLTYXsXenet2Xj-2VL{Oz3Xt52X0|vq1f(u*&j|KCr!G?@-d0|) z2Nhfk=1Cnkx@;W4K~u?q6(M+0xhkvH^TX~23S(qYUm!6 z6u+3i^fL|nw@!N+hm00En%fk8^SfZQ>e;UIkN_BTCrlzXZ*i+y%-E5-#6v``{IpX(_NWt08 zz0)VZmRM^6@@n@0+sXkTTBzDO^H0Rm-uQj#~r(|{iRMA-W|oMMPlbO0E2E|Fai&-EYKo)Q?kf1gC` Date: Wed, 17 May 2017 15:22:12 +0500 Subject: [PATCH 4/8] cleanup --- build.cake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 870e5937a..2ddb75630 100644 --- a/build.cake +++ b/build.cake @@ -12,6 +12,7 @@ var sourcePath = Directory("./src"); var testsPath = Directory("test"); var buildArtifacts = Directory("./artifacts/packages"); var solutionName = "./LinqToDB.Identity.sln"; +var nugetProject = "./src/LinqToDB.Identity/LinqToDB.Identity.csproj"; var envPackageVersion = EnvironmentVariable("nugetVersion"); var argRelease = Argument("Release", null); @@ -42,7 +43,7 @@ Task("Build") Console.WriteLine("Assembly Version: {0}", assemblyVersion); - TransformConfig("./src/LinqToDB.Identity/LinqToDB.Identity.csproj", "./src/LinqToDB.Identity/LinqToDB.Identity.csproj", + TransformConfig(nugetProject, nugetProject, new TransformationCollection { { "Project/PropertyGroup/Version", fullPackageVersion }, { "Project/PropertyGroup/VersionPrefix", packageVersion }, From 13d1be7f538314a77fd07d45db15118c230feb7e Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Wed, 17 May 2017 15:29:55 +0500 Subject: [PATCH 5/8] appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 7a673913d..a8b7d9a56 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,6 @@ init: - git config --global core.autocrlf true -- ps: | + - ps: | [Environment]::SetEnvironmentVariable("Test:SqlServer:DefaultConnectionString", "Server=(local)\SQL2012SP1;Database=master;Integrated Security=true", "Machine") [Environment]::SetEnvironmentVariable("Test:SqlServer:DefaultConnectionString", "Server=(local)\SQL2012SP1;Database=master;Integrated Security=true") From e28b4c9ec83ac232583467b1cf4dbf7c726d5709 Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Wed, 17 May 2017 15:31:56 +0500 Subject: [PATCH 6/8] appveyor.yml --- appveyor.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index a8b7d9a56..9e6615786 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,8 +1,7 @@ init: - git config --global core.autocrlf true - - ps: | - [Environment]::SetEnvironmentVariable("Test:SqlServer:DefaultConnectionString", "Server=(local)\SQL2012SP1;Database=master;Integrated Security=true", "Machine") - [Environment]::SetEnvironmentVariable("Test:SqlServer:DefaultConnectionString", "Server=(local)\SQL2012SP1;Database=master;Integrated Security=true") + - ps: [Environment]::SetEnvironmentVariable("Test:SqlServer:DefaultConnectionString", "Server=(local)\SQL2012SP1;Database=master;Integrated Security=true", "Machine") + - ps: [Environment]::SetEnvironmentVariable("Test:SqlServer:DefaultConnectionString", "Server=(local)\SQL2012SP1;Database=master;Integrated Security=true") cache: - packages -> **\packages.config @@ -15,6 +14,7 @@ version: $(nugetVersion).{build} build_script: - ps: .\build.ps1 + test: off artifacts: From cf88353bd6268739d411d3be084694dd0c8df27c Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Wed, 17 May 2017 15:43:26 +0500 Subject: [PATCH 7/8] cleanup --- NuGet.config | 11 +- appveyor.yml | 3 +- .../Controllers/AccountController.cs | 871 ++-- .../Controllers/HomeController.cs | 40 +- .../Controllers/ManageController.cs | 624 ++- samples/IdentitySample.Mvc/MessageServices.cs | 27 +- .../ExternalLoginConfirmationViewModel.cs | 20 +- .../ForgotPasswordViewModel.cs | 20 +- .../AccountViewModels/LoginViewModel.cs | 30 +- .../AccountViewModels/RegisterViewModel.cs | 40 +- .../ResetPasswordViewModel.cs | 38 +- .../AccountViewModels/SendCodeViewModel.cs | 19 +- .../AccountViewModels/VerifyCodeViewModel.cs | 32 +- .../Models/ApplicationDbContext.cs | 12 +- .../Models/ApplicationUser.cs | 14 +- .../AddPhoneNumberViewModel.cs | 22 +- .../ChangePasswordViewModel.cs | 40 +- .../ConfigureTwoFactorViewModel.cs | 15 +- .../ManageViewModels/FactorViewModel.cs | 17 +- .../Models/ManageViewModels/IndexViewModel.cs | 21 +- .../ManageViewModels/ManageLoginsViewModel.cs | 15 +- .../ManageViewModels/RemoveLoginViewModel.cs | 20 +- .../ManageViewModels/SetPasswordViewModel.cs | 32 +- .../VerifyPhoneNumberViewModel.cs | 26 +- samples/IdentitySample.Mvc/Program.cs | 30 +- .../Properties/launchSettings.json | 46 +- .../Services/IEmailSender.cs | 15 +- .../IdentitySample.Mvc/Services/ISmsSender.cs | 15 +- .../Services/MessageServices.cs | 39 +- samples/IdentitySample.Mvc/Startup.cs | 232 +- .../Views/Account/ConfirmEmail.cshtml | 10 +- .../Account/ExternalLoginConfirmation.cshtml | 46 +- .../Views/Account/ExternalLoginFailure.cshtml | 8 +- .../Views/Account/ForgotPassword.cshtml | 8 +- .../Account/ForgotPasswordConfirmation.cshtml | 6 +- .../Views/Account/Lockout.cshtml | 8 +- .../Views/Account/Login.cshtml | 159 +- .../Views/Account/Register.cshtml | 64 +- .../Views/Account/ResetPassword.cshtml | 66 +- .../Account/ResetPasswordConfirmation.cshtml | 6 +- .../Views/Account/SendCode.cshtml | 22 +- .../Views/Account/VerifyCode.cshtml | 56 +- .../Views/Home/Index.cshtml | 448 +- .../Views/Manage/AddPhoneNumber.cshtml | 36 +- .../Views/Manage/ChangePassword.cshtml | 64 +- .../Views/Manage/Index.cshtml | 74 +- .../Views/Manage/ManageLogins.cshtml | 83 +- .../Views/Manage/SetPassword.cshtml | 54 +- .../Views/Manage/VerifyPhoneNumber.cshtml | 40 +- .../Views/Shared/_Layout.cshtml | 90 +- .../Views/Shared/_LoginPartial.cshtml | 35 +- .../Shared/_ValidationScriptsPartial.cshtml | 4 +- .../Views/_ViewImports.cshtml | 2 +- .../Views/_ViewStart.cshtml | 4 +- samples/IdentitySample.Mvc/appsettings.json | 29 +- samples/IdentitySample.Mvc/web.Debug.config | 10 +- samples/IdentitySample.Mvc/web.Release.config | 12 +- samples/IdentitySample.Mvc/web.config | 14 +- .../IdentitySample.Mvc/wwwroot/css/site.css | 34 +- .../DefaultConnectionFactory.cs | 10 +- src/LinqToDB.Identity/Extensions.cs | 6 +- .../IdentityDataConnection.cs | 8 +- .../IdentityLinqToDbBuilderExtensions.cs | 3 +- src/LinqToDB.Identity/IdentityRole.cs | 5 +- src/LinqToDB.Identity/IdentityUser.cs | 2 +- src/LinqToDB.Identity/RoleStore.cs | 15 +- src/LinqToDB.Identity/TaskTools.cs | 16 +- src/LinqToDB.Identity/UserStore.cs | 77 +- .../InMemoryContext.cs | 3 +- .../InMemoryEFUserStoreTest.cs | 152 +- .../InMemoryStoreWithGenericsTest.cs | 607 +-- .../RoleStoreTest.cs | 139 +- .../TestIdentityFactory.cs | 75 +- .../CustomPocoTest.cs | 260 +- .../DbUtil.cs | 42 +- .../DefaultPocoTest.cs | 350 +- .../MiscTest.cs | 12 +- .../SqlStoreTestBase.cs | 683 +-- .../UserStoreGuidKeyTest.cs | 95 +- .../UserStoreIntKeyTest.cs | 52 +- .../UserStoreStringKeyTest.cs | 52 +- .../UserStoreTest.cs | 787 ++-- .../UserStoreWithGenericsTest.cs | 695 +-- .../EntityFrameworkServiceBuilderExtension.cs | 12 +- .../Utilities/ScratchDatabaseFixture.cs | 20 +- .../Utilities/SqlServerTestStore.cs | 312 +- .../Utilities/TestEnvironment.cs | 28 +- .../config.json | 8 +- test/Shared/ApiConsistencyTestBase.cs | 144 +- test/Shared/IdentityResultAssert.cs | 73 +- test/Shared/MockHelpers.cs | 158 +- test/Shared/PasswordHasherOptionsAccessor.cs | 9 +- test/Shared/PriorityOrderer.cs | 108 +- test/Shared/TestLogger.cs | 53 +- test/Shared/TestRole.cs | 111 +- test/Shared/TestRoleClaim.cs | 50 +- test/Shared/TestUser.cs | 180 +- test/Shared/TestUserClaim.cs | 50 +- test/Shared/TestUserLogin.cs | 50 +- test/Shared/TestUserRole.cs | 34 +- test/Shared/TestUserToken.cs | 50 +- test/Shared/UserManagerTestBase.cs | 3790 ++++++++--------- 102 files changed, 6515 insertions(+), 6749 deletions(-) diff --git a/NuGet.config b/NuGet.config index fe4af3374..1db8e2134 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,8 +1,9 @@ - + + - - - + + + - + \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 9e6615786..944147f3d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,6 @@ init: - git config --global core.autocrlf true - - ps: [Environment]::SetEnvironmentVariable("Test:SqlServer:DefaultConnectionString", "Server=(local)\SQL2012SP1;Database=master;Integrated Security=true", "Machine") - - ps: [Environment]::SetEnvironmentVariable("Test:SqlServer:DefaultConnectionString", "Server=(local)\SQL2012SP1;Database=master;Integrated Security=true") + - ps: $env:TestSqlServerDefaultConnectionString = "Server=(local)\SQL2012SP1;Database=master;Integrated Security=true" cache: - packages -> **\packages.config diff --git a/samples/IdentitySample.Mvc/Controllers/AccountController.cs b/samples/IdentitySample.Mvc/Controllers/AccountController.cs index 036806e21..90d6a52bb 100644 --- a/samples/IdentitySample.Mvc/Controllers/AccountController.cs +++ b/samples/IdentitySample.Mvc/Controllers/AccountController.cs @@ -1,475 +1,418 @@ -using System; -using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; +using IdentitySample.Models; +using IdentitySample.Models.AccountViewModels; +using IdentitySample.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.Extensions.Logging; -using IdentitySample.Models; -using IdentitySample.Models.AccountViewModels; -using IdentitySample.Services; namespace IdentitySample.Controllers { - [Authorize] - public class AccountController : Controller - { - private readonly UserManager _userManager; - private readonly SignInManager _signInManager; - private readonly IEmailSender _emailSender; - private readonly ISmsSender _smsSender; - private readonly ILogger _logger; - - public AccountController( - UserManager userManager, - SignInManager signInManager, - IEmailSender emailSender, - ISmsSender smsSender, - ILoggerFactory loggerFactory) - { - _userManager = userManager; - _signInManager = signInManager; - _emailSender = emailSender; - _smsSender = smsSender; - _logger = loggerFactory.CreateLogger(); - } - - // - // GET: /Account/Login - [HttpGet] - [AllowAnonymous] - public IActionResult Login(string returnUrl = null) - { - ViewData["ReturnUrl"] = returnUrl; - return View(); - } - - // - // POST: /Account/Login - [HttpPost] - [AllowAnonymous] - [ValidateAntiForgeryToken] - public async Task Login(LoginViewModel model, string returnUrl = null) - { - ViewData["ReturnUrl"] = returnUrl; - if (ModelState.IsValid) - { - // This doesn't count login failures towards account lockout - // To enable password failures to trigger account lockout, set lockoutOnFailure: true - var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false); - if (result.Succeeded) - { - _logger.LogInformation(1, "User logged in."); - return RedirectToLocal(returnUrl); - } - if (result.RequiresTwoFactor) - { - return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe }); - } - if (result.IsLockedOut) - { - _logger.LogWarning(2, "User account locked out."); - return View("Lockout"); - } - else - { - ModelState.AddModelError(string.Empty, "Invalid login attempt."); - return View(model); - } - } - - // If we got this far, something failed, redisplay form - return View(model); - } - - // - // GET: /Account/Register - [HttpGet] - [AllowAnonymous] - public IActionResult Register(string returnUrl = null) - { - ViewData["ReturnUrl"] = returnUrl; - return View(); - } - - // - // POST: /Account/Register - [HttpPost] - [AllowAnonymous] - [ValidateAntiForgeryToken] - public async Task Register(RegisterViewModel model, string returnUrl = null) - { - ViewData["ReturnUrl"] = returnUrl; - if (ModelState.IsValid) - { - var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; - var result = await _userManager.CreateAsync(user, model.Password); - if (result.Succeeded) - { - // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713 - // Send an email with this link - //var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); - //var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme); - //await _emailSender.SendEmailAsync(model.Email, "Confirm your account", - // "Please confirm your account by clicking this link: link"); - await _signInManager.SignInAsync(user, isPersistent: false); - _logger.LogInformation(3, "User created a new account with password."); - return RedirectToLocal(returnUrl); - } - AddErrors(result); - } - - // If we got this far, something failed, redisplay form - return View(model); - } - - // - // POST: /Account/LogOff - [HttpPost] - [ValidateAntiForgeryToken] - public async Task LogOff() - { - await _signInManager.SignOutAsync(); - _logger.LogInformation(4, "User logged out."); - return RedirectToAction(nameof(HomeController.Index), "Home"); - } - - // - // POST: /Account/ExternalLogin - [HttpPost] - [AllowAnonymous] - [ValidateAntiForgeryToken] - public IActionResult ExternalLogin(string provider, string returnUrl = null) - { - // Request a redirect to the external login provider. - var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }); - var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl); - return Challenge(properties, provider); - } - - // - // GET: /Account/ExternalLoginCallback - [HttpGet] - [AllowAnonymous] - public async Task ExternalLoginCallback(string returnUrl = null, string remoteError = null) - { - if (remoteError != null) - { - ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}"); - return View(nameof(Login)); - } - var info = await _signInManager.GetExternalLoginInfoAsync(); - if (info == null) - { - return RedirectToAction(nameof(Login)); - } - - // Sign in the user with this external login provider if the user already has a login. - var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false); - if (result.Succeeded) - { - // Update any authentication tokens if login succeeded - await _signInManager.UpdateExternalAuthenticationTokensAsync(info); - - _logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider); - return RedirectToLocal(returnUrl); - } - if (result.RequiresTwoFactor) - { - return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl }); - } - if (result.IsLockedOut) - { - return View("Lockout"); - } - else - { - // If the user does not have an account, then ask the user to create an account. - ViewData["ReturnUrl"] = returnUrl; - ViewData["LoginProvider"] = info.LoginProvider; - var email = info.Principal.FindFirstValue(ClaimTypes.Email); - return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email }); - } - } - - // - // POST: /Account/ExternalLoginConfirmation - [HttpPost] - [AllowAnonymous] - [ValidateAntiForgeryToken] - public async Task ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl = null) - { - if (ModelState.IsValid) - { - // Get the information about the user from the external login provider - var info = await _signInManager.GetExternalLoginInfoAsync(); - if (info == null) - { - return View("ExternalLoginFailure"); - } - var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; - var result = await _userManager.CreateAsync(user); - if (result.Succeeded) - { - result = await _userManager.AddLoginAsync(user, info); - if (result.Succeeded) - { - await _signInManager.SignInAsync(user, isPersistent: false); - _logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider); - - // Update any authentication tokens as well - await _signInManager.UpdateExternalAuthenticationTokensAsync(info); - - return RedirectToLocal(returnUrl); - } - } - AddErrors(result); - } - - ViewData["ReturnUrl"] = returnUrl; - return View(model); - } - - // GET: /Account/ConfirmEmail - [HttpGet] - [AllowAnonymous] - public async Task ConfirmEmail(string userId, string code) - { - if (userId == null || code == null) - { - return View("Error"); - } - var user = await _userManager.FindByIdAsync(userId); - if (user == null) - { - return View("Error"); - } - var result = await _userManager.ConfirmEmailAsync(user, code); - return View(result.Succeeded ? "ConfirmEmail" : "Error"); - } - - // - // GET: /Account/ForgotPassword - [HttpGet] - [AllowAnonymous] - public IActionResult ForgotPassword() - { - return View(); - } - - // - // POST: /Account/ForgotPassword - [HttpPost] - [AllowAnonymous] - [ValidateAntiForgeryToken] - public async Task ForgotPassword(ForgotPasswordViewModel model) - { - if (ModelState.IsValid) - { - var user = await _userManager.FindByNameAsync(model.Email); - if (user == null || !(await _userManager.IsEmailConfirmedAsync(user))) - { - // Don't reveal that the user does not exist or is not confirmed - return View("ForgotPasswordConfirmation"); - } - - // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713 - // Send an email with this link - //var code = await _userManager.GeneratePasswordResetTokenAsync(user); - //var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme); - //await _emailSender.SendEmailAsync(model.Email, "Reset Password", - // "Please reset your password by clicking here: link"); - //return View("ForgotPasswordConfirmation"); - } - - // If we got this far, something failed, redisplay form - return View(model); - } - - // - // GET: /Account/ForgotPasswordConfirmation - [HttpGet] - [AllowAnonymous] - public IActionResult ForgotPasswordConfirmation() - { - return View(); - } - - // - // GET: /Account/ResetPassword - [HttpGet] - [AllowAnonymous] - public IActionResult ResetPassword(string code = null) - { - return code == null ? View("Error") : View(); - } - - // - // POST: /Account/ResetPassword - [HttpPost] - [AllowAnonymous] - [ValidateAntiForgeryToken] - public async Task ResetPassword(ResetPasswordViewModel model) - { - if (!ModelState.IsValid) - { - return View(model); - } - var user = await _userManager.FindByNameAsync(model.Email); - if (user == null) - { - // Don't reveal that the user does not exist - return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account"); - } - var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password); - if (result.Succeeded) - { - return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account"); - } - AddErrors(result); - return View(); - } - - // - // GET: /Account/ResetPasswordConfirmation - [HttpGet] - [AllowAnonymous] - public IActionResult ResetPasswordConfirmation() - { - return View(); - } - - // - // GET: /Account/SendCode - [HttpGet] - [AllowAnonymous] - public async Task SendCode(string returnUrl = null, bool rememberMe = false) - { - var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); - if (user == null) - { - return View("Error"); - } - var userFactors = await _userManager.GetValidTwoFactorProvidersAsync(user); - var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList(); - return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe }); - } - - // - // POST: /Account/SendCode - [HttpPost] - [AllowAnonymous] - [ValidateAntiForgeryToken] - public async Task SendCode(SendCodeViewModel model) - { - if (!ModelState.IsValid) - { - return View(); - } - - var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); - if (user == null) - { - return View("Error"); - } - - // Generate the token and send it - var code = await _userManager.GenerateTwoFactorTokenAsync(user, model.SelectedProvider); - if (string.IsNullOrWhiteSpace(code)) - { - return View("Error"); - } - - var message = "Your security code is: " + code; - if (model.SelectedProvider == "Email") - { - await _emailSender.SendEmailAsync(await _userManager.GetEmailAsync(user), "Security Code", message); - } - else if (model.SelectedProvider == "Phone") - { - await _smsSender.SendSmsAsync(await _userManager.GetPhoneNumberAsync(user), message); - } - - return RedirectToAction(nameof(VerifyCode), new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe }); - } - - // - // GET: /Account/VerifyCode - [HttpGet] - [AllowAnonymous] - public async Task VerifyCode(string provider, bool rememberMe, string returnUrl = null) - { - // Require that the user has already logged in via username/password or external login - var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); - if (user == null) - { - return View("Error"); - } - return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe }); - } - - // - // POST: /Account/VerifyCode - [HttpPost] - [AllowAnonymous] - [ValidateAntiForgeryToken] - public async Task VerifyCode(VerifyCodeViewModel model) - { - if (!ModelState.IsValid) - { - return View(model); - } - - // The following code protects for brute force attacks against the two factor codes. - // If a user enters incorrect codes for a specified amount of time then the user account - // will be locked out for a specified amount of time. - var result = await _signInManager.TwoFactorSignInAsync(model.Provider, model.Code, model.RememberMe, model.RememberBrowser); - if (result.Succeeded) - { - return RedirectToLocal(model.ReturnUrl); - } - if (result.IsLockedOut) - { - _logger.LogWarning(7, "User account locked out."); - return View("Lockout"); - } - else - { - ModelState.AddModelError(string.Empty, "Invalid code."); - return View(model); - } - } - - #region Helpers - - private void AddErrors(IdentityResult result) - { - foreach (var error in result.Errors) - { - ModelState.AddModelError(string.Empty, error.Description); - } - } - - private Task GetCurrentUserAsync() - { - return _userManager.GetUserAsync(HttpContext.User); - } - - private IActionResult RedirectToLocal(string returnUrl) - { - if (Url.IsLocalUrl(returnUrl)) - { - return Redirect(returnUrl); - } - else - { - return RedirectToAction(nameof(HomeController.Index), "Home"); - } - } - - #endregion - } -} + [Authorize] + public class AccountController : Controller + { + private readonly IEmailSender _emailSender; + private readonly ILogger _logger; + private readonly SignInManager _signInManager; + private readonly ISmsSender _smsSender; + private readonly UserManager _userManager; + + public AccountController( + UserManager userManager, + SignInManager signInManager, + IEmailSender emailSender, + ISmsSender smsSender, + ILoggerFactory loggerFactory) + { + _userManager = userManager; + _signInManager = signInManager; + _emailSender = emailSender; + _smsSender = smsSender; + _logger = loggerFactory.CreateLogger(); + } + + // + // GET: /Account/Login + [HttpGet] + [AllowAnonymous] + public IActionResult Login(string returnUrl = null) + { + ViewData["ReturnUrl"] = returnUrl; + return View(); + } + + // + // POST: /Account/Login + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task Login(LoginViewModel model, string returnUrl = null) + { + ViewData["ReturnUrl"] = returnUrl; + if (ModelState.IsValid) + { + // This doesn't count login failures towards account lockout + // To enable password failures to trigger account lockout, set lockoutOnFailure: true + var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, false); + if (result.Succeeded) + { + _logger.LogInformation(1, "User logged in."); + return RedirectToLocal(returnUrl); + } + if (result.RequiresTwoFactor) + return RedirectToAction(nameof(SendCode), new {ReturnUrl = returnUrl, model.RememberMe}); + if (result.IsLockedOut) + { + _logger.LogWarning(2, "User account locked out."); + return View("Lockout"); + } + ModelState.AddModelError(string.Empty, "Invalid login attempt."); + return View(model); + } + + // If we got this far, something failed, redisplay form + return View(model); + } + + // + // GET: /Account/Register + [HttpGet] + [AllowAnonymous] + public IActionResult Register(string returnUrl = null) + { + ViewData["ReturnUrl"] = returnUrl; + return View(); + } + + // + // POST: /Account/Register + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task Register(RegisterViewModel model, string returnUrl = null) + { + ViewData["ReturnUrl"] = returnUrl; + if (ModelState.IsValid) + { + var user = new ApplicationUser {UserName = model.Email, Email = model.Email}; + var result = await _userManager.CreateAsync(user, model.Password); + if (result.Succeeded) + { + // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713 + // Send an email with this link + //var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); + //var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme); + //await _emailSender.SendEmailAsync(model.Email, "Confirm your account", + // "Please confirm your account by clicking this link: link"); + await _signInManager.SignInAsync(user, false); + _logger.LogInformation(3, "User created a new account with password."); + return RedirectToLocal(returnUrl); + } + AddErrors(result); + } + + // If we got this far, something failed, redisplay form + return View(model); + } + + // + // POST: /Account/LogOff + [HttpPost] + [ValidateAntiForgeryToken] + public async Task LogOff() + { + await _signInManager.SignOutAsync(); + _logger.LogInformation(4, "User logged out."); + return RedirectToAction(nameof(HomeController.Index), "Home"); + } + + // + // POST: /Account/ExternalLogin + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public IActionResult ExternalLogin(string provider, string returnUrl = null) + { + // Request a redirect to the external login provider. + var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new {ReturnUrl = returnUrl}); + var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl); + return Challenge(properties, provider); + } + + // + // GET: /Account/ExternalLoginCallback + [HttpGet] + [AllowAnonymous] + public async Task ExternalLoginCallback(string returnUrl = null, string remoteError = null) + { + if (remoteError != null) + { + ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}"); + return View(nameof(Login)); + } + var info = await _signInManager.GetExternalLoginInfoAsync(); + if (info == null) + return RedirectToAction(nameof(Login)); + + // Sign in the user with this external login provider if the user already has a login. + var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, false); + if (result.Succeeded) + { + // Update any authentication tokens if login succeeded + await _signInManager.UpdateExternalAuthenticationTokensAsync(info); + + _logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider); + return RedirectToLocal(returnUrl); + } + if (result.RequiresTwoFactor) + return RedirectToAction(nameof(SendCode), new {ReturnUrl = returnUrl}); + if (result.IsLockedOut) + return View("Lockout"); + // If the user does not have an account, then ask the user to create an account. + ViewData["ReturnUrl"] = returnUrl; + ViewData["LoginProvider"] = info.LoginProvider; + var email = info.Principal.FindFirstValue(ClaimTypes.Email); + return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel {Email = email}); + } + + // + // POST: /Account/ExternalLoginConfirmation + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, + string returnUrl = null) + { + if (ModelState.IsValid) + { + // Get the information about the user from the external login provider + var info = await _signInManager.GetExternalLoginInfoAsync(); + if (info == null) + return View("ExternalLoginFailure"); + var user = new ApplicationUser {UserName = model.Email, Email = model.Email}; + var result = await _userManager.CreateAsync(user); + if (result.Succeeded) + { + result = await _userManager.AddLoginAsync(user, info); + if (result.Succeeded) + { + await _signInManager.SignInAsync(user, false); + _logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider); + + // Update any authentication tokens as well + await _signInManager.UpdateExternalAuthenticationTokensAsync(info); + + return RedirectToLocal(returnUrl); + } + } + AddErrors(result); + } + + ViewData["ReturnUrl"] = returnUrl; + return View(model); + } + + // GET: /Account/ConfirmEmail + [HttpGet] + [AllowAnonymous] + public async Task ConfirmEmail(string userId, string code) + { + if (userId == null || code == null) + return View("Error"); + var user = await _userManager.FindByIdAsync(userId); + if (user == null) + return View("Error"); + var result = await _userManager.ConfirmEmailAsync(user, code); + return View(result.Succeeded ? "ConfirmEmail" : "Error"); + } + + // + // GET: /Account/ForgotPassword + [HttpGet] + [AllowAnonymous] + public IActionResult ForgotPassword() + { + return View(); + } + + // + // POST: /Account/ForgotPassword + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task ForgotPassword(ForgotPasswordViewModel model) + { + if (ModelState.IsValid) + { + var user = await _userManager.FindByNameAsync(model.Email); + if (user == null || !await _userManager.IsEmailConfirmedAsync(user)) + return View("ForgotPasswordConfirmation"); + + // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713 + // Send an email with this link + //var code = await _userManager.GeneratePasswordResetTokenAsync(user); + //var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme); + //await _emailSender.SendEmailAsync(model.Email, "Reset Password", + // "Please reset your password by clicking here: link"); + //return View("ForgotPasswordConfirmation"); + } + + // If we got this far, something failed, redisplay form + return View(model); + } + + // + // GET: /Account/ForgotPasswordConfirmation + [HttpGet] + [AllowAnonymous] + public IActionResult ForgotPasswordConfirmation() + { + return View(); + } + + // + // GET: /Account/ResetPassword + [HttpGet] + [AllowAnonymous] + public IActionResult ResetPassword(string code = null) + { + return code == null ? View("Error") : View(); + } + + // + // POST: /Account/ResetPassword + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task ResetPassword(ResetPasswordViewModel model) + { + if (!ModelState.IsValid) + return View(model); + var user = await _userManager.FindByNameAsync(model.Email); + if (user == null) + return RedirectToAction(nameof(ResetPasswordConfirmation), "Account"); + var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password); + if (result.Succeeded) + return RedirectToAction(nameof(ResetPasswordConfirmation), "Account"); + AddErrors(result); + return View(); + } + + // + // GET: /Account/ResetPasswordConfirmation + [HttpGet] + [AllowAnonymous] + public IActionResult ResetPasswordConfirmation() + { + return View(); + } + + // + // GET: /Account/SendCode + [HttpGet] + [AllowAnonymous] + public async Task SendCode(string returnUrl = null, bool rememberMe = false) + { + var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); + if (user == null) + return View("Error"); + var userFactors = await _userManager.GetValidTwoFactorProvidersAsync(user); + var factorOptions = userFactors.Select(purpose => new SelectListItem {Text = purpose, Value = purpose}).ToList(); + return View(new SendCodeViewModel {Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe}); + } + + // + // POST: /Account/SendCode + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task SendCode(SendCodeViewModel model) + { + if (!ModelState.IsValid) + return View(); + + var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); + if (user == null) + return View("Error"); + + // Generate the token and send it + var code = await _userManager.GenerateTwoFactorTokenAsync(user, model.SelectedProvider); + if (string.IsNullOrWhiteSpace(code)) + return View("Error"); + + var message = "Your security code is: " + code; + if (model.SelectedProvider == "Email") + await _emailSender.SendEmailAsync(await _userManager.GetEmailAsync(user), "Security Code", message); + else if (model.SelectedProvider == "Phone") + await _smsSender.SendSmsAsync(await _userManager.GetPhoneNumberAsync(user), message); + + return RedirectToAction(nameof(VerifyCode), + new {Provider = model.SelectedProvider, model.ReturnUrl, model.RememberMe}); + } + + // + // GET: /Account/VerifyCode + [HttpGet] + [AllowAnonymous] + public async Task VerifyCode(string provider, bool rememberMe, string returnUrl = null) + { + // Require that the user has already logged in via username/password or external login + var user = await _signInManager.GetTwoFactorAuthenticationUserAsync(); + if (user == null) + return View("Error"); + return View(new VerifyCodeViewModel {Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe}); + } + + // + // POST: /Account/VerifyCode + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task VerifyCode(VerifyCodeViewModel model) + { + if (!ModelState.IsValid) + return View(model); + + // The following code protects for brute force attacks against the two factor codes. + // If a user enters incorrect codes for a specified amount of time then the user account + // will be locked out for a specified amount of time. + var result = await _signInManager.TwoFactorSignInAsync(model.Provider, model.Code, model.RememberMe, + model.RememberBrowser); + if (result.Succeeded) + return RedirectToLocal(model.ReturnUrl); + if (result.IsLockedOut) + { + _logger.LogWarning(7, "User account locked out."); + return View("Lockout"); + } + ModelState.AddModelError(string.Empty, "Invalid code."); + return View(model); + } + + #region Helpers + + private void AddErrors(IdentityResult result) + { + foreach (var error in result.Errors) + ModelState.AddModelError(string.Empty, error.Description); + } + + private Task GetCurrentUserAsync() + { + return _userManager.GetUserAsync(HttpContext.User); + } + + private IActionResult RedirectToLocal(string returnUrl) + { + if (Url.IsLocalUrl(returnUrl)) + return Redirect(returnUrl); + return RedirectToAction(nameof(HomeController.Index), "Home"); + } + + #endregion + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Controllers/HomeController.cs b/samples/IdentitySample.Mvc/Controllers/HomeController.cs index e9c45b37a..7ae5a3c2a 100644 --- a/samples/IdentitySample.Mvc/Controllers/HomeController.cs +++ b/samples/IdentitySample.Mvc/Controllers/HomeController.cs @@ -2,28 +2,28 @@ namespace IdentitySample.Controllers { - public class HomeController : Controller - { - [HttpGet] - public IActionResult Index() - { - return View(); - } + public class HomeController : Controller + { + [HttpGet] + public IActionResult Index() + { + return View(); + } - [HttpGet] - public IActionResult About() - { - ViewBag.Message = "Your app description page."; + [HttpGet] + public IActionResult About() + { + ViewBag.Message = "Your app description page."; - return View(); - } + return View(); + } - [HttpGet] - public IActionResult Contact() - { - ViewBag.Message = "Your contact page."; + [HttpGet] + public IActionResult Contact() + { + ViewBag.Message = "Your contact page."; - return View(); - } - } + return View(); + } + } } \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Controllers/ManageController.cs b/samples/IdentitySample.Mvc/Controllers/ManageController.cs index 3d3f5146c..3bfd59b88 100644 --- a/samples/IdentitySample.Mvc/Controllers/ManageController.cs +++ b/samples/IdentitySample.Mvc/Controllers/ManageController.cs @@ -1,349 +1,341 @@ -using System; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using System.Security.Claims; +using IdentitySample.Models; +using IdentitySample.Models.ManageViewModels; +using IdentitySample.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; -using IdentitySample.Models; -using IdentitySample.Models.ManageViewModels; -using IdentitySample.Services; namespace IdentitySamples.Controllers { + [Authorize] + public class ManageController : Controller + { + private readonly IEmailSender _emailSender; + private readonly ILogger _logger; + private readonly SignInManager _signInManager; + private readonly ISmsSender _smsSender; + private readonly UserManager _userManager; - [Authorize] - public class ManageController : Controller - { - private readonly UserManager _userManager; - private readonly SignInManager _signInManager; - private readonly IEmailSender _emailSender; - private readonly ISmsSender _smsSender; - private readonly ILogger _logger; - - public ManageController( - UserManager userManager, - SignInManager signInManager, - IEmailSender emailSender, - ISmsSender smsSender, - ILoggerFactory loggerFactory) - { - _userManager = userManager; - _signInManager = signInManager; - _emailSender = emailSender; - _smsSender = smsSender; - _logger = loggerFactory.CreateLogger(); - } + public ManageController( + UserManager userManager, + SignInManager signInManager, + IEmailSender emailSender, + ISmsSender smsSender, + ILoggerFactory loggerFactory) + { + _userManager = userManager; + _signInManager = signInManager; + _emailSender = emailSender; + _smsSender = smsSender; + _logger = loggerFactory.CreateLogger(); + } - // - // GET: /Manage/Index - [HttpGet] - public async Task Index(ManageMessageId? message = null) - { - ViewData["StatusMessage"] = - message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." - : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." - : message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set." - : message == ManageMessageId.Error ? "An error has occurred." - : message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added." - : message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed." - : ""; + // + // GET: /Manage/Index + [HttpGet] + public async Task Index(ManageMessageId? message = null) + { + ViewData["StatusMessage"] = + message == ManageMessageId.ChangePasswordSuccess + ? "Your password has been changed." + : message == ManageMessageId.SetPasswordSuccess + ? "Your password has been set." + : message == ManageMessageId.SetTwoFactorSuccess + ? "Your two-factor authentication provider has been set." + : message == ManageMessageId.Error + ? "An error has occurred." + : message == ManageMessageId.AddPhoneSuccess + ? "Your phone number was added." + : message == ManageMessageId.RemovePhoneSuccess + ? "Your phone number was removed." + : ""; - var user = await GetCurrentUserAsync(); - var model = new IndexViewModel - { - HasPassword = await _userManager.HasPasswordAsync(user), - PhoneNumber = await _userManager.GetPhoneNumberAsync(user), - TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user), - Logins = await _userManager.GetLoginsAsync(user), - BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user) - }; - return View(model); - } + var user = await GetCurrentUserAsync(); + var model = new IndexViewModel + { + HasPassword = await _userManager.HasPasswordAsync(user), + PhoneNumber = await _userManager.GetPhoneNumberAsync(user), + TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user), + Logins = await _userManager.GetLoginsAsync(user), + BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user) + }; + return View(model); + } - // - // POST: /Manage/RemoveLogin - [HttpPost] - [ValidateAntiForgeryToken] - public async Task RemoveLogin(RemoveLoginViewModel account) - { - ManageMessageId? message = ManageMessageId.Error; - var user = await GetCurrentUserAsync(); - if (user != null) - { - var result = await _userManager.RemoveLoginAsync(user, account.LoginProvider, account.ProviderKey); - if (result.Succeeded) - { - await _signInManager.SignInAsync(user, isPersistent: false); - message = ManageMessageId.RemoveLoginSuccess; - } - } - return RedirectToAction(nameof(ManageLogins), new { Message = message }); - } + // + // POST: /Manage/RemoveLogin + [HttpPost] + [ValidateAntiForgeryToken] + public async Task RemoveLogin(RemoveLoginViewModel account) + { + ManageMessageId? message = ManageMessageId.Error; + var user = await GetCurrentUserAsync(); + if (user != null) + { + var result = await _userManager.RemoveLoginAsync(user, account.LoginProvider, account.ProviderKey); + if (result.Succeeded) + { + await _signInManager.SignInAsync(user, false); + message = ManageMessageId.RemoveLoginSuccess; + } + } + return RedirectToAction(nameof(ManageLogins), new {Message = message}); + } - // - // GET: /Manage/AddPhoneNumber - public IActionResult AddPhoneNumber() - { - return View(); - } + // + // GET: /Manage/AddPhoneNumber + public IActionResult AddPhoneNumber() + { + return View(); + } - // - // POST: /Manage/AddPhoneNumber - [HttpPost] - [ValidateAntiForgeryToken] - public async Task AddPhoneNumber(AddPhoneNumberViewModel model) - { - if (!ModelState.IsValid) - { - return View(model); - } - // Generate the token and send it - var user = await GetCurrentUserAsync(); - var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber); - await _smsSender.SendSmsAsync(model.PhoneNumber, "Your security code is: " + code); - return RedirectToAction(nameof(VerifyPhoneNumber), new { PhoneNumber = model.PhoneNumber }); - } + // + // POST: /Manage/AddPhoneNumber + [HttpPost] + [ValidateAntiForgeryToken] + public async Task AddPhoneNumber(AddPhoneNumberViewModel model) + { + if (!ModelState.IsValid) + return View(model); + // Generate the token and send it + var user = await GetCurrentUserAsync(); + var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber); + await _smsSender.SendSmsAsync(model.PhoneNumber, "Your security code is: " + code); + return RedirectToAction(nameof(VerifyPhoneNumber), new {model.PhoneNumber}); + } - // - // POST: /Manage/EnableTwoFactorAuthentication - [HttpPost] - [ValidateAntiForgeryToken] - public async Task EnableTwoFactorAuthentication() - { - var user = await GetCurrentUserAsync(); - if (user != null) - { - await _userManager.SetTwoFactorEnabledAsync(user, true); - await _signInManager.SignInAsync(user, isPersistent: false); - _logger.LogInformation(1, "User enabled two-factor authentication."); - } - return RedirectToAction(nameof(Index), "Manage"); - } + // + // POST: /Manage/EnableTwoFactorAuthentication + [HttpPost] + [ValidateAntiForgeryToken] + public async Task EnableTwoFactorAuthentication() + { + var user = await GetCurrentUserAsync(); + if (user != null) + { + await _userManager.SetTwoFactorEnabledAsync(user, true); + await _signInManager.SignInAsync(user, false); + _logger.LogInformation(1, "User enabled two-factor authentication."); + } + return RedirectToAction(nameof(Index), "Manage"); + } - // - // POST: /Manage/DisableTwoFactorAuthentication - [HttpPost] - [ValidateAntiForgeryToken] - public async Task DisableTwoFactorAuthentication() - { - var user = await GetCurrentUserAsync(); - if (user != null) - { - await _userManager.SetTwoFactorEnabledAsync(user, false); - await _signInManager.SignInAsync(user, isPersistent: false); - _logger.LogInformation(2, "User disabled two-factor authentication."); - } - return RedirectToAction(nameof(Index), "Manage"); - } + // + // POST: /Manage/DisableTwoFactorAuthentication + [HttpPost] + [ValidateAntiForgeryToken] + public async Task DisableTwoFactorAuthentication() + { + var user = await GetCurrentUserAsync(); + if (user != null) + { + await _userManager.SetTwoFactorEnabledAsync(user, false); + await _signInManager.SignInAsync(user, false); + _logger.LogInformation(2, "User disabled two-factor authentication."); + } + return RedirectToAction(nameof(Index), "Manage"); + } - // - // GET: /Manage/VerifyPhoneNumber - [HttpGet] - public async Task VerifyPhoneNumber(string phoneNumber) - { - var code = await _userManager.GenerateChangePhoneNumberTokenAsync(await GetCurrentUserAsync(), phoneNumber); - // Send an SMS to verify the phone number - return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber }); - } + // + // GET: /Manage/VerifyPhoneNumber + [HttpGet] + public async Task VerifyPhoneNumber(string phoneNumber) + { + var code = await _userManager.GenerateChangePhoneNumberTokenAsync(await GetCurrentUserAsync(), phoneNumber); + // Send an SMS to verify the phone number + return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel {PhoneNumber = phoneNumber}); + } - // - // POST: /Manage/VerifyPhoneNumber - [HttpPost] - [ValidateAntiForgeryToken] - public async Task VerifyPhoneNumber(VerifyPhoneNumberViewModel model) - { - if (!ModelState.IsValid) - { - return View(model); - } - var user = await GetCurrentUserAsync(); - if (user != null) - { - var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code); - if (result.Succeeded) - { - await _signInManager.SignInAsync(user, isPersistent: false); - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.AddPhoneSuccess }); - } - } - // If we got this far, something failed, redisplay the form - ModelState.AddModelError(string.Empty, "Failed to verify phone number"); - return View(model); - } + // + // POST: /Manage/VerifyPhoneNumber + [HttpPost] + [ValidateAntiForgeryToken] + public async Task VerifyPhoneNumber(VerifyPhoneNumberViewModel model) + { + if (!ModelState.IsValid) + return View(model); + var user = await GetCurrentUserAsync(); + if (user != null) + { + var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code); + if (result.Succeeded) + { + await _signInManager.SignInAsync(user, false); + return RedirectToAction(nameof(Index), new {Message = ManageMessageId.AddPhoneSuccess}); + } + } + // If we got this far, something failed, redisplay the form + ModelState.AddModelError(string.Empty, "Failed to verify phone number"); + return View(model); + } - // - // GET: /Manage/RemovePhoneNumber - [HttpPost] - [ValidateAntiForgeryToken] - public async Task RemovePhoneNumber() - { - var user = await GetCurrentUserAsync(); - if (user != null) - { - var result = await _userManager.SetPhoneNumberAsync(user, null); - if (result.Succeeded) - { - await _signInManager.SignInAsync(user, isPersistent: false); - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.RemovePhoneSuccess }); - } - } - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); - } + // + // GET: /Manage/RemovePhoneNumber + [HttpPost] + [ValidateAntiForgeryToken] + public async Task RemovePhoneNumber() + { + var user = await GetCurrentUserAsync(); + if (user != null) + { + var result = await _userManager.SetPhoneNumberAsync(user, null); + if (result.Succeeded) + { + await _signInManager.SignInAsync(user, false); + return RedirectToAction(nameof(Index), new {Message = ManageMessageId.RemovePhoneSuccess}); + } + } + return RedirectToAction(nameof(Index), new {Message = ManageMessageId.Error}); + } - // - // GET: /Manage/ChangePassword - [HttpGet] - public IActionResult ChangePassword() - { - return View(); - } + // + // GET: /Manage/ChangePassword + [HttpGet] + public IActionResult ChangePassword() + { + return View(); + } - // - // POST: /Manage/ChangePassword - [HttpPost] - [ValidateAntiForgeryToken] - public async Task ChangePassword(ChangePasswordViewModel model) - { - if (!ModelState.IsValid) - { - return View(model); - } - var user = await GetCurrentUserAsync(); - if (user != null) - { - var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword); - if (result.Succeeded) - { - await _signInManager.SignInAsync(user, isPersistent: false); - _logger.LogInformation(3, "User changed their password successfully."); - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangePasswordSuccess }); - } - AddErrors(result); - return View(model); - } - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); - } + // + // POST: /Manage/ChangePassword + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ChangePassword(ChangePasswordViewModel model) + { + if (!ModelState.IsValid) + return View(model); + var user = await GetCurrentUserAsync(); + if (user != null) + { + var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword); + if (result.Succeeded) + { + await _signInManager.SignInAsync(user, false); + _logger.LogInformation(3, "User changed their password successfully."); + return RedirectToAction(nameof(Index), new {Message = ManageMessageId.ChangePasswordSuccess}); + } + AddErrors(result); + return View(model); + } + return RedirectToAction(nameof(Index), new {Message = ManageMessageId.Error}); + } - // - // GET: /Manage/SetPassword - [HttpGet] - public IActionResult SetPassword() - { - return View(); - } + // + // GET: /Manage/SetPassword + [HttpGet] + public IActionResult SetPassword() + { + return View(); + } - // - // POST: /Manage/SetPassword - [HttpPost] - [ValidateAntiForgeryToken] - public async Task SetPassword(SetPasswordViewModel model) - { - if (!ModelState.IsValid) - { - return View(model); - } + // + // POST: /Manage/SetPassword + [HttpPost] + [ValidateAntiForgeryToken] + public async Task SetPassword(SetPasswordViewModel model) + { + if (!ModelState.IsValid) + return View(model); - var user = await GetCurrentUserAsync(); - if (user != null) - { - var result = await _userManager.AddPasswordAsync(user, model.NewPassword); - if (result.Succeeded) - { - await _signInManager.SignInAsync(user, isPersistent: false); - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetPasswordSuccess }); - } - AddErrors(result); - return View(model); - } - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); - } + var user = await GetCurrentUserAsync(); + if (user != null) + { + var result = await _userManager.AddPasswordAsync(user, model.NewPassword); + if (result.Succeeded) + { + await _signInManager.SignInAsync(user, false); + return RedirectToAction(nameof(Index), new {Message = ManageMessageId.SetPasswordSuccess}); + } + AddErrors(result); + return View(model); + } + return RedirectToAction(nameof(Index), new {Message = ManageMessageId.Error}); + } - //GET: /Manage/ManageLogins - [HttpGet] - public async Task ManageLogins(ManageMessageId? message = null) - { - ViewData["StatusMessage"] = - message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." - : message == ManageMessageId.AddLoginSuccess ? "The external login was added." - : message == ManageMessageId.Error ? "An error has occurred." - : ""; - var user = await GetCurrentUserAsync(); - if (user == null) - { - return View("Error"); - } - var userLogins = await _userManager.GetLoginsAsync(user); - var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList(); - ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1; - return View(new ManageLoginsViewModel - { - CurrentLogins = userLogins, - OtherLogins = otherLogins - }); - } + //GET: /Manage/ManageLogins + [HttpGet] + public async Task ManageLogins(ManageMessageId? message = null) + { + ViewData["StatusMessage"] = + message == ManageMessageId.RemoveLoginSuccess + ? "The external login was removed." + : message == ManageMessageId.AddLoginSuccess + ? "The external login was added." + : message == ManageMessageId.Error + ? "An error has occurred." + : ""; + var user = await GetCurrentUserAsync(); + if (user == null) + return View("Error"); + var userLogins = await _userManager.GetLoginsAsync(user); + var otherLogins = _signInManager.GetExternalAuthenticationSchemes() + .Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)) + .ToList(); + ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1; + return View(new ManageLoginsViewModel + { + CurrentLogins = userLogins, + OtherLogins = otherLogins + }); + } - // - // POST: /Manage/LinkLogin - [HttpPost] - [ValidateAntiForgeryToken] - public IActionResult LinkLogin(string provider) - { - // Request a redirect to the external login provider to link a login for the current user - var redirectUrl = Url.Action("LinkLoginCallback", "Manage"); - var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User)); - return Challenge(properties, provider); - } + // + // POST: /Manage/LinkLogin + [HttpPost] + [ValidateAntiForgeryToken] + public IActionResult LinkLogin(string provider) + { + // Request a redirect to the external login provider to link a login for the current user + var redirectUrl = Url.Action("LinkLoginCallback", "Manage"); + var properties = + _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User)); + return Challenge(properties, provider); + } - // - // GET: /Manage/LinkLoginCallback - [HttpGet] - public async Task LinkLoginCallback() - { - var user = await GetCurrentUserAsync(); - if (user == null) - { - return View("Error"); - } - var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user)); - if (info == null) - { - return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error }); - } - var result = await _userManager.AddLoginAsync(user, info); - var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error; - return RedirectToAction(nameof(ManageLogins), new { Message = message }); - } + // + // GET: /Manage/LinkLoginCallback + [HttpGet] + public async Task LinkLoginCallback() + { + var user = await GetCurrentUserAsync(); + if (user == null) + return View("Error"); + var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user)); + if (info == null) + return RedirectToAction(nameof(ManageLogins), new {Message = ManageMessageId.Error}); + var result = await _userManager.AddLoginAsync(user, info); + var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error; + return RedirectToAction(nameof(ManageLogins), new {Message = message}); + } - #region Helpers + #region Helpers - private void AddErrors(IdentityResult result) - { - foreach (var error in result.Errors) - { - ModelState.AddModelError(string.Empty, error.Description); - } - } + private void AddErrors(IdentityResult result) + { + foreach (var error in result.Errors) + ModelState.AddModelError(string.Empty, error.Description); + } - public enum ManageMessageId - { - AddPhoneSuccess, - AddLoginSuccess, - ChangePasswordSuccess, - SetTwoFactorSuccess, - SetPasswordSuccess, - RemoveLoginSuccess, - RemovePhoneSuccess, - Error - } + public enum ManageMessageId + { + AddPhoneSuccess, + AddLoginSuccess, + ChangePasswordSuccess, + SetTwoFactorSuccess, + SetPasswordSuccess, + RemoveLoginSuccess, + RemovePhoneSuccess, + Error + } - private Task GetCurrentUserAsync() - { - return _userManager.GetUserAsync(HttpContext.User); - } + private Task GetCurrentUserAsync() + { + return _userManager.GetUserAsync(HttpContext.User); + } - #endregion - } -} + #endregion + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/MessageServices.cs b/samples/IdentitySample.Mvc/MessageServices.cs index 6860d99af..8110b05ef 100644 --- a/samples/IdentitySample.Mvc/MessageServices.cs +++ b/samples/IdentitySample.Mvc/MessageServices.cs @@ -2,19 +2,18 @@ namespace IdentitySamples { - public static class MessageServices - { - public static Task SendEmailAsync(string email, string subject, string message) - { - // Plug in your email service - return Task.FromResult(0); - } + public static class MessageServices + { + public static Task SendEmailAsync(string email, string subject, string message) + { + // Plug in your email service + return Task.FromResult(0); + } - public static Task SendSmsAsync(string number, string message) - { - // Plug in your sms service - return Task.FromResult(0); - } - - } + public static Task SendSmsAsync(string number, string message) + { + // Plug in your sms service + return Task.FromResult(0); + } + } } \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs b/samples/IdentitySample.Mvc/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs index da18df3ef..aabe12be7 100644 --- a/samples/IdentitySample.Mvc/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/AccountViewModels/ExternalLoginConfirmationViewModel.cs @@ -1,15 +1,11 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations; namespace IdentitySample.Models.AccountViewModels { - public class ExternalLoginConfirmationViewModel - { - [Required] - [EmailAddress] - public string Email { get; set; } - } -} + public class ExternalLoginConfirmationViewModel + { + [Required] + [EmailAddress] + public string Email { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/AccountViewModels/ForgotPasswordViewModel.cs b/samples/IdentitySample.Mvc/Models/AccountViewModels/ForgotPasswordViewModel.cs index 7685e0ec1..f4d5193d2 100644 --- a/samples/IdentitySample.Mvc/Models/AccountViewModels/ForgotPasswordViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/AccountViewModels/ForgotPasswordViewModel.cs @@ -1,15 +1,11 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations; namespace IdentitySample.Models.AccountViewModels { - public class ForgotPasswordViewModel - { - [Required] - [EmailAddress] - public string Email { get; set; } - } -} + public class ForgotPasswordViewModel + { + [Required] + [EmailAddress] + public string Email { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/AccountViewModels/LoginViewModel.cs b/samples/IdentitySample.Mvc/Models/AccountViewModels/LoginViewModel.cs index 7b269fb51..15959fd1e 100644 --- a/samples/IdentitySample.Mvc/Models/AccountViewModels/LoginViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/AccountViewModels/LoginViewModel.cs @@ -1,22 +1,18 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations; namespace IdentitySample.Models.AccountViewModels { - public class LoginViewModel - { - [Required] - [EmailAddress] - public string Email { get; set; } + public class LoginViewModel + { + [Required] + [EmailAddress] + public string Email { get; set; } - [Required] - [DataType(DataType.Password)] - public string Password { get; set; } + [Required] + [DataType(DataType.Password)] + public string Password { get; set; } - [Display(Name = "Remember me?")] - public bool RememberMe { get; set; } - } -} + [Display(Name = "Remember me?")] + public bool RememberMe { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/AccountViewModels/RegisterViewModel.cs b/samples/IdentitySample.Mvc/Models/AccountViewModels/RegisterViewModel.cs index 99bf5fa91..8497b75bc 100644 --- a/samples/IdentitySample.Mvc/Models/AccountViewModels/RegisterViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/AccountViewModels/RegisterViewModel.cs @@ -1,27 +1,23 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations; namespace IdentitySample.Models.AccountViewModels { - public class RegisterViewModel - { - [Required] - [EmailAddress] - [Display(Name = "Email")] - public string Email { get; set; } + public class RegisterViewModel + { + [Required] + [EmailAddress] + [Display(Name = "Email")] + public string Email { get; set; } - [Required] - [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] - [DataType(DataType.Password)] - [Display(Name = "Password")] - public string Password { get; set; } + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "Password")] + public string Password { get; set; } - [DataType(DataType.Password)] - [Display(Name = "Confirm password")] - [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] - public string ConfirmPassword { get; set; } - } -} + [DataType(DataType.Password)] + [Display(Name = "Confirm password")] + [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/AccountViewModels/ResetPasswordViewModel.cs b/samples/IdentitySample.Mvc/Models/AccountViewModels/ResetPasswordViewModel.cs index 89959c847..5be0a8109 100644 --- a/samples/IdentitySample.Mvc/Models/AccountViewModels/ResetPasswordViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/AccountViewModels/ResetPasswordViewModel.cs @@ -1,27 +1,23 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations; namespace IdentitySample.Models.AccountViewModels { - public class ResetPasswordViewModel - { - [Required] - [EmailAddress] - public string Email { get; set; } + public class ResetPasswordViewModel + { + [Required] + [EmailAddress] + public string Email { get; set; } - [Required] - [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] - [DataType(DataType.Password)] - public string Password { get; set; } + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + public string Password { get; set; } - [DataType(DataType.Password)] - [Display(Name = "Confirm password")] - [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] - public string ConfirmPassword { get; set; } + [DataType(DataType.Password)] + [Display(Name = "Confirm password")] + [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } - public string Code { get; set; } - } -} + public string Code { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/AccountViewModels/SendCodeViewModel.cs b/samples/IdentitySample.Mvc/Models/AccountViewModels/SendCodeViewModel.cs index 7d8716745..65de762b3 100644 --- a/samples/IdentitySample.Mvc/Models/AccountViewModels/SendCodeViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/AccountViewModels/SendCodeViewModel.cs @@ -1,19 +1,16 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Rendering; namespace IdentitySample.Models.AccountViewModels { - public class SendCodeViewModel - { - public string SelectedProvider { get; set; } + public class SendCodeViewModel + { + public string SelectedProvider { get; set; } - public ICollection Providers { get; set; } + public ICollection Providers { get; set; } - public string ReturnUrl { get; set; } + public string ReturnUrl { get; set; } - public bool RememberMe { get; set; } - } -} + public bool RememberMe { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/AccountViewModels/VerifyCodeViewModel.cs b/samples/IdentitySample.Mvc/Models/AccountViewModels/VerifyCodeViewModel.cs index df6dce271..e78d84ab7 100644 --- a/samples/IdentitySample.Mvc/Models/AccountViewModels/VerifyCodeViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/AccountViewModels/VerifyCodeViewModel.cs @@ -1,25 +1,21 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations; namespace IdentitySample.Models.AccountViewModels { - public class VerifyCodeViewModel - { - [Required] - public string Provider { get; set; } + public class VerifyCodeViewModel + { + [Required] + public string Provider { get; set; } - [Required] - public string Code { get; set; } + [Required] + public string Code { get; set; } - public string ReturnUrl { get; set; } + public string ReturnUrl { get; set; } - [Display(Name = "Remember this browser?")] - public bool RememberBrowser { get; set; } + [Display(Name = "Remember this browser?")] + public bool RememberBrowser { get; set; } - [Display(Name = "Remember me?")] - public bool RememberMe { get; set; } - } -} + [Display(Name = "Remember me?")] + public bool RememberMe { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/ApplicationDbContext.cs b/samples/IdentitySample.Mvc/Models/ApplicationDbContext.cs index 55b0a62b0..e12ffd0ff 100644 --- a/samples/IdentitySample.Mvc/Models/ApplicationDbContext.cs +++ b/samples/IdentitySample.Mvc/Models/ApplicationDbContext.cs @@ -1,12 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using LinqToDB.Identity; namespace IdentitySample.Models { - public class ApplicationDataConnection : IdentityDataConnection - { - } -} + public class ApplicationDataConnection : IdentityDataConnection + { + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/ApplicationUser.cs b/samples/IdentitySample.Mvc/Models/ApplicationUser.cs index a4be7d067..30c5957e6 100644 --- a/samples/IdentitySample.Mvc/Models/ApplicationUser.cs +++ b/samples/IdentitySample.Mvc/Models/ApplicationUser.cs @@ -1,13 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using LinqToDB.Identity; namespace IdentitySample.Models { - // Add profile data for application users by adding properties to the ApplicationUser class - public class ApplicationUser : IdentityUser - { - } -} + // Add profile data for application users by adding properties to the ApplicationUser class + public class ApplicationUser : IdentityUser + { + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/ManageViewModels/AddPhoneNumberViewModel.cs b/samples/IdentitySample.Mvc/Models/ManageViewModels/AddPhoneNumberViewModel.cs index 28f0d3aaf..e679b60bb 100644 --- a/samples/IdentitySample.Mvc/Models/ManageViewModels/AddPhoneNumberViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/ManageViewModels/AddPhoneNumberViewModel.cs @@ -1,16 +1,12 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations; namespace IdentitySample.Models.ManageViewModels { - public class AddPhoneNumberViewModel - { - [Required] - [Phone] - [Display(Name = "Phone number")] - public string PhoneNumber { get; set; } - } -} + public class AddPhoneNumberViewModel + { + [Required] + [Phone] + [Display(Name = "Phone number")] + public string PhoneNumber { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/ManageViewModels/ChangePasswordViewModel.cs b/samples/IdentitySample.Mvc/Models/ManageViewModels/ChangePasswordViewModel.cs index c30745e58..aad52d470 100644 --- a/samples/IdentitySample.Mvc/Models/ManageViewModels/ChangePasswordViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/ManageViewModels/ChangePasswordViewModel.cs @@ -1,27 +1,23 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations; namespace IdentitySample.Models.ManageViewModels { - public class ChangePasswordViewModel - { - [Required] - [DataType(DataType.Password)] - [Display(Name = "Current password")] - public string OldPassword { get; set; } + public class ChangePasswordViewModel + { + [Required] + [DataType(DataType.Password)] + [Display(Name = "Current password")] + public string OldPassword { get; set; } - [Required] - [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] - [DataType(DataType.Password)] - [Display(Name = "New password")] - public string NewPassword { get; set; } + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "New password")] + public string NewPassword { get; set; } - [DataType(DataType.Password)] - [Display(Name = "Confirm new password")] - [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] - public string ConfirmPassword { get; set; } - } -} + [DataType(DataType.Password)] + [Display(Name = "Confirm new password")] + [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/ManageViewModels/ConfigureTwoFactorViewModel.cs b/samples/IdentitySample.Mvc/Models/ManageViewModels/ConfigureTwoFactorViewModel.cs index 76d371bfd..5f507e37a 100644 --- a/samples/IdentitySample.Mvc/Models/ManageViewModels/ConfigureTwoFactorViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/ManageViewModels/ConfigureTwoFactorViewModel.cs @@ -1,15 +1,12 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Rendering; namespace IdentitySample.Models.ManageViewModels { - public class ConfigureTwoFactorViewModel - { - public string SelectedProvider { get; set; } + public class ConfigureTwoFactorViewModel + { + public string SelectedProvider { get; set; } - public ICollection Providers { get; set; } - } -} + public ICollection Providers { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/ManageViewModels/FactorViewModel.cs b/samples/IdentitySample.Mvc/Models/ManageViewModels/FactorViewModel.cs index 88b968ae7..0569a21b9 100644 --- a/samples/IdentitySample.Mvc/Models/ManageViewModels/FactorViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/ManageViewModels/FactorViewModel.cs @@ -1,12 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace IdentitySample.Models.ManageViewModels +namespace IdentitySample.Models.ManageViewModels { - public class FactorViewModel - { - public string Purpose { get; set; } - } -} + public class FactorViewModel + { + public string Purpose { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/ManageViewModels/IndexViewModel.cs b/samples/IdentitySample.Mvc/Models/ManageViewModels/IndexViewModel.cs index 09ce077c8..6e615c70d 100644 --- a/samples/IdentitySample.Mvc/Models/ManageViewModels/IndexViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/ManageViewModels/IndexViewModel.cs @@ -1,21 +1,18 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; namespace IdentitySample.Models.ManageViewModels { - public class IndexViewModel - { - public bool HasPassword { get; set; } + public class IndexViewModel + { + public bool HasPassword { get; set; } - public IList Logins { get; set; } + public IList Logins { get; set; } - public string PhoneNumber { get; set; } + public string PhoneNumber { get; set; } - public bool TwoFactor { get; set; } + public bool TwoFactor { get; set; } - public bool BrowserRemembered { get; set; } - } -} + public bool BrowserRemembered { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/ManageViewModels/ManageLoginsViewModel.cs b/samples/IdentitySample.Mvc/Models/ManageViewModels/ManageLoginsViewModel.cs index 70948effa..bf1ffb623 100644 --- a/samples/IdentitySample.Mvc/Models/ManageViewModels/ManageLoginsViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/ManageViewModels/ManageLoginsViewModel.cs @@ -1,16 +1,13 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Authentication; using Microsoft.AspNetCore.Identity; namespace IdentitySample.Models.ManageViewModels { - public class ManageLoginsViewModel - { - public IList CurrentLogins { get; set; } + public class ManageLoginsViewModel + { + public IList CurrentLogins { get; set; } - public IList OtherLogins { get; set; } - } -} + public IList OtherLogins { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/ManageViewModels/RemoveLoginViewModel.cs b/samples/IdentitySample.Mvc/Models/ManageViewModels/RemoveLoginViewModel.cs index b46474e66..fe1e9ae1b 100644 --- a/samples/IdentitySample.Mvc/Models/ManageViewModels/RemoveLoginViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/ManageViewModels/RemoveLoginViewModel.cs @@ -1,14 +1,8 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; - -namespace IdentitySample.Models.ManageViewModels +namespace IdentitySample.Models.ManageViewModels { - public class RemoveLoginViewModel - { - public string LoginProvider { get; set; } - public string ProviderKey { get; set; } - } -} + public class RemoveLoginViewModel + { + public string LoginProvider { get; set; } + public string ProviderKey { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/ManageViewModels/SetPasswordViewModel.cs b/samples/IdentitySample.Mvc/Models/ManageViewModels/SetPasswordViewModel.cs index 2e5fc4369..253827c15 100644 --- a/samples/IdentitySample.Mvc/Models/ManageViewModels/SetPasswordViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/ManageViewModels/SetPasswordViewModel.cs @@ -1,22 +1,18 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations; namespace IdentitySample.Models.ManageViewModels { - public class SetPasswordViewModel - { - [Required] - [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] - [DataType(DataType.Password)] - [Display(Name = "New password")] - public string NewPassword { get; set; } + public class SetPasswordViewModel + { + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "New password")] + public string NewPassword { get; set; } - [DataType(DataType.Password)] - [Display(Name = "Confirm new password")] - [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] - public string ConfirmPassword { get; set; } - } -} + [DataType(DataType.Password)] + [Display(Name = "Confirm new password")] + [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Models/ManageViewModels/VerifyPhoneNumberViewModel.cs b/samples/IdentitySample.Mvc/Models/ManageViewModels/VerifyPhoneNumberViewModel.cs index fbe22f4c8..7e1c4d610 100644 --- a/samples/IdentitySample.Mvc/Models/ManageViewModels/VerifyPhoneNumberViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/ManageViewModels/VerifyPhoneNumberViewModel.cs @@ -1,19 +1,15 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations; namespace IdentitySample.Models.ManageViewModels { - public class VerifyPhoneNumberViewModel - { - [Required] - public string Code { get; set; } + public class VerifyPhoneNumberViewModel + { + [Required] + public string Code { get; set; } - [Required] - [Phone] - [Display(Name = "Phone number")] - public string PhoneNumber { get; set; } - } -} + [Required] + [Phone] + [Display(Name = "Phone number")] + public string PhoneNumber { get; set; } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Program.cs b/samples/IdentitySample.Mvc/Program.cs index b186e6812..b48f01d8c 100644 --- a/samples/IdentitySample.Mvc/Program.cs +++ b/samples/IdentitySample.Mvc/Program.cs @@ -4,21 +4,21 @@ namespace IdentitySample { - public static class Program - { - public static void Main(string[] args) - { - var config = new ConfigurationBuilder().AddEnvironmentVariables("ASPNETCORE_").Build(); + public static class Program + { + public static void Main(string[] args) + { + var config = new ConfigurationBuilder().AddEnvironmentVariables("ASPNETCORE_").Build(); - var host = new WebHostBuilder() - .UseKestrel() - .UseConfiguration(config) - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseStartup() - .Build(); + var host = new WebHostBuilder() + .UseKestrel() + .UseConfiguration(config) + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup() + .Build(); - host.Run(); - } - } + host.Run(); + } + } } \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Properties/launchSettings.json b/samples/IdentitySample.Mvc/Properties/launchSettings.json index 485fe8532..500d8b107 100644 --- a/samples/IdentitySample.Mvc/Properties/launchSettings.json +++ b/samples/IdentitySample.Mvc/Properties/launchSettings.json @@ -1,25 +1,25 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:28248/", - "sslPort": 0 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNET_ENVIRONMENT": "Development" - } - }, - "web": { - "commandName": "web", - "environmentVariables": { - "ASPNET_ENVIRONMENT": "Development" - } - } - } + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:28248/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNET_ENVIRONMENT": "Development" + } + }, + "web": { + "commandName": "web", + "environmentVariables": { + "ASPNET_ENVIRONMENT": "Development" + } + } + } } \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Services/IEmailSender.cs b/samples/IdentitySample.Mvc/Services/IEmailSender.cs index f8a5ef6d5..427ee59d0 100644 --- a/samples/IdentitySample.Mvc/Services/IEmailSender.cs +++ b/samples/IdentitySample.Mvc/Services/IEmailSender.cs @@ -1,12 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace IdentitySample.Services { - public interface IEmailSender - { - Task SendEmailAsync(string email, string subject, string message); - } -} + public interface IEmailSender + { + Task SendEmailAsync(string email, string subject, string message); + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Services/ISmsSender.cs b/samples/IdentitySample.Mvc/Services/ISmsSender.cs index 169b56bac..197bb886d 100644 --- a/samples/IdentitySample.Mvc/Services/ISmsSender.cs +++ b/samples/IdentitySample.Mvc/Services/ISmsSender.cs @@ -1,12 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace IdentitySample.Services { - public interface ISmsSender - { - Task SendSmsAsync(string number, string message); - } -} + public interface ISmsSender + { + Task SendSmsAsync(string number, string message); + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Services/MessageServices.cs b/samples/IdentitySample.Mvc/Services/MessageServices.cs index 469bb05c7..4c2ea1923 100644 --- a/samples/IdentitySample.Mvc/Services/MessageServices.cs +++ b/samples/IdentitySample.Mvc/Services/MessageServices.cs @@ -1,25 +1,22 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace IdentitySample.Services { - // This class is used by the application to send Email and SMS - // when you turn on two-factor authentication in ASP.NET Identity. - // For more details see this link http://go.microsoft.com/fwlink/?LinkID=532713 - public class AuthMessageSender : IEmailSender, ISmsSender - { - public Task SendEmailAsync(string email, string subject, string message) - { - // Plug in your email service here to send an email. - return Task.FromResult(0); - } + // This class is used by the application to send Email and SMS + // when you turn on two-factor authentication in ASP.NET Identity. + // For more details see this link http://go.microsoft.com/fwlink/?LinkID=532713 + public class AuthMessageSender : IEmailSender, ISmsSender + { + public Task SendEmailAsync(string email, string subject, string message) + { + // Plug in your email service here to send an email. + return Task.FromResult(0); + } - public Task SendSmsAsync(string number, string message) - { - // Plug in your SMS service here to send a text message. - return Task.FromResult(0); - } - } -} + public Task SendSmsAsync(string number, string message) + { + // Plug in your SMS service here to send a text message. + return Task.FromResult(0); + } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Startup.cs b/samples/IdentitySample.Mvc/Startup.cs index ca4af1de0..d54b6eaac 100644 --- a/samples/IdentitySample.Mvc/Startup.cs +++ b/samples/IdentitySample.Mvc/Startup.cs @@ -1,110 +1,98 @@ -using System; -using System.Collections.Generic; using System.Data.SqlClient; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; +using System.IO; using IdentitySample.Models; using IdentitySample.Services; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.DataProtection; -using System.IO; using LinqToDB; using LinqToDB.Data; using LinqToDB.DataProvider.SqlServer; using LinqToDB.Identity; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace IdentitySample { - public class Startup - { - public Startup(IHostingEnvironment env) - { - // Set up configuration sources. - var builder = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json") - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); - - if (env.IsDevelopment()) - { - // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 - builder.AddUserSecrets(); - } - - builder.AddEnvironmentVariables(); - Configuration = builder.Build(); - } - - public IConfigurationRoot Configuration { get; set; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - // Set connection configuration - DataConnection - .AddConfiguration( - "Default", - Configuration["Data:DefaultConnection:ConnectionString"], - new SqlServerDataProvider("Default", SqlServerVersion.v2012)); - - DataConnection.DefaultConfiguration = "Default"; - - services.AddIdentity(options => { - options.Cookies.ApplicationCookie.AuthenticationScheme = "ApplicationCookie"; - options.Cookies.ApplicationCookie.CookieName = "Interop"; - options.Cookies.ApplicationCookie.DataProtectionProvider = DataProtectionProvider.Create(new DirectoryInfo("C:\\Github\\Identity\\artifacts")); - }) - .AddLinqToDBStores(new DefaultConnectionFactory()) - .AddDefaultTokenProviders(); - - services.AddMvc(); - - // Add application services. - services.AddTransient(); - services.AddTransient(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) - { - loggerFactory.AddConsole(Configuration.GetSection("Logging")); - loggerFactory.AddDebug(); - - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - //app.UseDatabaseErrorPage(); - } - else - { - app.UseExceptionHandler("/Home/Error"); - } - - var connectionString = new SqlConnectionStringBuilder(Configuration["Data:DefaultConnection:ConnectionString"]) - { - InitialCatalog = "master" - }.ConnectionString; - - using (var db = new DataConnection(SqlServerTools.GetDataProvider(), connectionString)) - { - try - { - var sql = "create database [" + - new SqlConnectionStringBuilder(Configuration["Data:DefaultConnection:ConnectionString"]) - .InitialCatalog + "]"; - db.Execute(sql); - } - catch - { - // - } - - } + public class Startup + { + public Startup(IHostingEnvironment env) + { + // Set up configuration sources. + var builder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json") + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", true); + + if (env.IsDevelopment()) + builder.AddUserSecrets(); + + builder.AddEnvironmentVariables(); + Configuration = builder.Build(); + } + + public IConfigurationRoot Configuration { get; set; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + // Set connection configuration + DataConnection + .AddConfiguration( + "Default", + Configuration["Data:DefaultConnection:ConnectionString"], + new SqlServerDataProvider("Default", SqlServerVersion.v2012)); + + DataConnection.DefaultConfiguration = "Default"; + + services.AddIdentity(options => + { + options.Cookies.ApplicationCookie.AuthenticationScheme = "ApplicationCookie"; + options.Cookies.ApplicationCookie.CookieName = "Interop"; + options.Cookies.ApplicationCookie.DataProtectionProvider = + DataProtectionProvider.Create(new DirectoryInfo("C:\\Github\\Identity\\artifacts")); + }) + .AddLinqToDBStores(new DefaultConnectionFactory()) + .AddDefaultTokenProviders(); + + services.AddMvc(); + + // Add application services. + services.AddTransient(); + services.AddTransient(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + { + loggerFactory.AddConsole(Configuration.GetSection("Logging")); + loggerFactory.AddDebug(); + + if (env.IsDevelopment()) + app.UseDeveloperExceptionPage(); + else + app.UseExceptionHandler("/Home/Error"); + + var connectionString = new SqlConnectionStringBuilder(Configuration["Data:DefaultConnection:ConnectionString"]) + { + InitialCatalog = "master" + }.ConnectionString; + + using (var db = new DataConnection(SqlServerTools.GetDataProvider(), connectionString)) + { + try + { + var sql = "create database [" + + new SqlConnectionStringBuilder(Configuration["Data:DefaultConnection:ConnectionString"]) + .InitialCatalog + "]"; + db.Execute(sql); + } + catch + { + // + } + } // Try to create tables using (var db = new ApplicationDataConnection()) @@ -116,34 +104,32 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF TryCreateTable>(db); TryCreateTable>(db); TryCreateTable>(db); - } app.UseStaticFiles(); - app.UseIdentity(); - // To configure external authentication please see http://go.microsoft.com/fwlink/?LinkID=532715 - - app.UseMvc(routes => - { - routes.MapRoute( - name: "default", - template: "{controller=Home}/{action=Index}/{id?}"); - }); - } - - private void TryCreateTable(ApplicationDataConnection db) - where T : class - { - try - { - db.CreateTable(); - } - catch - { - // - } - } - } -} + app.UseIdentity(); + // To configure external authentication please see http://go.microsoft.com/fwlink/?LinkID=532715 + app.UseMvc(routes => + { + routes.MapRoute( + "default", + "{controller=Home}/{action=Index}/{id?}"); + }); + } + + private void TryCreateTable(ApplicationDataConnection db) + where T : class + { + try + { + db.CreateTable(); + } + catch + { + // + } + } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Account/ConfirmEmail.cshtml b/samples/IdentitySample.Mvc/Views/Account/ConfirmEmail.cshtml index 3244fef5f..6ea5b414c 100644 --- a/samples/IdentitySample.Mvc/Views/Account/ConfirmEmail.cshtml +++ b/samples/IdentitySample.Mvc/Views/Account/ConfirmEmail.cshtml @@ -1,10 +1,10 @@ @{ - ViewData["Title"] = "Confirm Email"; + ViewData["Title"] = "Confirm Email"; }

@ViewData["Title"].

-

- Thank you for confirming your email. Please Click here to Log in. -

-
+

+ Thank you for confirming your email. Please Click here to Log in. +

+ \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Account/ExternalLoginConfirmation.cshtml b/samples/IdentitySample.Mvc/Views/Account/ExternalLoginConfirmation.cshtml index fcd3b1869..45ce406a7 100644 --- a/samples/IdentitySample.Mvc/Views/Account/ExternalLoginConfirmation.cshtml +++ b/samples/IdentitySample.Mvc/Views/Account/ExternalLoginConfirmation.cshtml @@ -1,35 +1,35 @@ @model ExternalLoginConfirmationViewModel @{ - ViewData["Title"] = "Register"; + ViewData["Title"] = "Register"; }

@ViewData["Title"].

Associate your @ViewData["LoginProvider"] account.

-

Association Form

-
-
+

Association Form

+
+
-

- You've successfully authenticated with @ViewData["LoginProvider"]. - Please enter a user name for this site below and click the Register button to finish - logging in. -

-
- -
- - -
-
-
-
- -
-
+

+ You've successfully authenticated with @ViewData["LoginProvider"]. + Please enter a user name for this site below and click the Register button to finish + logging in. +

+
+ +
+ + +
+
+
+
+ +
+
@section Scripts { - @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } -} + @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Account/ExternalLoginFailure.cshtml b/samples/IdentitySample.Mvc/Views/Account/ExternalLoginFailure.cshtml index d89339e01..1c093a83b 100644 --- a/samples/IdentitySample.Mvc/Views/Account/ExternalLoginFailure.cshtml +++ b/samples/IdentitySample.Mvc/Views/Account/ExternalLoginFailure.cshtml @@ -1,8 +1,8 @@ @{ - ViewData["Title"] = "Login Failure"; + ViewData["Title"] = "Login Failure"; }
-

@ViewData["Title"].

-

Unsuccessful login with service.

-
+

@ViewData["Title"].

+

Unsuccessful login with service.

+ \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Account/ForgotPassword.cshtml b/samples/IdentitySample.Mvc/Views/Account/ForgotPassword.cshtml index 8400cc7e2..a1db8e91d 100644 --- a/samples/IdentitySample.Mvc/Views/Account/ForgotPassword.cshtml +++ b/samples/IdentitySample.Mvc/Views/Account/ForgotPassword.cshtml @@ -1,11 +1,11 @@ @model ForgotPasswordViewModel @{ - ViewData["Title"] = "Forgot your password?"; + ViewData["Title"] = "Forgot your password?"; }

@ViewData["Title"].

- For more information on how to enable reset password please see this article. + For more information on how to enable reset password please see this article.

@*
@@ -27,5 +27,5 @@
*@ @section Scripts { - @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } -} + @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Account/ForgotPasswordConfirmation.cshtml b/samples/IdentitySample.Mvc/Views/Account/ForgotPasswordConfirmation.cshtml index ab9bf44c8..e278df7ed 100644 --- a/samples/IdentitySample.Mvc/Views/Account/ForgotPasswordConfirmation.cshtml +++ b/samples/IdentitySample.Mvc/Views/Account/ForgotPasswordConfirmation.cshtml @@ -1,8 +1,8 @@ @{ - ViewData["Title"] = "Forgot Password Confirmation"; + ViewData["Title"] = "Forgot Password Confirmation"; }

@ViewData["Title"].

- Please check your email to reset your password. -

+ Please check your email to reset your password. +

\ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Account/Lockout.cshtml b/samples/IdentitySample.Mvc/Views/Account/Lockout.cshtml index 2cc946d5c..c5c90bb8a 100644 --- a/samples/IdentitySample.Mvc/Views/Account/Lockout.cshtml +++ b/samples/IdentitySample.Mvc/Views/Account/Lockout.cshtml @@ -1,8 +1,8 @@ @{ - ViewData["Title"] = "Locked out"; + ViewData["Title"] = "Locked out"; }
-

Locked out.

-

This account has been locked out, please try again later.

-
+

Locked out.

+

This account has been locked out, please try again later.

+ \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Account/Login.cshtml b/samples/IdentitySample.Mvc/Views/Account/Login.cshtml index e788eec18..679fac83b 100644 --- a/samples/IdentitySample.Mvc/Views/Account/Login.cshtml +++ b/samples/IdentitySample.Mvc/Views/Account/Login.cshtml @@ -1,92 +1,89 @@ -@using System.Collections.Generic -@using Microsoft.AspNetCore.Http -@using Microsoft.AspNetCore.Http.Authentication @model LoginViewModel @inject SignInManager SignInManager @{ - ViewData["Title"] = "Log in"; + ViewData["Title"] = "Log in"; }

@ViewData["Title"].

-
-
-
-

Use a local account to log in.

-
-
-
- -
- - -
-
-
- -
- - -
-
-
-
-
- -
-
-
-
-
- -
-
-

- Register as a new user? -

-

- Forgot your password? -

-
-
-
-
-
-

Use another service to log in.

-
- @{ - var loginProviders = SignInManager.GetExternalAuthenticationSchemes().ToList(); - if (loginProviders.Count == 0) - { -
-

- There are no external authentication services configured. See this article - for details on setting up this ASP.NET application to support logging in via external services. -

-
- } - else - { -
-
-

- @foreach (var provider in loginProviders) - { - - } -

-
-
- } - } -
-
+
+
+
+

Use a local account to log in.

+
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+ +
+
+
+
+
+ +
+
+

+ Register as a new user? +

+

+ Forgot your password? +

+
+
+
+
+
+

Use another service to log in.

+
+ @{ + var loginProviders = SignInManager.GetExternalAuthenticationSchemes().ToList(); + if (loginProviders.Count == 0) + { +
+

+ There are no external authentication services configured. See this article + for details on setting up this ASP.NET application to support logging in via external services. +

+
+ } + else + { +
+
+

+ @foreach (var provider in loginProviders) + { + + } +

+
+
+ } + } +
+
@section Scripts { - @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } -} + @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Account/Register.cshtml b/samples/IdentitySample.Mvc/Views/Account/Register.cshtml index 7d064f1b6..257c3f7af 100644 --- a/samples/IdentitySample.Mvc/Views/Account/Register.cshtml +++ b/samples/IdentitySample.Mvc/Views/Account/Register.cshtml @@ -1,42 +1,42 @@ @model RegisterViewModel @{ - ViewData["Title"] = "Register"; + ViewData["Title"] = "Register"; }

@ViewData["Title"].

-

Create a new account.

-
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
-
- -
-
+

Create a new account.

+
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+ +
+
@section Scripts { - @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } -} + @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Account/ResetPassword.cshtml b/samples/IdentitySample.Mvc/Views/Account/ResetPassword.cshtml index 8ab27b68e..f2a5c4b49 100644 --- a/samples/IdentitySample.Mvc/Views/Account/ResetPassword.cshtml +++ b/samples/IdentitySample.Mvc/Views/Account/ResetPassword.cshtml @@ -1,43 +1,43 @@ @model ResetPasswordViewModel @{ - ViewData["Title"] = "Reset password"; + ViewData["Title"] = "Reset password"; }

@ViewData["Title"].

-

Reset your password.

-
-
- -
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
-
- -
-
+

Reset your password.

+
+
+ +
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+ +
+
@section Scripts { - @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } -} + @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Account/ResetPasswordConfirmation.cshtml b/samples/IdentitySample.Mvc/Views/Account/ResetPasswordConfirmation.cshtml index bef2e4570..14f07ecde 100644 --- a/samples/IdentitySample.Mvc/Views/Account/ResetPasswordConfirmation.cshtml +++ b/samples/IdentitySample.Mvc/Views/Account/ResetPasswordConfirmation.cshtml @@ -1,8 +1,8 @@ @{ - ViewData["Title"] = "Reset password confirmation"; + ViewData["Title"] = "Reset password confirmation"; }

@ViewData["Title"].

- Your password has been reset. Please Click here to log in. -

+ Your password has been reset. Please Click here to log in. +

\ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Account/SendCode.cshtml b/samples/IdentitySample.Mvc/Views/Account/SendCode.cshtml index 0c8762998..2a6f4453f 100644 --- a/samples/IdentitySample.Mvc/Views/Account/SendCode.cshtml +++ b/samples/IdentitySample.Mvc/Views/Account/SendCode.cshtml @@ -1,21 +1,21 @@ @model SendCodeViewModel @{ - ViewData["Title"] = "Send Verification Code"; + ViewData["Title"] = "Send Verification Code"; }

@ViewData["Title"].

- -
-
- Select Two-Factor Authentication Provider: - - -
-
+ +
+
+ Select Two-Factor Authentication Provider: + + +
+
@section Scripts { - @{await Html.RenderPartialAsync("_ValidationScriptsPartial"); } -} + @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Account/VerifyCode.cshtml b/samples/IdentitySample.Mvc/Views/Account/VerifyCode.cshtml index 3689cbba4..95125ac76 100644 --- a/samples/IdentitySample.Mvc/Views/Account/VerifyCode.cshtml +++ b/samples/IdentitySample.Mvc/Views/Account/VerifyCode.cshtml @@ -1,38 +1,38 @@ @model VerifyCodeViewModel @{ - ViewData["Title"] = "Verify"; + ViewData["Title"] = "Verify"; }

@ViewData["Title"].

-
- - -

@ViewData["Status"]

-
-
- -
- - -
-
-
-
-
- - -
-
-
-
-
- -
-
+
+ + +

@ViewData["Status"]

+
+
+ +
+ + +
+
+
+
+
+ + +
+
+
+
+
+ +
+
@section Scripts { - @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } -} + @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Home/Index.cshtml b/samples/IdentitySample.Mvc/Views/Home/Index.cshtml index 59dc45d93..b07d5cd07 100644 --- a/samples/IdentitySample.Mvc/Views/Home/Index.cshtml +++ b/samples/IdentitySample.Mvc/Views/Home/Index.cshtml @@ -1,233 +1,235 @@ @{ - Layout = "/Views/Shared/_Layout.cshtml"; - ViewBag.Title = "Home Page"; + Layout = "/Views/Shared/_Layout.cshtml"; + ViewBag.Title = "Home Page"; }
-

ASP.NET Identity

-

ASP.NET Identity is the membership system for ASP.NET apps. Following are the features of ASP.NET Identity in this sample application.

-

Learn more »

+

ASP.NET Identity

+

ASP.NET Identity is the membership system for ASP.NET apps. Following are the features of ASP.NET Identity in this sample application.

+

+ Learn more » +

-
-
-
Initialize ASP.NET Identity
-
- You can initialize ASP.NET Identity when the application starts. Since ASP.NET Identity is Entity Framework based in this sample, - you can create DatabaseInitializer which is configured to get called each time the app starts. - Please look in App_Start\IdentityConfig.cs - This code shows the following -
    -
  • When should the Initializer run and when should the database be created
  • -
  • Create Admin user
  • -
  • Create Admin role
  • -
  • Add Admin user to Admin role
  • -
-
-
-
-
-
-
Add profile data for the user
-
- Please follow this tutorial. +
+
+
Initialize ASP.NET Identity
+
+ You can initialize ASP.NET Identity when the application starts. Since ASP.NET Identity is Entity Framework based in this sample, + you can create DatabaseInitializer which is configured to get called each time the app starts. + Please look in App_Start\IdentityConfig.cs + This code shows the following +
    +
  • When should the Initializer run and when should the database be created
  • +
  • Create Admin user
  • +
  • Create Admin role
  • +
  • Add Admin user to Admin role
  • +
+
+
+
+
+
+
Add profile data for the user
+
+ Please follow this tutorial. -
    -
  • Add profile information in the Users Table
  • -
  • Look in Models\IdentityModels.cs for examples
  • -
-
-
-
-
-
-
Validation
-
- When you create a User using a username or password, the Identity system performs validation on the username and password, and the passwords are hashed before they are - stored in the database. You can customize the validation by changing some of the properties of the validators such as Turn alphanumeric on/off, set minimum password length - or you can write your own custom validators and register them with the UserManager. -
-
-
-
-
-
Register a user and login
-
- Click @Html.ActionLink("Register", "Register", "Account") and see the code in AccountController.cs and Register Action. - Click @Html.ActionLink("Log in", "Login", "Account") and see the code in AccountController.cs and Login Action. -
-
-
-
-
-
Social Logins
-
- You can the support so that users can login using their Facebook, Google, Twitter, Microsoft Account and more. -
-
- -
-
-
-
-
-
Basic User Management
-
- Do Create, Update, List and Delete Users. - Assign a Role to a User. - Only Users In Role Admin can access this page. This uses the [Authorize(Roles = "Admin")] on the UserAdmin controller. -
-
-
-
-
-
Basic Role Management
-
- Do Create, Update, List and Delete Roles. - Only Users In Role Admin can access this page. This authorization is done by using the [Authorize(Roles = "Admin")] on the RolesAdmin controller. -
-
-
-
-
-
Account Confirmation
-
- When you register a new account, you will be sent an email confirmation. - You can use an email service such as SendGrid which integrates nicely with Windows Azure and requires no configuration or - set up an SMTP server to send email. - You can send email using the EmailService which is registered in App_Start\IdentityConfig.cs -
-
-
-
-
-
Two-Factor Authentication
-
- This sample shows how you can use Two-Factor authentication. This sample has a SMS and email service registered where you can send SMS or email for sending the security code. - You can add more two-factor authentication factors such as QR codes and plug them into ASP.NET Identity. -
    -
  • - You can use a SMS using Twilio or use any means of sending SMS. Please read for more details on using Twilio. - You can send SMS using the SmsService which is registered in App_Start\IdentityConfig.cs -
  • -
  • - You can use an email service such as SendGrid or - set up an SMTP server to send email. - You can send email using the EmailService which is registered in App_Start\IdentityConfig.cs -
  • +
      +
    • Add profile information in the Users Table
    • +
    • Look in Models\IdentityModels.cs for examples
    • +
    +
+
+
+
+
+
Validation
+
+ When you create a User using a username or password, the Identity system performs validation on the username and password, and the passwords are hashed before they are + stored in the database. You can customize the validation by changing some of the properties of the validators such as Turn alphanumeric on/off, set minimum password length + or you can write your own custom validators and register them with the UserManager. +
+
+
+
+
+
Register a user and login
+
+ Click @Html.ActionLink("Register", "Register", "Account") and see the code in AccountController.cs and Register Action. + Click @Html.ActionLink("Log in", "Login", "Account") and see the code in AccountController.cs and Login Action. +
+
+
+
+
+
Social Logins
+
+ You can the support so that users can login using their Facebook, Google, Twitter, Microsoft Account and more. +
+
+ +
+
+
+
+
+
Basic User Management
+
+ Do Create, Update, List and Delete Users. + Assign a Role to a User. + Only Users In Role Admin can access this page. This uses the [Authorize(Roles = "Admin")] on the UserAdmin controller. +
+
+
+
+
+
Basic Role Management
+
+ Do Create, Update, List and Delete Roles. + Only Users In Role Admin can access this page. This authorization is done by using the [Authorize(Roles = "Admin")] on the RolesAdmin controller. +
+
+
+
+
+
Account Confirmation
+
+ When you register a new account, you will be sent an email confirmation. + You can use an email service such as SendGrid which integrates nicely with Windows Azure and requires no configuration or + set up an SMTP server to send email. + You can send email using the EmailService which is registered in App_Start\IdentityConfig.cs +
+
+
+
+
+
Two-Factor Authentication
+
+ This sample shows how you can use Two-Factor authentication. This sample has a SMS and email service registered where you can send SMS or email for sending the security code. + You can add more two-factor authentication factors such as QR codes and plug them into ASP.NET Identity. +
    +
  • + You can use a SMS using Twilio or use any means of sending SMS. Please read for more details on using Twilio. + You can send SMS using the SmsService which is registered in App_Start\IdentityConfig.cs +
  • +
  • + You can use an email service such as SendGrid or + set up an SMTP server to send email. + You can send email using the EmailService which is registered in App_Start\IdentityConfig.cs +
  • -
  • - When you login, you can add a phone number by clicking the Manage page. -
  • -
  • - Once you add a phone number and have the Phone service hooked to send a SMS, you will get a code through SMS to confirm your phone number. -
  • -
  • - In the Manage page, you can turn on Two-Factor authentication. -
  • -
  • - When you logout and login, after you enter the username and password, you will get an option of how to get the security code to use for two-factor authentication. -
  • -
  • - You can copy the code from your SMS or email and enter in the form to login. -
  • -
  • - The sample also shows how to protect against Brute force attacks against two-factor codes. When you enter a code incorrectly for 5 times then you will be - lockedout for 5 min before you can enter a new code. These settings can be configured in App_Start\IdentityConfig.cs by setting DefaultAccountLockoutTimeSpan and MaxFailedAccessAttemptsBeforeLockout on the UserManager. -
  • -
  • - If the machine you are browsing this website is your own machine, you can choose to check the "Remember Me" option after you enter the code. - This option will remember you forever on this machine and will not ask you for the two-factor authentication, the next time when you login to the website. - You can change your "Remember Me" settings for two-factor authentication in the Manage page. -
  • -
-
-
-
-
-
-
Account Lockout
-
- Provide a way to Lockout out the user if the user enters their password or two-factor codes incorrectly. - The number of invalid attempts and the timespan for the users are locked out can be configured. - A developer can optionally turn off Account Lockout for certain user accounts should they need to. -
-
    -
  • Account LockOut settings can be configured in the UserManager in IdentityConfig.cs
  • -
-
-
-
-
-
Security Token provider
-
- Support a way to regenerate the Security Token for the user in cases when the User changes there password or any other security related information such as removing an associated login(such as Facebook, Google, Microsoft Account etc). - This is needed to ensure that any tokens generated with the old password are invalidated. In the sample project, if you change the users password then a new token is generated for the user and any previous tokens are invalidated. - This feature provides an extra layer of security to your application since when you change your password, you will be logged out from everywhere (all other browsers) where you have logged into this application. -
-
-
    -
  • The provider is registered when you add CookieAuthentication in StartupAuth to your application.
  • -
-
-
-
-
-
-
Password Reset
-
- Allows the user to reset their passwords if they have forgotten their password. In this sample users need to confirm their email before they can reset their passwords. -
-
-
-
-
-
Custom Storage providers
-
- You can extend ASP.NET Identity to write your own custom storage provider for storing the ASP.NET Identity system and user data - in a persistance system of your choice such as MondoDb, RavenDb, Azure Table Storage etc. -
-
- -
-
-
-
-
-
Documentation
-
- -
-
-
+
  • + When you login, you can add a phone number by clicking the Manage page. +
  • +
  • + Once you add a phone number and have the Phone service hooked to send a SMS, you will get a code through SMS to confirm your phone number. +
  • +
  • + In the Manage page, you can turn on Two-Factor authentication. +
  • +
  • + When you logout and login, after you enter the username and password, you will get an option of how to get the security code to use for two-factor authentication. +
  • +
  • + You can copy the code from your SMS or email and enter in the form to login. +
  • +
  • + The sample also shows how to protect against Brute force attacks against two-factor codes. When you enter a code incorrectly for 5 times then you will be + lockedout for 5 min before you can enter a new code. These settings can be configured in App_Start\IdentityConfig.cs by setting DefaultAccountLockoutTimeSpan and MaxFailedAccessAttemptsBeforeLockout on the UserManager. +
  • +
  • + If the machine you are browsing this website is your own machine, you can choose to check the "Remember Me" option after you enter the code. + This option will remember you forever on this machine and will not ask you for the two-factor authentication, the next time when you login to the website. + You can change your "Remember Me" settings for two-factor authentication in the Manage page. +
  • + +
    +
    +
    +
    +
    +
    Account Lockout
    +
    + Provide a way to Lockout out the user if the user enters their password or two-factor codes incorrectly. + The number of invalid attempts and the timespan for the users are locked out can be configured. + A developer can optionally turn off Account Lockout for certain user accounts should they need to. +
    +
      +
    • Account LockOut settings can be configured in the UserManager in IdentityConfig.cs
    • +
    +
    +
    +
    +
    +
    Security Token provider
    +
    + Support a way to regenerate the Security Token for the user in cases when the User changes there password or any other security related information such as removing an associated login(such as Facebook, Google, Microsoft Account etc). + This is needed to ensure that any tokens generated with the old password are invalidated. In the sample project, if you change the users password then a new token is generated for the user and any previous tokens are invalidated. + This feature provides an extra layer of security to your application since when you change your password, you will be logged out from everywhere (all other browsers) where you have logged into this application. +
    +
    +
      +
    • The provider is registered when you add CookieAuthentication in StartupAuth to your application.
    • +
    +
    +
    +
    +
    +
    +
    Password Reset
    +
    + Allows the user to reset their passwords if they have forgotten their password. In this sample users need to confirm their email before they can reset their passwords. +
    +
    +
    +
    +
    +
    Custom Storage providers
    +
    + You can extend ASP.NET Identity to write your own custom storage provider for storing the ASP.NET Identity system and user data + in a persistance system of your choice such as MondoDb, RavenDb, Azure Table Storage etc. +
    +
    + +
    +
    +
    +
    +
    +
    Documentation
    +
    + +
    +
    +
    \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Manage/AddPhoneNumber.cshtml b/samples/IdentitySample.Mvc/Views/Manage/AddPhoneNumber.cshtml index 1e09409ca..4782b5e7d 100644 --- a/samples/IdentitySample.Mvc/Views/Manage/AddPhoneNumber.cshtml +++ b/samples/IdentitySample.Mvc/Views/Manage/AddPhoneNumber.cshtml @@ -1,27 +1,27 @@ @model AddPhoneNumberViewModel @{ - ViewData["Title"] = "Add Phone Number"; + ViewData["Title"] = "Add Phone Number"; }

    @ViewData["Title"].

    -

    Add a phone number.

    -
    -
    -
    - -
    - - -
    -
    -
    -
    - -
    -
    +

    Add a phone number.

    +
    +
    +
    + +
    + + +
    +
    +
    +
    + +
    +
    @section Scripts { - @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } -} + @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Manage/ChangePassword.cshtml b/samples/IdentitySample.Mvc/Views/Manage/ChangePassword.cshtml index 6127082df..f903b5639 100644 --- a/samples/IdentitySample.Mvc/Views/Manage/ChangePassword.cshtml +++ b/samples/IdentitySample.Mvc/Views/Manage/ChangePassword.cshtml @@ -1,42 +1,42 @@ @model ChangePasswordViewModel @{ - ViewData["Title"] = "Change Password"; + ViewData["Title"] = "Change Password"; }

    @ViewData["Title"].

    -

    Change Password Form

    -
    -
    -
    - -
    - - -
    -
    -
    - -
    - - -
    -
    -
    - -
    - - -
    -
    -
    -
    - -
    -
    +

    Change Password Form

    +
    +
    +
    + +
    + + +
    +
    +
    + +
    + + +
    +
    +
    + +
    + + +
    +
    +
    +
    + +
    +
    @section Scripts { - @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } -} + @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Manage/Index.cshtml b/samples/IdentitySample.Mvc/Views/Manage/Index.cshtml index 79a2d97dd..8a4a84213 100644 --- a/samples/IdentitySample.Mvc/Views/Manage/Index.cshtml +++ b/samples/IdentitySample.Mvc/Views/Manage/Index.cshtml @@ -1,38 +1,38 @@ @model IndexViewModel @{ - ViewData["Title"] = "Manage your account"; + ViewData["Title"] = "Manage your account"; }

    @ViewData["Title"].

    @ViewData["StatusMessage"]

    -

    Change your account settings

    -
    -
    -
    Password:
    -
    - @if (Model.HasPassword) - { - [  Change  ] - } - else - { - [  Create  ] - } -
    -
    External Logins:
    -
    - @Model.Logins.Count [  Manage  ] -
    -
    Phone Number:
    -
    -

    - Phone Numbers can used as a second factor of verification in two-factor authentication. - See this article - for details on setting up this ASP.NET application to support two-factor authentication using SMS. -

    - @*@(Model.PhoneNumber ?? "None") +

    Change your account settings

    +
    +
    +
    Password:
    +
    + @if (Model.HasPassword) + { + [  Change  ] + } + else + { + [  Create  ] + } +
    +
    External Logins:
    +
    + @Model.Logins.Count [  Manage  ] +
    +
    Phone Number:
    +
    +

    + Phone Numbers can used as a second factor of verification in two-factor authentication. + See this article + for details on setting up this ASP.NET application to support two-factor authentication using SMS. +

    + @*@(Model.PhoneNumber ?? "None") @if (Model.PhoneNumber != null) {
    @@ -45,15 +45,15 @@ { [  Add  ] }*@ -
    +
    -
    Two-Factor Authentication:
    -
    -

    - There are no two-factor authentication providers configured. See this article - for setting up this application to support two-factor authentication. -

    - @*@if (Model.TwoFactor) +
    Two-Factor Authentication:
    +
    +

    + There are no two-factor authentication providers configured. See this article + for setting up this application to support two-factor authentication. +

    + @*@if (Model.TwoFactor) {
    Enabled [] @@ -65,6 +65,6 @@ [] Disabled
    }*@ -
    -
    + +
    \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Manage/ManageLogins.cshtml b/samples/IdentitySample.Mvc/Views/Manage/ManageLogins.cshtml index 1bfb1d8af..7f8a0e52d 100644 --- a/samples/IdentitySample.Mvc/Views/Manage/ManageLogins.cshtml +++ b/samples/IdentitySample.Mvc/Views/Manage/ManageLogins.cshtml @@ -1,7 +1,6 @@ @model ManageLoginsViewModel -@using Microsoft.AspNetCore.Http.Authentication @{ - ViewData["Title"] = "Manage your external logins"; + ViewData["Title"] = "Manage your external logins"; }

    @ViewData["Title"].

    @@ -9,46 +8,46 @@

    @ViewData["StatusMessage"]

    @if (Model.CurrentLogins.Count > 0) { -

    Registered Logins

    - - - @for (var index = 0; index < Model.CurrentLogins.Count; index++) - { - - - - - } - -
    @Model.CurrentLogins[index].LoginProvider - @if ((bool)ViewData["ShowRemoveButton"]) - { -
    -
    - - - -
    -
    - } - else - { - @:   - } -
    +

    Registered Logins

    + + + @for (var index = 0; index < Model.CurrentLogins.Count; index++) + { + + + + + } + +
    @Model.CurrentLogins[index].LoginProvider + @if ((bool) ViewData["ShowRemoveButton"]) + { +
    +
    + + + +
    +
    + } + else + { + @:   + } +
    } @if (Model.OtherLogins.Count > 0) { -

    Add another service to log in.

    -
    -
    -
    -

    - @foreach (var provider in Model.OtherLogins) - { - - } -

    -
    -
    -} +

    Add another service to log in.

    +
    +
    +
    +

    + @foreach (var provider in Model.OtherLogins) + { + + } +

    +
    +
    +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Manage/SetPassword.cshtml b/samples/IdentitySample.Mvc/Views/Manage/SetPassword.cshtml index d1a1b77a4..4a1dbe62d 100644 --- a/samples/IdentitySample.Mvc/Views/Manage/SetPassword.cshtml +++ b/samples/IdentitySample.Mvc/Views/Manage/SetPassword.cshtml @@ -1,38 +1,38 @@ @model SetPasswordViewModel @{ - ViewData["Title"] = "Set Password"; + ViewData["Title"] = "Set Password"; }

    - You do not have a local username/password for this site. Add a local - account so you can log in without an external login. + You do not have a local username/password for this site. Add a local + account so you can log in without an external login.

    -

    Set your password

    -
    -
    -
    - -
    - - -
    -
    -
    - -
    - - -
    -
    -
    -
    - -
    -
    +

    Set your password

    +
    +
    +
    + +
    + + +
    +
    +
    + +
    + + +
    +
    +
    +
    + +
    +
    @section Scripts { - @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } -} + @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Manage/VerifyPhoneNumber.cshtml b/samples/IdentitySample.Mvc/Views/Manage/VerifyPhoneNumber.cshtml index 17787816b..f93adb4c3 100644 --- a/samples/IdentitySample.Mvc/Views/Manage/VerifyPhoneNumber.cshtml +++ b/samples/IdentitySample.Mvc/Views/Manage/VerifyPhoneNumber.cshtml @@ -1,30 +1,30 @@ @model VerifyPhoneNumberViewModel @{ - ViewData["Title"] = "Verify Phone Number"; + ViewData["Title"] = "Verify Phone Number"; }

    @ViewData["Title"].

    - -

    Add a phone number.

    -
    @ViewData["Status"]
    -
    -
    -
    - -
    - - -
    -
    -
    -
    - -
    -
    + +

    Add a phone number.

    +
    @ViewData["Status"]
    +
    +
    +
    + +
    + + +
    +
    +
    +
    + +
    +
    @section Scripts { - @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } -} + @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Shared/_Layout.cshtml b/samples/IdentitySample.Mvc/Views/Shared/_Layout.cshtml index 912a38b7a..42a09564a 100644 --- a/samples/IdentitySample.Mvc/Views/Shared/_Layout.cshtml +++ b/samples/IdentitySample.Mvc/Views/Shared/_Layout.cshtml @@ -1,46 +1,52 @@  - - - - @ViewData["Title"] - Identity Sample - - - - - -
    - @RenderBody() -
    -
    -

    © $year$ - $safeprojectname$

    -
    -
    + + + + @ViewData["Title"] - Identity Sample + + + + + +
    + @RenderBody() +
    +
    +

    © $year$ - $safeprojectname$

    +
    +
    - - - + + + - @RenderSection("scripts", required: false) - - +@RenderSection("scripts", false) + + \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Shared/_LoginPartial.cshtml b/samples/IdentitySample.Mvc/Views/Shared/_LoginPartial.cshtml index 87d35e3ab..428f55ea5 100644 --- a/samples/IdentitySample.Mvc/Views/Shared/_LoginPartial.cshtml +++ b/samples/IdentitySample.Mvc/Views/Shared/_LoginPartial.cshtml @@ -1,26 +1,27 @@ -@using Microsoft.AspNetCore.Identity -@using IdentitySample.Models - @inject SignInManager SignInManager @inject UserManager UserManager @if (SignInManager.IsSignedIn(User)) { - + } else { - + } \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/Shared/_ValidationScriptsPartial.cshtml b/samples/IdentitySample.Mvc/Views/Shared/_ValidationScriptsPartial.cshtml index a6c30d4d8..e22c6751e 100644 --- a/samples/IdentitySample.Mvc/Views/Shared/_ValidationScriptsPartial.cshtml +++ b/samples/IdentitySample.Mvc/Views/Shared/_ValidationScriptsPartial.cshtml @@ -1,2 +1,2 @@ - - \ No newline at end of file + + \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/_ViewImports.cshtml b/samples/IdentitySample.Mvc/Views/_ViewImports.cshtml index fbba680c3..69b1d906b 100644 --- a/samples/IdentitySample.Mvc/Views/_ViewImports.cshtml +++ b/samples/IdentitySample.Mvc/Views/_ViewImports.cshtml @@ -3,4 +3,4 @@ @using IdentitySample.Models.AccountViewModels @using IdentitySample.Models.ManageViewModels @using Microsoft.AspNetCore.Identity -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/Views/_ViewStart.cshtml b/samples/IdentitySample.Mvc/Views/_ViewStart.cshtml index a5f10045d..817a91341 100644 --- a/samples/IdentitySample.Mvc/Views/_ViewStart.cshtml +++ b/samples/IdentitySample.Mvc/Views/_ViewStart.cshtml @@ -1,3 +1,3 @@ @{ - Layout = "_Layout"; -} + Layout = "_Layout"; +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/appsettings.json b/samples/IdentitySample.Mvc/appsettings.json index fb243cd65..3ec973003 100644 --- a/samples/IdentitySample.Mvc/appsettings.json +++ b/samples/IdentitySample.Mvc/appsettings.json @@ -1,15 +1,16 @@ { - "Data": { - "DefaultConnection": { - "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Interop-Shared;Trusted_Connection=True;MultipleActiveResultSets=true" - } - }, - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - } -} + "Data": { + "DefaultConnection": { + "ConnectionString": + "Server=(localdb)\\mssqllocaldb;Database=Interop-Shared;Trusted_Connection=True;MultipleActiveResultSets=true" + } + }, + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/web.Debug.config b/samples/IdentitySample.Mvc/web.Debug.config index 2e302f9f9..a1e51202a 100644 --- a/samples/IdentitySample.Mvc/web.Debug.config +++ b/samples/IdentitySample.Mvc/web.Debug.config @@ -1,9 +1,9 @@ - + - - - - + \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/web.Release.config b/samples/IdentitySample.Mvc/web.Release.config index c35844462..0625433c6 100644 --- a/samples/IdentitySample.Mvc/web.Release.config +++ b/samples/IdentitySample.Mvc/web.Release.config @@ -1,9 +1,9 @@ - + - - - - - + \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/web.config b/samples/IdentitySample.Mvc/web.config index f7ac67933..2f3a6dcec 100644 --- a/samples/IdentitySample.Mvc/web.config +++ b/samples/IdentitySample.Mvc/web.config @@ -1,9 +1,11 @@  + - - - - - - + + + + + + \ No newline at end of file diff --git a/samples/IdentitySample.Mvc/wwwroot/css/site.css b/samples/IdentitySample.Mvc/wwwroot/css/site.css index 1eaae3d04..3d031b9f4 100644 --- a/samples/IdentitySample.Mvc/wwwroot/css/site.css +++ b/samples/IdentitySample.Mvc/wwwroot/css/site.css @@ -1,34 +1,32 @@ body { - padding-top: 50px; - padding-bottom: 20px; + padding-bottom: 20px; + padding-top: 50px; } /* Wrapping element */ + /* Set some basic padding to keep content from hitting the edges */ + .body-content { - padding-left: 15px; - padding-right: 15px; + padding-left: 15px; + padding-right: 15px; } /* Set widths on the form inputs since otherwise they're 100% wide */ + input, select, -textarea { - max-width: 280px; -} +textarea { max-width: 280px; } /* Carousel */ -.carousel-caption { - z-index: 10 !important; -} - .carousel-caption p { - font-size: 20px; - line-height: 1.4; - } +.carousel-caption { z-index: 10 !important; } -@media (min-width: 768px) { - .carousel-caption { - z-index: 10 !important; - } +.carousel-caption p { + font-size: 20px; + line-height: 1.4; } + +@media (min-width: 768px) { + .carousel-caption { z-index: 10 !important; } +} \ No newline at end of file diff --git a/src/LinqToDB.Identity/DefaultConnectionFactory.cs b/src/LinqToDB.Identity/DefaultConnectionFactory.cs index 3e9385e55..a0e3e6184 100644 --- a/src/LinqToDB.Identity/DefaultConnectionFactory.cs +++ b/src/LinqToDB.Identity/DefaultConnectionFactory.cs @@ -17,7 +17,10 @@ public class DefaultConnectionFactory : IConnectionFactor /// /// /// - public TConnection GetConnection() => new TConnection(); + public TConnection GetConnection() + { + return new TConnection(); + } /// /// Creates with default parameters @@ -25,6 +28,9 @@ public class DefaultConnectionFactory : IConnectionFactor /// /// /// - public TContext GetContext() => new TContext(); + public TContext GetContext() + { + return new TContext(); + } } } \ No newline at end of file diff --git a/src/LinqToDB.Identity/Extensions.cs b/src/LinqToDB.Identity/Extensions.cs index affd5ac25..297937fd2 100644 --- a/src/LinqToDB.Identity/Extensions.cs +++ b/src/LinqToDB.Identity/Extensions.cs @@ -20,7 +20,9 @@ public static T TryInsertAndSetIdentity(this IDataContext db, T obj) ms.SetValue(obj, res, identity); } else + { db.Insert(obj); + } return obj; } @@ -39,7 +41,7 @@ public static int UpdateConcurrent(this IDataContext dc, T obj) var stamp = Guid.NewGuid().ToString(); var query = dc.GetTable() - .Where(_ => _.Id.Equals(obj.Id) && (_.ConcurrencyStamp == obj.ConcurrencyStamp)) + .Where(_ => _.Id.Equals(obj.Id) && _.ConcurrencyStamp == obj.ConcurrencyStamp) .Set(_ => _.ConcurrencyStamp, stamp); var ed = dc.MappingSchema.GetEntityDescriptor(typeof(T)); @@ -47,7 +49,7 @@ public static int UpdateConcurrent(this IDataContext dc, T obj) foreach ( var column in ed.Columns.Where( - _ => (_.MemberName != nameof(IConcurrency.ConcurrencyStamp)) && !_.IsPrimaryKey && !_.SkipOnUpdate)) + _ => _.MemberName != nameof(IConcurrency.ConcurrencyStamp) && !_.IsPrimaryKey && !_.SkipOnUpdate)) { var expr = Expression .Lambda>( diff --git a/src/LinqToDB.Identity/IdentityDataConnection.cs b/src/LinqToDB.Identity/IdentityDataConnection.cs index e50f2a2cc..3995d0d17 100644 --- a/src/LinqToDB.Identity/IdentityDataConnection.cs +++ b/src/LinqToDB.Identity/IdentityDataConnection.cs @@ -149,9 +149,9 @@ public IdentityDataConnection() /// The type of role objects. /// The type of the primary key for users and roles. public class IdentityDataConnection : - IdentityDataConnection - , IdentityUserRole, IdentityUserLogin, - IdentityRoleClaim, IdentityUserToken> + IdentityDataConnection + , IdentityUserRole, IdentityUserLogin, + IdentityRoleClaim, IdentityUserToken> where TUser : class, IIdentityUser where TRole : class, IIdentityRole where TKey : IEquatable @@ -229,7 +229,7 @@ public IdentityDataConnection() /// The type of the role claim object. /// The type of the user token object. public class IdentityDataConnection : - DataConnection + DataConnection where TUser : class, IIdentityUser where TRole : class, IIdentityRole where TKey : IEquatable diff --git a/src/LinqToDB.Identity/IdentityLinqToDbBuilderExtensions.cs b/src/LinqToDB.Identity/IdentityLinqToDbBuilderExtensions.cs index e9f637f7d..40b5c4021 100644 --- a/src/LinqToDB.Identity/IdentityLinqToDbBuilderExtensions.cs +++ b/src/LinqToDB.Identity/IdentityLinqToDbBuilderExtensions.cs @@ -41,7 +41,8 @@ public static IdentityBuilder AddLinqToDBStores(this Iden { builder.Services.AddSingleton(factory); - builder.Services.TryAdd(GetDefaultServices(builder.UserType, builder.RoleType, typeof(TContext), typeof(TConnection))); + builder.Services.TryAdd( + GetDefaultServices(builder.UserType, builder.RoleType, typeof(TContext), typeof(TConnection))); return builder; } diff --git a/src/LinqToDB.Identity/IdentityRole.cs b/src/LinqToDB.Identity/IdentityRole.cs index cf5147f03..74fd87f21 100644 --- a/src/LinqToDB.Identity/IdentityRole.cs +++ b/src/LinqToDB.Identity/IdentityRole.cs @@ -107,10 +107,7 @@ public IdentityRole(string roleName) : this() /// Navigation property for claims in this role. /// [Association(ThisKey = nameof(Id), OtherKey = nameof(IdentityRoleClaim.RoleId), Storage = nameof(_claims))] - public virtual ICollection Claims - { - get { return _claims; } - } + public virtual ICollection Claims => _claims; /// /// Gets or sets the primary key for this role. diff --git a/src/LinqToDB.Identity/IdentityUser.cs b/src/LinqToDB.Identity/IdentityUser.cs index edc6545d7..343a91f12 100644 --- a/src/LinqToDB.Identity/IdentityUser.cs +++ b/src/LinqToDB.Identity/IdentityUser.cs @@ -41,7 +41,7 @@ public IdentityUser(string userName) : this() /// /// The type used for the primary key for the user. public class IdentityUser : - IdentityUser, IdentityUserRole, IdentityUserLogin> + IdentityUser, IdentityUserRole, IdentityUserLogin> where TKey : IEquatable { } diff --git a/src/LinqToDB.Identity/RoleStore.cs b/src/LinqToDB.Identity/RoleStore.cs index 3b33f7698..cc017facd 100644 --- a/src/LinqToDB.Identity/RoleStore.cs +++ b/src/LinqToDB.Identity/RoleStore.cs @@ -10,7 +10,6 @@ using System.Threading.Tasks; using LinqToDB.Data; using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.Internal; namespace LinqToDB.Identity { @@ -58,9 +57,9 @@ public RoleStore(IConnectionFactory factory, IdentityErro /// /// public class RoleStore : - RoleStore, IdentityRoleClaim>, - IQueryableRoleStore, - IRoleClaimStore + RoleStore, IdentityRoleClaim>, + IQueryableRoleStore, + IRoleClaimStore where TRole : IdentityRole where TKey : IEquatable where TContext : IDataContext @@ -108,8 +107,8 @@ protected override IdentityRoleClaim CreateRoleClaim(TRole role, Claim cla /// /// public abstract class RoleStore : - IQueryableRoleStore, - IRoleClaimStore + IQueryableRoleStore, + IRoleClaimStore where TRole : class, IIdentityRole where TKey : IEquatable where TUserRole : class, IIdentityUserRole @@ -214,7 +213,7 @@ public virtual async Task DeleteAsync(TRole role, _factory .GetContext() .GetTable() - .Where(_ => _.Id.Equals(role.Id) && (_.ConcurrencyStamp == role.ConcurrencyStamp)) + .Where(_ => _.Id.Equals(role.Id) && _.ConcurrencyStamp == role.ConcurrencyStamp) .Delete(), cancellationToken); return result == 1 ? IdentityResult.Success : IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure()); @@ -431,7 +430,7 @@ public async Task RemoveClaimAsync(TRole role, Claim claim, await Task.Run(() => Context.GetTable() - .Where(rc => rc.RoleId.Equals(role.Id) && (rc.ClaimValue == claim.Value) && (rc.ClaimType == claim.Type)) + .Where(rc => rc.RoleId.Equals(role.Id) && rc.ClaimValue == claim.Value && rc.ClaimType == claim.Type) .Delete(), cancellationToken); } diff --git a/src/LinqToDB.Identity/TaskTools.cs b/src/LinqToDB.Identity/TaskTools.cs index 18153af9e..4fc2c765d 100644 --- a/src/LinqToDB.Identity/TaskTools.cs +++ b/src/LinqToDB.Identity/TaskTools.cs @@ -1,14 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace LinqToDB.Identity { internal static class TaskCache { /// - /// Gets a completed with the value of default(T). + /// Gets a completed with the value of default(T). /// public static Task DefaultCompletedTask { get; } = Task.FromResult(default(T)); } @@ -16,13 +13,12 @@ internal static class TaskCache internal static class TaskCache { /// - /// A that's already completed successfully. + /// A that's already completed successfully. /// /// - /// We're caching this in a static readonly field to make it more inlinable and avoid the volatile lookup done - /// by Task.CompletedTask. + /// We're caching this in a static readonly field to make it more inlinable and avoid the volatile lookup done + /// by Task.CompletedTask. /// public static readonly Task CompletedTask = Task.FromResult(0); } - -} +} \ No newline at end of file diff --git a/src/LinqToDB.Identity/UserStore.cs b/src/LinqToDB.Identity/UserStore.cs index 1c364e835..7a139f838 100644 --- a/src/LinqToDB.Identity/UserStore.cs +++ b/src/LinqToDB.Identity/UserStore.cs @@ -13,7 +13,6 @@ using System.Threading.Tasks; using LinqToDB.Data; using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.Internal; namespace LinqToDB.Identity { @@ -76,9 +75,9 @@ public UserStore(IConnectionFactory factory, IdentityErro /// The type of the primary key for a role. /// The type repewsenting database getConnection public class UserStore : - UserStore - , IdentityUserRole, IdentityUserLogin, - IdentityUserToken> + UserStore + , IdentityUserRole, IdentityUserLogin, + IdentityUserToken> where TUser : IdentityUser where TRole : IdentityRole where TContext : IDataContext @@ -150,7 +149,8 @@ protected override IdentityUserLogin CreateUserLogin(TUser user, UserLogin /// The name of the user token. /// The value of the user token. /// - protected override IdentityUserToken CreateUserToken(TUser user, string loginProvider, string name, string value) + protected override IdentityUserToken CreateUserToken(TUser user, string loginProvider, string name, + string value) { return new IdentityUserToken { @@ -175,9 +175,9 @@ protected override IdentityUserToken CreateUserToken(TUser user, string lo /// The type representing a user token. /// The type repewsenting database getConnection public abstract class UserStore : - UserStore - > + TUserToken> : + UserStore + > where TUser : IdentityUser where TRole : IdentityRole> where TContext : IDataContext @@ -217,18 +217,18 @@ public UserStore(IConnectionFactory factory, IdentityErro /// The type representing a role claim. /// The type repewsenting database getConnection public abstract class UserStore : - IUserLoginStore, - IUserRoleStore, - IUserClaimStore, - IUserPasswordStore, - IUserSecurityStampStore, - IUserEmailStore, - IUserLockoutStore, - IUserPhoneNumberStore, - IQueryableUserStore, - IUserTwoFactorStore, - IUserAuthenticationTokenStore + TUserToken, TRoleClaim> : + IUserLoginStore, + IUserRoleStore, + IUserClaimStore, + IUserPasswordStore, + IUserSecurityStampStore, + IUserEmailStore, + IUserLockoutStore, + IUserPhoneNumberStore, + IQueryableUserStore, + IUserTwoFactorStore, + IUserAuthenticationTokenStore where TUser : class, IIdentityUser where TRole : class, IIdentityRole where TUserClaim : class, IIdentityUserClaim @@ -300,12 +300,14 @@ await Task.Run(() => using (var dc = _factory.GetConnection()) { var q = dc.GetTable() - .Where(_ => _.UserId.Equals(user.Id) && (_.LoginProvider == loginProvider) && (_.Name == name)); + .Where(_ => _.UserId.Equals(user.Id) && _.LoginProvider == loginProvider && _.Name == name); var token = q.FirstOrDefault(); if (token == null) + { dc.Insert(CreateUserToken(user, loginProvider, name, value)); + } else { token.Value = value; @@ -338,8 +340,8 @@ public async Task RemoveTokenAsync(TUser user, string loginProvider, string name await Task.Run(() => _factory.GetContext() .GetTable() - .Where(_ => _.UserId.Equals(user.Id) && (_.LoginProvider == loginProvider) && (_.Name == name)). - Delete(), + .Where(_ => _.UserId.Equals(user.Id) && _.LoginProvider == loginProvider && _.Name == name) + .Delete(), cancellationToken); } @@ -365,7 +367,7 @@ public async Task GetTokenAsync(TUser user, string loginProvider, string var entry = await _factory.GetContext() .GetTable() - .Where(_ => _.UserId.Equals(user.Id) && (_.LoginProvider == loginProvider) && (_.Name == name)) + .Where(_ => _.UserId.Equals(user.Id) && _.LoginProvider == loginProvider && _.Name == name) .FirstOrDefaultAsync(cancellationToken); return entry?.Value; @@ -388,7 +390,8 @@ public virtual async Task> GetClaimsAsync(TUser user, throw new ArgumentNullException(nameof(user)); return await - _factory.GetContext().GetTable() + _factory.GetContext() + .GetTable() .Where(uc => uc.UserId.Equals(user.Id)) .Select(c => c.ToClaim()) .ToListAsync(cancellationToken); @@ -447,8 +450,9 @@ public virtual async Task ReplaceClaimAsync(TUser user, Claim claim, Claim newCl await Task.Run(() => { - var q = _factory.GetContext().GetTable() - .Where(uc => uc.UserId.Equals(user.Id) && (uc.ClaimValue == claim.Value) && (uc.ClaimType == claim.Type)); + var q = _factory.GetContext() + .GetTable() + .Where(uc => uc.UserId.Equals(user.Id) && uc.ClaimValue == claim.Value && uc.ClaimType == claim.Type); q.Set(_ => _.ClaimValue, newClaim.Value) .Set(_ => _.ClaimType, newClaim.Type) @@ -535,8 +539,8 @@ public virtual async Task> GetUsersForClaimAsync(Claim claim, var query = from userclaims in dc.GetTable() join user in Users on userclaims.UserId equals user.Id - where (userclaims.ClaimValue == claim.Value) - && (userclaims.ClaimType == claim.Type) + where userclaims.ClaimValue == claim.Value + && userclaims.ClaimType == claim.Type select user; return await query.ToListAsync(cancellationToken); @@ -624,7 +628,8 @@ public virtual Task SetEmailAsync(TUser user, string email, /// The task object containing the results of the asynchronous operation, the email address for the specified /// . /// - public virtual Task GetEmailAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + public virtual Task GetEmailAsync(TUser user, + CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -1030,7 +1035,7 @@ public virtual async Task DeleteAsync(TUser user, _factory .GetContext() .GetTable() - .Where(_ => _.Id.Equals(user.Id) && (_.ConcurrencyStamp == user.ConcurrencyStamp)) + .Where(_ => _.Id.Equals(user.Id) && _.ConcurrencyStamp == user.ConcurrencyStamp) .Delete(), cancellationToken); return result == 1 ? IdentityResult.Success : IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure()); } @@ -1132,8 +1137,8 @@ await Task.Run(() => .GetTable() .Delete( userLogin => - userLogin.UserId.Equals(user.Id) && (userLogin.LoginProvider == loginProvider) && - (userLogin.ProviderKey == providerKey)), + userLogin.UserId.Equals(user.Id) && userLogin.LoginProvider == loginProvider && + userLogin.ProviderKey == providerKey), cancellationToken); } @@ -1188,7 +1193,7 @@ public virtual async Task FindByLoginAsync(string loginProvider, string p var dc = _factory.GetContext(); var q = from ul in dc.GetTable() join u in dc.GetTable() on ul.UserId equals u.Id - where (ul.LoginProvider == loginProvider) && (ul.ProviderKey == providerKey) + where ul.LoginProvider == loginProvider && ul.ProviderKey == providerKey select u; return await q.FirstOrDefaultAsync(cancellationToken); @@ -1400,7 +1405,7 @@ await Task.Run(() => var q = from ur in dc.GetTable() join r in dc.GetTable() on ur.RoleId equals r.Id - where (r.NormalizedName == normalizedRoleName) && ur.UserId.Equals(user.Id) + where r.NormalizedName == normalizedRoleName && ur.UserId.Equals(user.Id) select ur; q.Delete(); @@ -1462,7 +1467,7 @@ public virtual async Task IsInRoleAsync(TUser user, string normalizedRoleN var q = from ur in dc.GetTable() join r in dc.GetTable() on ur.RoleId equals r.Id - where (r.NormalizedName == normalizedRoleName) && ur.UserId.Equals(user.Id) + where r.NormalizedName == normalizedRoleName && ur.UserId.Equals(user.Id) select ur; return await q.AnyAsync(cancellationToken); diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryContext.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryContext.cs index 66d0c6113..08abebf27 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryContext.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryContext.cs @@ -44,4 +44,5 @@ // { } // } -//} \ No newline at end of file +//} + diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryEFUserStoreTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryEFUserStoreTest.cs index 31c32e49e..c8ce509e9 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryEFUserStoreTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryEFUserStoreTest.cs @@ -14,94 +14,110 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test { - public class InMemoryStorage: IDisposable + public class InMemoryStorage : IDisposable { - private static int _counter = 0; - private static object _syncRoot = new object(); - - public string ConnectionString => _connectionString; - private SqliteConnection _connection; - private string _connectionString; + private static int _counter; + private static readonly object _syncRoot = new object(); + private readonly SqliteConnection _connection; public InMemoryStorage() { lock (_syncRoot) { - _connectionString = $"Data Source=file:memdb{_counter}?mode=memory&cache=shared"; + ConnectionString = $"Data Source=file:memdb{_counter}?mode=memory&cache=shared"; //_connectionString = "Data Source=file:memdb?mode=memory&cache=shared"; _counter++; } var connectionString = ConnectionString; //"Data Source=:memory:;"; - _connection = new SqliteConnection(connectionString); - _connection.Open(); - + _connection = new SqliteConnection(connectionString); + _connection.Open(); } + public string ConnectionString { get; } + public void Dispose() { _connection.Dispose(); } } - public class InMemoryEFUserStoreTest : UserManagerTestBase, IClassFixture - { - public InMemoryEFUserStoreTest(InMemoryStorage storage) - { - _storage = storage; - } - private InMemoryStorage _storage; + public class InMemoryEFUserStoreTest : UserManagerTestBase, + IClassFixture + { + private readonly InMemoryStorage _storage; + + public InMemoryEFUserStoreTest(InMemoryStorage storage) + { + _storage = storage; + } - protected override TestConnectionFactory CreateTestContext() - { - var connectionString = _storage.ConnectionString; + protected override TestConnectionFactory CreateTestContext() + { + var connectionString = _storage.ConnectionString; var factory = new TestConnectionFactory(new SQLiteDataProvider(), "InMemoryEFUserStoreTest", connectionString); CreateTables(factory, connectionString); - return factory; - } - - protected override void AddUserStore(IServiceCollection services, TestConnectionFactory context = null) - { - services.AddSingleton>(new UserStore(context ?? CreateTestContext())); - } - - protected override void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null) - { - var store = new RoleStore(context ?? CreateTestContext()); - services.AddSingleton>(store); - } - - protected override IdentityUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "", - bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false) - { - return new IdentityUser - { - UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()), - Email = email, - PhoneNumber = phoneNumber, - LockoutEnabled = lockoutEnabled, - LockoutEnd = lockoutEnd - }; - } - - protected override IdentityRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false) - { - var roleName = useRoleNamePrefixAsRoleName ? roleNamePrefix : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid()); - return new IdentityRole(roleName); - } - - protected override void SetUserPasswordHash(IdentityUser user, string hashedPassword) - { - user.PasswordHash = hashedPassword; - } - - protected override Expression> UserNameEqualsPredicate(string userName) => u => u.UserName == userName; - - protected override Expression> RoleNameEqualsPredicate(string roleName) => r => r.Name == roleName; - - protected override Expression> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName); - - protected override Expression> RoleNameStartsWithPredicate(string roleName) => r => r.Name.StartsWith(roleName); - } -} + return factory; + } + + protected override void AddUserStore(IServiceCollection services, TestConnectionFactory context = null) + { + services.AddSingleton>( + new UserStore(context ?? CreateTestContext())); + } + + protected override void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null) + { + var store = new RoleStore(context ?? CreateTestContext()); + services.AddSingleton>(store); + } + + protected override IdentityUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "", + bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), + bool useNamePrefixAsUserName = false) + { + return new IdentityUser + { + UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()), + Email = email, + PhoneNumber = phoneNumber, + LockoutEnabled = lockoutEnabled, + LockoutEnd = lockoutEnd + }; + } + + protected override IdentityRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false) + { + var roleName = useRoleNamePrefixAsRoleName + ? roleNamePrefix + : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid()); + return new IdentityRole(roleName); + } + + protected override void SetUserPasswordHash(IdentityUser user, string hashedPassword) + { + user.PasswordHash = hashedPassword; + } + + protected override Expression> UserNameEqualsPredicate(string userName) + { + return u => u.UserName == userName; + } + + protected override Expression> RoleNameEqualsPredicate(string roleName) + { + return r => r.Name == roleName; + } + + protected override Expression> UserNameStartsWithPredicate(string userName) + { + return u => u.UserName.StartsWith(userName); + } + + protected override Expression> RoleNameStartsWithPredicate(string roleName) + { + return r => r.Name.StartsWith(roleName); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryStoreWithGenericsTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryStoreWithGenericsTest.cs index b3b2065d5..6ded8ead0 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryStoreWithGenericsTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryStoreWithGenericsTest.cs @@ -18,313 +18,338 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test { - public class InMemoryEFUserStoreTestWithGenerics : UserManagerTestBase, IDisposable, IClassFixture + public class InMemoryEFUserStoreTestWithGenerics : + UserManagerTestBase, IDisposable, IClassFixture { -// private readonly InMemoryContextWithGenerics _context; - private UserStoreWithGenerics _store; - private InMemoryStorage _storage; - public InMemoryEFUserStoreTestWithGenerics(InMemoryStorage storage) - { - var services = new ServiceCollection(); - services.AddSingleton(); - //services.AddDbContext(options => options.UseInMemoryDatabase()); + { + var services = new ServiceCollection(); + services.AddSingleton(); + //services.AddDbContext(options => options.UseInMemoryDatabase()); // _context = services.BuildServiceProvider().GetRequiredService(); - _storage = storage; - } + _storage = storage; + } + + public void Dispose() + { + } + +// private readonly InMemoryContextWithGenerics _context; + private UserStoreWithGenerics _store; + + private readonly InMemoryStorage _storage; protected override TestConnectionFactory CreateTestContext() { var connectionString = _storage.ConnectionString; //"Data Source=:memory:;"; - var factory = new TestConnectionFactory(new SQLiteDataProvider(), "InMemoryEFUserStoreTestWithGenerics", connectionString); + var factory = new TestConnectionFactory(new SQLiteDataProvider(), "InMemoryEFUserStoreTestWithGenerics", + connectionString); CreateTables(factory, connectionString); return factory; } protected override void AddUserStore(IServiceCollection services, TestConnectionFactory context = null) - { - _store = new UserStoreWithGenerics(context ?? CreateTestContext(), "TestContext"); - services.AddSingleton>(_store); - } - - protected override void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null) - { - services.AddSingleton>(new RoleStoreWithGenerics(context ?? CreateTestContext(), "TestContext")); - } - - protected override IdentityUserWithGenerics CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "", - bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false) - { - return new IdentityUserWithGenerics - { - UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()), - Email = email, - PhoneNumber = phoneNumber, - LockoutEnabled = lockoutEnabled, - LockoutEnd = lockoutEnd - }; - } - - protected override MyIdentityRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false) - { - var roleName = useRoleNamePrefixAsRoleName ? roleNamePrefix : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid()); - return new MyIdentityRole(roleName); - } - - protected override void SetUserPasswordHash(IdentityUserWithGenerics user, string hashedPassword) - { - user.PasswordHash = hashedPassword; - } - - protected override Expression> UserNameEqualsPredicate(string userName) => u => u.UserName == userName; - - protected override Expression> RoleNameEqualsPredicate(string roleName) => r => r.Name == roleName; - - protected override Expression> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName); - - protected override Expression> RoleNameStartsWithPredicate(string roleName) => r => r.Name.StartsWith(roleName); - - [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 void Dispose() - { - } - } - - public class ClaimEqualityComparer : IEqualityComparer - { - public static IEqualityComparer 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 : IdentityUser - { - public IdentityUserWithGenerics() - { - Id = Guid.NewGuid().ToString(); - } - } - - public class UserStoreWithGenerics : UserStore - { - public string LoginContext { get; set; } - - public UserStoreWithGenerics(TestConnectionFactory factory, string loginContext) - : base(factory) - { - LoginContext = loginContext; - factory.CreateTable(); - factory.CreateTable(); - factory.CreateTable(); - factory.CreateTable(); - } - - 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 : RoleStore> - { - private string _loginContext; - public RoleStoreWithGenerics(TestConnectionFactory factory, string loginContext) : base(factory) - { - _loginContext = loginContext; + { + _store = new UserStoreWithGenerics(context ?? CreateTestContext(), "TestContext"); + services.AddSingleton>(_store); + } + + protected override void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null) + { + services.AddSingleton>( + new RoleStoreWithGenerics(context ?? CreateTestContext(), "TestContext")); + } + + protected override IdentityUserWithGenerics CreateTestUser(string namePrefix = "", string email = "", + string phoneNumber = "", + bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), + bool useNamePrefixAsUserName = false) + { + return new IdentityUserWithGenerics + { + UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()), + Email = email, + PhoneNumber = phoneNumber, + LockoutEnabled = lockoutEnabled, + LockoutEnd = lockoutEnd + }; + } + + protected override MyIdentityRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false) + { + var roleName = useRoleNamePrefixAsRoleName + ? roleNamePrefix + : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid()); + return new MyIdentityRole(roleName); + } + + protected override void SetUserPasswordHash(IdentityUserWithGenerics user, string hashedPassword) + { + user.PasswordHash = hashedPassword; + } + + protected override Expression> UserNameEqualsPredicate(string userName) + { + return u => u.UserName == userName; + } + + protected override Expression> RoleNameEqualsPredicate(string roleName) + { + return r => r.Name == roleName; + } + + protected override Expression> UserNameStartsWithPredicate(string userName) + { + return u => u.UserName.StartsWith(userName); + } + + protected override Expression> RoleNameStartsWithPredicate(string roleName) + { + return r => r.Name.StartsWith(roleName); + } + + [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 (var 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 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); + var claim = new Claim("c", "b", "i"); + var oldClaim = userClaims.FirstOrDefault(); + IdentityResultAssert.IsSuccess(await manager.ReplaceClaimAsync(user, oldClaim, claim)); + var newUserClaims = await manager.GetClaimsAsync(user); + Assert.Equal(1, newUserClaims.Count); + var newClaim = newUserClaims.FirstOrDefault(); + Assert.Equal(claim.Type, newClaim.Type); + Assert.Equal(claim.Value, newClaim.Value); + Assert.Equal(claim.Issuer, newClaim.Issuer); + } + + [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 (var 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); + } + } + + public class ClaimEqualityComparer : IEqualityComparer + { + public static IEqualityComparer 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 : IdentityUser + { + public IdentityUserWithGenerics() + { + Id = Guid.NewGuid().ToString(); + } + } + + public class UserStoreWithGenerics : UserStore + { + public UserStoreWithGenerics(TestConnectionFactory factory, string loginContext) + : base(factory) + { + LoginContext = loginContext; + factory.CreateTable(); + factory.CreateTable(); + factory.CreateTable(); + factory.CreateTable(); + } + + public string LoginContext { get; set; } + + 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 : RoleStore> + { + private string _loginContext; + + public RoleStoreWithGenerics(TestConnectionFactory factory, string loginContext) : base(factory) + { + _loginContext = loginContext; factory.CreateTable>(); factory.CreateTable(); } protected override IdentityRoleClaim CreateRoleClaim(MyIdentityRole role, Claim claim) - { - return new IdentityRoleClaim { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value }; - } - } - - public class IdentityUserClaimWithIssuer : IdentityUserClaim - { - 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 - { - public DateTime Created { get; set; } - } - - public class MyIdentityRole : IdentityRole> - { - public MyIdentityRole() : base() - { - Id = Guid.NewGuid().ToString(); - } - - public MyIdentityRole(string roleName) : this() - { - Name = roleName; - } - - } - - public class IdentityUserTokenWithStuff : IdentityUserToken - { - public string Stuff { get; set; } - } - - public class IdentityUserLoginWithContext : IdentityUserLogin - { - public string Context { get; set; } - } - - //public class InMemoryContextWithGenerics : InMemoryContext, IdentityUserTokenWithStuff> - //{ - - //} - - #endregion + { + return new IdentityRoleClaim {RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value}; + } + } + + public class IdentityUserClaimWithIssuer : IdentityUserClaim + { + 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 + { + public DateTime Created { get; set; } + } + + public class MyIdentityRole : IdentityRole> + { + public MyIdentityRole() + { + Id = Guid.NewGuid().ToString(); + } + + public MyIdentityRole(string roleName) : this() + { + Name = roleName; + } + } + + public class IdentityUserTokenWithStuff : IdentityUserToken + { + public string Stuff { get; set; } + } + + public class IdentityUserLoginWithContext : IdentityUserLogin + { + public string Context { get; set; } + } + + //public class InMemoryContextWithGenerics : InMemoryContext, IdentityUserTokenWithStuff> + //{ + + //} + + #endregion } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/RoleStoreTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/RoleStoreTest.cs index 880d9a817..ab233efbc 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/RoleStoreTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/RoleStoreTest.cs @@ -13,25 +13,17 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test { - public class RoleStoreTest : IClassFixture - { - private InMemoryStorage _storage; - - public RoleStoreTest(InMemoryStorage storage) - { - _storage = storage; - } + public class RoleStoreTest : IClassFixture + { + public RoleStoreTest(InMemoryStorage storage) + { + _storage = storage; + } - [Fact] - public async Task CanCreateUsingAddRoleManager() - { - var manager = TestIdentityFactory.CreateRoleManager(GetConnectionFactory()); - Assert.NotNull(manager); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(new IdentityRole("arole"))); - } + private readonly InMemoryStorage _storage; - private IConnectionFactory GetConnectionFactory() - { + private IConnectionFactory GetConnectionFactory() + { var connectionString = _storage.ConnectionString; var factory = new TestConnectionFactory(new SQLiteDataProvider(), "RoleStoreTest", connectionString); @@ -40,58 +32,67 @@ private IConnectionFactory GetConnectionFactory() } [Fact] - public async Task CanCreateRoleWithSingletonManager() - { - var services = TestIdentityFactory.CreateTestServices(); - //services.AddEntityFrameworkInMemoryDatabase(); - services.AddSingleton>(GetConnectionFactory()); - services.AddTransient, RoleStore>(); - services.AddSingleton>(); - var provider = services.BuildServiceProvider(); - var manager = provider.GetRequiredService>(); - Assert.NotNull(manager); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(new IdentityRole("someRole"))); - } + public async Task CanCreateRoleWithSingletonManager() + { + var services = TestIdentityFactory.CreateTestServices(); + //services.AddEntityFrameworkInMemoryDatabase(); + services.AddSingleton(GetConnectionFactory()); + services.AddTransient, RoleStore>(); + services.AddSingleton>(); + var provider = services.BuildServiceProvider(); + var manager = provider.GetRequiredService>(); + Assert.NotNull(manager); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(new IdentityRole("someRole"))); + } - [Fact] - public async Task RoleStoreMethodsThrowWhenDisposedTest() - { - var store = new RoleStore(GetConnectionFactory()); - store.Dispose(); - await Assert.ThrowsAsync(async () => await store.FindByIdAsync(null)); - await Assert.ThrowsAsync(async () => await store.FindByNameAsync(null)); - await Assert.ThrowsAsync(async () => await store.GetRoleIdAsync(null)); - await Assert.ThrowsAsync(async () => await store.GetRoleNameAsync(null)); - await Assert.ThrowsAsync(async () => await store.SetRoleNameAsync(null, null)); - await Assert.ThrowsAsync(async () => await store.CreateAsync(null)); - await Assert.ThrowsAsync(async () => await store.UpdateAsync(null)); - await Assert.ThrowsAsync(async () => await store.DeleteAsync(null)); - } + [Fact] + public async Task CanCreateUsingAddRoleManager() + { + var manager = TestIdentityFactory.CreateRoleManager(GetConnectionFactory()); + Assert.NotNull(manager); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(new IdentityRole("arole"))); + } - [Fact] - public async Task RoleStorePublicNullCheckTest() - { - Assert.Throws("factory", () => new RoleStore(null)); - var store = new RoleStore(GetConnectionFactory()); - await Assert.ThrowsAsync("role", async () => await store.GetRoleIdAsync(null)); - await Assert.ThrowsAsync("role", async () => await store.GetRoleNameAsync(null)); - await Assert.ThrowsAsync("role", async () => await store.SetRoleNameAsync(null, null)); - await Assert.ThrowsAsync("role", async () => await store.CreateAsync(null)); - await Assert.ThrowsAsync("role", async () => await store.UpdateAsync(null)); - await Assert.ThrowsAsync("role", async () => await store.DeleteAsync(null)); - } + [Fact] + public async Task CanUpdateRoleName() + { + var manager = TestIdentityFactory.CreateRoleManager(GetConnectionFactory()); + var role = new IdentityRole("UpdateRoleName"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(role)); + Assert.Null(await manager.FindByNameAsync("New")); + IdentityResultAssert.IsSuccess(await manager.SetRoleNameAsync(role, "New")); + IdentityResultAssert.IsSuccess(await manager.UpdateAsync(role)); + Assert.NotNull(await manager.FindByNameAsync("New")); + Assert.Null(await manager.FindByNameAsync("UpdateAsync")); + } + + [Fact] + public async Task RoleStoreMethodsThrowWhenDisposedTest() + { + var store = new RoleStore(GetConnectionFactory()); + store.Dispose(); + await Assert.ThrowsAsync(async () => await store.FindByIdAsync(null)); + await Assert.ThrowsAsync(async () => await store.FindByNameAsync(null)); + await Assert.ThrowsAsync(async () => await store.GetRoleIdAsync(null)); + await Assert.ThrowsAsync(async () => await store.GetRoleNameAsync(null)); + await Assert.ThrowsAsync(async () => await store.SetRoleNameAsync(null, null)); + await Assert.ThrowsAsync(async () => await store.CreateAsync(null)); + await Assert.ThrowsAsync(async () => await store.UpdateAsync(null)); + await Assert.ThrowsAsync(async () => await store.DeleteAsync(null)); + } - [Fact] - public async Task CanUpdateRoleName() - { - var manager = TestIdentityFactory.CreateRoleManager(GetConnectionFactory()); - var role = new IdentityRole("UpdateRoleName"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(role)); - Assert.Null(await manager.FindByNameAsync("New")); - IdentityResultAssert.IsSuccess(await manager.SetRoleNameAsync(role, "New")); - IdentityResultAssert.IsSuccess(await manager.UpdateAsync(role)); - Assert.NotNull(await manager.FindByNameAsync("New")); - Assert.Null(await manager.FindByNameAsync("UpdateAsync")); - } - } -} + [Fact] + public async Task RoleStorePublicNullCheckTest() + { + Assert.Throws("factory", + () => new RoleStore(null)); + var store = new RoleStore(GetConnectionFactory()); + await Assert.ThrowsAsync("role", async () => await store.GetRoleIdAsync(null)); + await Assert.ThrowsAsync("role", async () => await store.GetRoleNameAsync(null)); + await Assert.ThrowsAsync("role", async () => await store.SetRoleNameAsync(null, null)); + await Assert.ThrowsAsync("role", async () => await store.CreateAsync(null)); + await Assert.ThrowsAsync("role", async () => await store.UpdateAsync(null)); + await Assert.ThrowsAsync("role", async () => await store.DeleteAsync(null)); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/TestIdentityFactory.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/TestIdentityFactory.cs index 8f9f61d15..4e803dfe8 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/TestIdentityFactory.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/TestIdentityFactory.cs @@ -1,7 +1,6 @@ // 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 LinqToDB; using LinqToDB.Data; using LinqToDB.Identity; @@ -10,40 +9,40 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test { - public static class TestIdentityFactory - { - // public static InMemoryContext CreateContext() - // { - // var services = new ServiceCollection(); - // var serviceProvider = services.BuildServiceProvider(); - - // var db = new InMemoryContext(); - // //db.Database.EnsureCreated(); - - //throw new NotImplementedException(); - - // //return db; - // } - - public static IServiceCollection CreateTestServices() - { - var services = new ServiceCollection(); - services.AddSingleton(); - services.AddLogging(); - services.AddIdentity(); - return services; - } - - public static RoleManager CreateRoleManager(IConnectionFactory factory) - { - var services = CreateTestServices(); - services.AddSingleton>(new RoleStore(factory)); - return services.BuildServiceProvider().GetRequiredService>(); - } - - //public static RoleManager CreateRoleManager() - //{ - // return CreateRoleManager(CreateContext()); - //} - } -} + public static class TestIdentityFactory + { + // public static InMemoryContext CreateContext() + // { + // var services = new ServiceCollection(); + // var serviceProvider = services.BuildServiceProvider(); + + // var db = new InMemoryContext(); + // //db.Database.EnsureCreated(); + + //throw new NotImplementedException(); + + // //return db; + // } + + public static IServiceCollection CreateTestServices() + { + var services = new ServiceCollection(); + services.AddSingleton(); + services.AddLogging(); + services.AddIdentity(); + return services; + } + + public static RoleManager CreateRoleManager(IConnectionFactory factory) + { + var services = CreateTestServices(); + services.AddSingleton>(new RoleStore(factory)); + return services.BuildServiceProvider().GetRequiredService>(); + } + //{ + + //public static RoleManager CreateRoleManager() + // return CreateRoleManager(CreateContext()); + //} + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/CustomPocoTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/CustomPocoTest.cs index 5689d9748..20775d454 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/CustomPocoTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/CustomPocoTest.cs @@ -3,12 +3,10 @@ using System; using System.Linq; -using System.Threading.Tasks; using LinqToDB; using LinqToDB.Data; using LinqToDB.DataProvider; using LinqToDB.DataProvider.SqlServer; -using LinqToDB.Identity; using LinqToDB.Mapping; using Microsoft.AspNetCore.Identity.Test; using Microsoft.AspNetCore.Testing.xunit; @@ -16,145 +14,141 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test { - public class CustomPocoTest : IClassFixture - { - private readonly ScratchDatabaseFixture _fixture; - private readonly TestConnectionFactory _factory; - private readonly SqlServerDataProvider _dataProvider = new SqlServerDataProvider("*", SqlServerVersion.v2012); + public class CustomPocoTest : IClassFixture + { + private readonly SqlServerDataProvider _dataProvider = new SqlServerDataProvider("*", SqlServerVersion.v2012); + private readonly TestConnectionFactory _factory; + private readonly ScratchDatabaseFixture _fixture; + + public CustomPocoTest(ScratchDatabaseFixture fixture) + { + _fixture = fixture; + _factory = new TestConnectionFactory(_dataProvider, nameof(CustomPocoTest), _fixture.ConnectionString); + } + + public CustomDbContext CreateContext(bool delete = false) where TKey : IEquatable + { + var db = new CustomDbContext(_dataProvider, _fixture.ConnectionString); + if (delete) + _factory.DropTable>(); + + _factory.CreateTable>(); + return db; + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public void CanUpdateNameGuid() + { + using (var db = CreateContext(true)) + { + var oldName = Guid.NewGuid().ToString(); + var user = new User {UserName = oldName, Id = Guid.NewGuid()}; + db.Insert(user); + var newName = Guid.NewGuid().ToString(); + + user.UserName = newName; + db.Update(user); + + Assert.Null(db.Users.SingleOrDefault(u => u.UserName == oldName)); + Assert.Equal(user, db.Users.Single(u => u.UserName == newName)); + } + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public void CanUpdateNameString() + { + using (var db = CreateContext(true)) + { + var oldName = Guid.NewGuid().ToString(); + var user = new User {UserName = oldName, Id = Guid.NewGuid().ToString()}; + db.Insert(user); + + var newName = Guid.NewGuid().ToString(); + user.UserName = newName; + db.Update(user); + + Assert.Null(db.Users.SingleOrDefault(u => u.UserName == oldName)); + Assert.Equal(user, db.Users.Single(u => u.UserName == newName)); + } + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public void CanCreateUserInt() + { + using (var db = CreateContext(true)) + { + var user = new User(); + db.Insert(user); - public CustomPocoTest(ScratchDatabaseFixture fixture) - { - _fixture = fixture; - _factory = new TestConnectionFactory(_dataProvider, nameof(CustomPocoTest), _fixture.ConnectionString); + user.UserName = "Boo"; + db.Update(user); + + var fetch = db.Users.First(u => u.UserName == "Boo"); + Assert.Equal(user, fetch); + } + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public void CanUpdateNameInt() + { + using (var db = CreateContext(true)) + { + var oldName = Guid.NewGuid().ToString(); + var user = new User {UserName = oldName}; + db.Insert(user); + + var newName = Guid.NewGuid().ToString(); + user.UserName = newName; + db.Update(user); - } + Assert.Null(db.Users.SingleOrDefault(u => u.UserName == oldName)); + Assert.Equal(user, db.Users.Single(u => u.UserName == newName)); + } + } - public class User where TKey : IEquatable - { + public class User where TKey : IEquatable + { [PrimaryKey] [Column(Length = 255, CanBeNull = false)] - public TKey Id { get; set; } - public string UserName { get; set; } - - public override bool Equals(object obj) - { - var other = obj as User; - if (other == null) - return false; - - return Id.Equals(other.Id) && UserName == other.UserName; - } - - public override int GetHashCode() - { - return Id.GetHashCode(); - } - } - - public class CustomDbContext : DataConnection where TKey : IEquatable - { - public CustomDbContext(IDataProvider dataProvider, string connectionString) - :base(dataProvider, connectionString) - { - - } + public TKey Id { get; set; } - public ITable> Users => GetTable>(); + public string UserName { get; set; } - } + public override bool Equals(object obj) + { + var other = obj as User; + if (other == null) + return false; - public CustomDbContext CreateContext(bool delete = false) where TKey : IEquatable - { - var db = new CustomDbContext(_dataProvider, _fixture.ConnectionString); - if (delete) - { - _factory.DropTable>(); - } + return Id.Equals(other.Id) && UserName == other.UserName; + } - _factory.CreateTable>(); - return db; - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public void CanUpdateNameGuid() - { - using (var db = CreateContext(true)) - { - var oldName = Guid.NewGuid().ToString(); - var user = new User { UserName = oldName, Id = Guid.NewGuid() }; - db.Insert(user); - var newName = Guid.NewGuid().ToString(); + public override int GetHashCode() + { + return Id.GetHashCode(); + } + } - user.UserName = newName; - db.Update(user); - - Assert.Null(db.Users.SingleOrDefault(u => u.UserName == oldName)); - Assert.Equal(user, db.Users.Single(u => u.UserName == newName)); - } - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public void CanUpdateNameString() - { - using (var db = CreateContext(true)) - { - var oldName = Guid.NewGuid().ToString(); - var user = new User { UserName = oldName, Id = Guid.NewGuid().ToString() }; - db.Insert(user); - - var newName = Guid.NewGuid().ToString(); - user.UserName = newName; - db.Update(user); - - Assert.Null(db.Users.SingleOrDefault(u => u.UserName == oldName)); - Assert.Equal(user, db.Users.Single(u => u.UserName == newName)); - } - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public void CanCreateUserInt() - { - using (var db = CreateContext(true)) - { - var user = new User(); - db.Insert(user); - - user.UserName = "Boo"; - db.Update(user); - - var fetch = db.Users.First(u => u.UserName == "Boo"); - Assert.Equal(user, fetch); - } - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public void CanUpdateNameInt() - { - using (var db = CreateContext(true)) - { - var oldName = Guid.NewGuid().ToString(); - var user = new User { UserName = oldName }; - db.Insert(user); - - var newName = Guid.NewGuid().ToString(); - user.UserName = newName; - db.Update(user); - - Assert.Null(db.Users.SingleOrDefault(u => u.UserName == oldName)); - Assert.Equal(user, db.Users.Single(u => u.UserName == newName)); - } - } - } + public class CustomDbContext : DataConnection where TKey : IEquatable + { + public CustomDbContext(IDataProvider dataProvider, string connectionString) + : base(dataProvider, connectionString) + { + } + + public ITable> Users => GetTable>(); + } + } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/DbUtil.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/DbUtil.cs index 16c22ef8d..be3f5a03f 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/DbUtil.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/DbUtil.cs @@ -1,33 +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 LinqToDB.DataProvider.SqlServer; -using LinqToDB.Identity; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; - namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test { - public static class DbUtil - { - - // public static IServiceCollection ConfigureDbServices(string connectionString, IServiceCollection services = null) - // { - // if (services == null) - // { - // services = new ServiceCollection(); - // } - // services.AddSingleton(); + public static class DbUtil + { + // public static IServiceCollection ConfigureDbServices(string connectionString, IServiceCollection services = null) + // { + // if (services == null) + // { + // services = new ServiceCollection(); + // } + // services.AddSingleton(); - //LinqToDB.Data.DataConnection.AddConfiguration("*", connectionString, new SqlServerDataProvider("*", SqlServerVersion.v2008)); + //LinqToDB.Data.DataConnection.AddConfiguration("*", connectionString, new SqlServerDataProvider("*", SqlServerVersion.v2008)); - // return services; - // } + // return services; + // } - //public static TContext Create(string connectionString) where TContext : DbContext - //{ - // var serviceProvider = ConfigureDbServices(connectionString).BuildServiceProvider(); - // return serviceProvider.GetRequiredService(); - //} - } + //public static TContext Create(string connectionString) where TContext : DbContext + //{ + // var serviceProvider = ConfigureDbServices(connectionString).BuildServiceProvider(); + // return serviceProvider.GetRequiredService(); + //} + } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/DefaultPocoTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/DefaultPocoTest.cs index b18a85e95..bc2513c08 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/DefaultPocoTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/DefaultPocoTest.cs @@ -13,190 +13,180 @@ using Microsoft.AspNetCore.Identity.Test; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; using Xunit; namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test { - public class DefaultPocoTest : IClassFixture - { - private readonly ApplicationBuilder _builder; - private readonly SqlServerDataProvider _dataProvider = new SqlServerDataProvider("*", SqlServerVersion.v2012); - - static DefaultPocoTest() - { - MappingSchema.Default - .GetFluentMappingBuilder() - .Entity() - .HasPrimaryKey(_ => _.Id) - .Property(_ => _.Id) - .HasLength(255) - .IsNullable(false) - .Entity() - .HasPrimaryKey(_ => _.Id) - .Property(_ => _.Id) - .HasLength(255) - .IsNullable(false); - } - - public DefaultPocoTest(ScratchDatabaseFixture fixture) - { - var services = new ServiceCollection(); - - var factory = new TestConnectionFactory(_dataProvider, nameof(DefaultPocoTest), fixture.ConnectionString); - services - .AddIdentity() - .AddLinqToDBStores(factory); - - services.AddTransient(_ => new IdentityDataConnection(_dataProvider, fixture.ConnectionString)); - - services.AddLogging(); - - var provider = services.BuildServiceProvider(); - _builder = new ApplicationBuilder(provider); + public class DefaultPocoTest : IClassFixture + { + private readonly ApplicationBuilder _builder; + private readonly SqlServerDataProvider _dataProvider = new SqlServerDataProvider("*", SqlServerVersion.v2012); + + static DefaultPocoTest() + { + MappingSchema.Default + .GetFluentMappingBuilder() + .Entity() + .HasPrimaryKey(_ => _.Id) + .Property(_ => _.Id) + .HasLength(255) + .IsNullable(false) + .Entity() + .HasPrimaryKey(_ => _.Id) + .Property(_ => _.Id) + .HasLength(255) + .IsNullable(false); + } + + public DefaultPocoTest(ScratchDatabaseFixture fixture) + { + var services = new ServiceCollection(); + + var factory = new TestConnectionFactory(_dataProvider, nameof(DefaultPocoTest), fixture.ConnectionString); + services + .AddIdentity() + .AddLinqToDBStores(factory); + + services.AddTransient(_ => new IdentityDataConnection(_dataProvider, fixture.ConnectionString)); + + services.AddLogging(); + + var provider = services.BuildServiceProvider(); + _builder = new ApplicationBuilder(provider); factory.CreateTables(); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task EnsureStartupUsageWorks() - { - var userStore = _builder.ApplicationServices.GetRequiredService>(); - var userManager = _builder.ApplicationServices.GetRequiredService>(); - - Assert.NotNull(userStore); - Assert.NotNull(userManager); - - const string userName = "admin"; - const string password = "1qaz@WSX"; - var user = new IdentityUser { UserName = userName }; - IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user, password)); - IdentityResultAssert.IsSuccess(await userManager.DeleteAsync(user)); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task CanIncludeUserClaimsTest() - { - // Arrange - var userManager = _builder.ApplicationServices.GetRequiredService>(); - var dbContext = _builder.ApplicationServices.GetRequiredService(); - - var username = "user" + new Random().Next(); - var user = new IdentityUser() { UserName = username }; - IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user)); - - for (var i = 0; i < 10; i++) - { - IdentityResultAssert.IsSuccess(await userManager.AddClaimAsync(user, new Claim(i.ToString(), "foo"))); - } - - user = dbContext.Users.LoadWith(x => x.Claims).FirstOrDefault(x => x.UserName == username); - - // Assert - Assert.NotNull(user); - Assert.NotNull(user.Claims); - Assert.Equal(10, user.Claims.Count()); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task CanIncludeUserLoginsTest() - { - // Arrange - var userManager = _builder.ApplicationServices.GetRequiredService>(); - var dbContext = _builder.ApplicationServices.GetRequiredService(); - - var username = "user" + new Random().Next(); - var user = new IdentityUser() { UserName = username }; - IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user)); - - for (var i = 0; i < 10; i++) - { - IdentityResultAssert.IsSuccess(await userManager.AddLoginAsync(user, new UserLoginInfo("foo" + i, "bar" + i, "foo"))); - } - - user = dbContext.Users.LoadWith(x => x.Logins).FirstOrDefault(x => x.UserName == username); - - // Assert - Assert.NotNull(user); - Assert.NotNull(user.Logins); - Assert.Equal(10, user.Logins.Count()); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task CanIncludeUserRolesTest() - { - // Arrange - var userManager = _builder.ApplicationServices.GetRequiredService>(); - var roleManager = _builder.ApplicationServices.GetRequiredService>(); - var dbContext = _builder.ApplicationServices.GetRequiredService(); - - const string roleName = "Admin"; - for (var i = 0; i < 10; i++) - { - IdentityResultAssert.IsSuccess(await roleManager.CreateAsync(new IdentityRole(roleName + i))); - } - var username = "user" + new Random().Next(); - var user = new IdentityUser() { UserName = username }; - IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user)); - - for (var i = 0; i < 10; i++) - { - IdentityResultAssert.IsSuccess(await userManager.AddToRoleAsync(user, roleName + i)); - } - - user = dbContext.Users.LoadWith(x => x.Roles).FirstOrDefault(x => x.UserName == username); - - // Assert - Assert.NotNull(user); - Assert.NotNull(user.Roles); - Assert.Equal(10, user.Roles.Count()); - - for (var i = 0; i < 10; i++) - { - var role = dbContext.Roles.LoadWith(r => r.Users).FirstOrDefault(r => r.Name == (roleName + i)); - Assert.NotNull(role); - Assert.NotNull(role.Users); - Assert.Equal(1, role.Users.Count()); - } - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task CanIncludeRoleClaimsTest() - { - // Arrange - var roleManager = _builder.ApplicationServices.GetRequiredService>(); - var dbContext = _builder.ApplicationServices.GetRequiredService(); - - var role = new IdentityRole("Admin"); - - IdentityResultAssert.IsSuccess(await roleManager.CreateAsync(role)); - - for (var i = 0; i < 10; i++) - { - IdentityResultAssert.IsSuccess(await roleManager.AddClaimAsync(role, new Claim("foo" + i, "bar" + i))); - } - - role = dbContext.Roles.LoadWith(x => x.Claims).FirstOrDefault(x => x.Name == "Admin"); - - // Assert - Assert.NotNull(role); - Assert.NotNull(role.Claims); - Assert.Equal(10, role.Claims.Count()); - } - } + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task EnsureStartupUsageWorks() + { + var userStore = _builder.ApplicationServices.GetRequiredService>(); + var userManager = _builder.ApplicationServices.GetRequiredService>(); + + Assert.NotNull(userStore); + Assert.NotNull(userManager); + + const string userName = "admin"; + const string password = "1qaz@WSX"; + var user = new IdentityUser {UserName = userName}; + IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user, password)); + IdentityResultAssert.IsSuccess(await userManager.DeleteAsync(user)); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task CanIncludeUserClaimsTest() + { + // Arrange + var userManager = _builder.ApplicationServices.GetRequiredService>(); + var dbContext = _builder.ApplicationServices.GetRequiredService(); + + var username = "user" + new Random().Next(); + var user = new IdentityUser {UserName = username}; + IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user)); + + for (var i = 0; i < 10; i++) + IdentityResultAssert.IsSuccess(await userManager.AddClaimAsync(user, new Claim(i.ToString(), "foo"))); + + user = dbContext.Users.LoadWith(x => x.Claims).FirstOrDefault(x => x.UserName == username); + + // Assert + Assert.NotNull(user); + Assert.NotNull(user.Claims); + Assert.Equal(10, user.Claims.Count()); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task CanIncludeUserLoginsTest() + { + // Arrange + var userManager = _builder.ApplicationServices.GetRequiredService>(); + var dbContext = _builder.ApplicationServices.GetRequiredService(); + + var username = "user" + new Random().Next(); + var user = new IdentityUser {UserName = username}; + IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user)); + + for (var i = 0; i < 10; i++) + IdentityResultAssert.IsSuccess( + await userManager.AddLoginAsync(user, new UserLoginInfo("foo" + i, "bar" + i, "foo"))); + + user = dbContext.Users.LoadWith(x => x.Logins).FirstOrDefault(x => x.UserName == username); + + // Assert + Assert.NotNull(user); + Assert.NotNull(user.Logins); + Assert.Equal(10, user.Logins.Count()); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task CanIncludeUserRolesTest() + { + // Arrange + var userManager = _builder.ApplicationServices.GetRequiredService>(); + var roleManager = _builder.ApplicationServices.GetRequiredService>(); + var dbContext = _builder.ApplicationServices.GetRequiredService(); + + const string roleName = "Admin"; + for (var i = 0; i < 10; i++) + IdentityResultAssert.IsSuccess(await roleManager.CreateAsync(new IdentityRole(roleName + i))); + var username = "user" + new Random().Next(); + var user = new IdentityUser {UserName = username}; + IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user)); + + for (var i = 0; i < 10; i++) + IdentityResultAssert.IsSuccess(await userManager.AddToRoleAsync(user, roleName + i)); + + user = dbContext.Users.LoadWith(x => x.Roles).FirstOrDefault(x => x.UserName == username); + + // Assert + Assert.NotNull(user); + Assert.NotNull(user.Roles); + Assert.Equal(10, user.Roles.Count()); + + for (var i = 0; i < 10; i++) + { + var role = dbContext.Roles.LoadWith(r => r.Users).FirstOrDefault(r => r.Name == roleName + i); + Assert.NotNull(role); + Assert.NotNull(role.Users); + Assert.Equal(1, role.Users.Count()); + } + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task CanIncludeRoleClaimsTest() + { + // Arrange + var roleManager = _builder.ApplicationServices.GetRequiredService>(); + var dbContext = _builder.ApplicationServices.GetRequiredService(); + + var role = new IdentityRole("Admin"); + + IdentityResultAssert.IsSuccess(await roleManager.CreateAsync(role)); + + for (var i = 0; i < 10; i++) + IdentityResultAssert.IsSuccess(await roleManager.AddClaimAsync(role, new Claim("foo" + i, "bar" + i))); + + role = dbContext.Roles.LoadWith(x => x.Claims).FirstOrDefault(x => x.Name == "Admin"); + + // Assert + Assert.NotNull(role); + Assert.NotNull(role.Claims); + Assert.Equal(10, role.Claims.Count()); + } + } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/MiscTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/MiscTest.cs index 83a7e80d5..6cd70a974 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/MiscTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/MiscTest.cs @@ -1,14 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Data.SqlClient; -using System.Linq; -using System.Threading.Tasks; +using System.Data.SqlClient; using Xunit; namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test { - public class MiscTest - { + public class MiscTest + { [Fact] public void SqlServerConnectionStringBuilderTest() { @@ -30,4 +26,4 @@ public void SqlServerConnectionStringBuilderTest() Assert.Contains("Password12!", csb.ConnectionString); } } -} +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/SqlStoreTestBase.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/SqlStoreTestBase.cs index f9964867a..e49dbd1ab 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/SqlStoreTestBase.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/SqlStoreTestBase.cs @@ -2,7 +2,6 @@ // 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.Data.SqlClient; using System.Linq; using System.Linq.Expressions; @@ -10,7 +9,6 @@ using System.Threading.Tasks; using LinqToDB; using LinqToDB.Data; -using LinqToDB.DataProvider; using LinqToDB.DataProvider.SqlServer; using LinqToDB.Identity; using Microsoft.AspNetCore.Identity.Test; @@ -21,350 +19,365 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test { - public abstract class SqlStoreTestBase : UserManagerTestBase, IClassFixture - where TUser : IdentityUser, new() - where TRole : IdentityRole, new() - where TKey : IEquatable + public abstract class SqlStoreTestBase : UserManagerTestBase, + IClassFixture + where TUser : IdentityUser, new() + where TRole : IdentityRole, new() + where TKey : IEquatable { private readonly ScratchDatabaseFixture _fixture; - protected SqlStoreTestBase(ScratchDatabaseFixture fixture) - { - _fixture = fixture; - } - - protected override bool ShouldSkipDbTests() - { - return TestPlatformHelper.IsMono || !TestPlatformHelper.IsWindows; - } - - //public class TestDbContext : IdentityDataConnection { - // public TestDbContext() : base() { } - - // public TestDbContext(string configurationString) : base(configurationString) - // { - // } - //} - - protected override TUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "", - bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false) - { - return new TUser - { - UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()), - Email = email, - PhoneNumber = phoneNumber, - LockoutEnabled = lockoutEnabled, - LockoutEnd = lockoutEnd - }; - } - - protected override TRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false) - { - var roleName = useRoleNamePrefixAsRoleName ? roleNamePrefix : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid()); - return new TRole() { Name = roleName }; - } - - protected override Expression> RoleNameEqualsPredicate(string roleName) => r => r.Name == roleName; - - protected override Expression> UserNameEqualsPredicate(string userName) => u => u.UserName == userName; - - protected override Expression> RoleNameStartsWithPredicate(string roleName) => r => r.Name.StartsWith(roleName); - - protected override Expression> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName); - - - public TestConnectionFactory CreateContext() - { + protected SqlStoreTestBase(ScratchDatabaseFixture fixture) + { + _fixture = fixture; + } + + protected override bool ShouldSkipDbTests() + { + return TestPlatformHelper.IsMono || !TestPlatformHelper.IsWindows; + } + + //public class TestDbContext : IdentityDataConnection { + // public TestDbContext() : base() { } + + // public TestDbContext(string configurationString) : base(configurationString) + // { + // } + //} + + protected override TUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "", + bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), + bool useNamePrefixAsUserName = false) + { + return new TUser + { + UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()), + Email = email, + PhoneNumber = phoneNumber, + LockoutEnabled = lockoutEnabled, + LockoutEnd = lockoutEnd + }; + } + + protected override TRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false) + { + var roleName = useRoleNamePrefixAsRoleName + ? roleNamePrefix + : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid()); + return new TRole {Name = roleName}; + } + + protected override Expression> RoleNameEqualsPredicate(string roleName) + { + return r => r.Name == roleName; + } + + protected override Expression> UserNameEqualsPredicate(string userName) + { + return u => u.UserName == userName; + } + + protected override Expression> RoleNameStartsWithPredicate(string roleName) + { + return r => r.Name.StartsWith(roleName); + } + + protected override Expression> UserNameStartsWithPredicate(string userName) + { + return u => u.UserName.StartsWith(userName); + } + + + public TestConnectionFactory CreateContext() + { //throw new NotImplementedException(); - //var db = DbUtil.Create(_fixture.ConnectionString); - //db.Database.EnsureCreated(); - //return db; + //var db = DbUtil.Create(_fixture.ConnectionString); + //db.Database.EnsureCreated(); + //return db; - var factory = new TestConnectionFactory(new SqlServerDataProvider("*", SqlServerVersion.v2012), "Test", - _fixture.ConnectionString); + var factory = new TestConnectionFactory(new SqlServerDataProvider("*", SqlServerVersion.v2012), "Test", + _fixture.ConnectionString); CreateTables(factory, _fixture.ConnectionString); return factory; - } + } protected override TestConnectionFactory CreateTestContext() - { - return CreateContext(); - } - - protected override void AddUserStore(IServiceCollection services, TestConnectionFactory context = null) - { - services.AddSingleton>(new UserStore(CreateTestContext())); - } - - protected override void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null) - { - services.AddSingleton>(new RoleStore(CreateTestContext())); - } - - protected override void SetUserPasswordHash(TUser user, string hashedPassword) - { - user.PasswordHash = hashedPassword; - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public void EnsureDefaultSchema() - { - VerifyDefaultSchema(CreateContext().GetConnection()); - } - - internal static void VerifyDefaultSchema(DataConnection dbContext) - { - var sqlConn = dbContext.Connection; - - using (var db = new SqlConnection(sqlConn.ConnectionString)) - { - var ms = dbContext.MappingSchema; - var u = ms.GetEntityDescriptor(typeof(TUser)); - var r = ms.GetEntityDescriptor(typeof(TRole)); - var ur = ms.GetEntityDescriptor(typeof(IdentityUserRole)); - var uc = ms.GetEntityDescriptor(typeof(IdentityUserClaim)); - var ul = ms.GetEntityDescriptor(typeof(IdentityUserLogin)); - var ut = ms.GetEntityDescriptor(typeof(IdentityUserToken)); - - - db.Open(); - Assert.True(VerifyColumns(db, u.TableName, "Id", "UserName", "Email", "PasswordHash", "SecurityStamp", - "EmailConfirmed", "PhoneNumber", "PhoneNumberConfirmed", "TwoFactorEnabled", "LockoutEnabled", - "LockoutEnd", "AccessFailedCount", "ConcurrencyStamp", "NormalizedUserName", "NormalizedEmail")); - Assert.True(VerifyColumns(db, r.TableName, "Id", "Name", "NormalizedName", "ConcurrencyStamp")); - Assert.True(VerifyColumns(db, ur.TableName, "UserId", "RoleId")); - Assert.True(VerifyColumns(db, uc.TableName, "Id", "UserId", "ClaimType", "ClaimValue")); - Assert.True(VerifyColumns(db, ul.TableName, "UserId", "ProviderKey", "LoginProvider", "ProviderDisplayName")); - Assert.True(VerifyColumns(db, ut.TableName, "UserId", "LoginProvider", "Name", "Value")); - - db.Close(); - } - } - - internal static bool VerifyColumns(SqlConnection conn, string table, params string[] columns) - { - var count = 0; - using ( - var command = - new SqlCommand("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME=@Table", conn)) - { - command.Parameters.Add(new SqlParameter("Table", table)); - using (var reader = command.ExecuteReader()) - { - while (reader.Read()) - { - count++; - if (!columns.Contains(reader.GetString(0))) - { - return false; - } - } - return count == columns.Length; - } - } - } - - internal static void VerifyIndex(SqlConnection conn, string table, string index, bool isUnique = false) - { - using ( - var command = - new SqlCommand( - "SELECT COUNT(*) FROM sys.indexes where NAME=@Index AND object_id = OBJECT_ID(@Table) AND is_unique = @Unique", conn)) - { - command.Parameters.Add(new SqlParameter("Index", index)); - command.Parameters.Add(new SqlParameter("Table", table)); - command.Parameters.Add(new SqlParameter("Unique", isUnique)); - using (var reader = command.ExecuteReader()) - { - Assert.True(reader.Read()); - Assert.True(reader.GetInt32(0) > 0); - } - } - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task DeleteRoleNonEmptySucceedsTest() - { - // Need fail if not empty? - var context = CreateTestContext(); - var userMgr = CreateManager(context); - var roleMgr = CreateRoleManager(context); - 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.Equal(1, roles.Count()); - 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.Equal(0, roles.Count()); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - 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.Equal(1, roles.Count()); - - IdentityResultAssert.IsSuccess(await userMgr.DeleteAsync(user)); - IdentityResultAssert.IsSuccess(await roleMgr.DeleteAsync(role)); - - roles = await userMgr.GetRolesAsync(user); - Assert.Equal(0, roles.Count()); - } - - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public void CanCreateUserUsingEF() - { - using (var db = CreateContext().GetConnection()) - { - var user = CreateTestUser(); - db.Insert(user); + { + return CreateContext(); + } + + protected override void AddUserStore(IServiceCollection services, TestConnectionFactory context = null) + { + services.AddSingleton>( + new UserStore(CreateTestContext())); + } + + protected override void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null) + { + services.AddSingleton>( + new RoleStore(CreateTestContext())); + } + + protected override void SetUserPasswordHash(TUser user, string hashedPassword) + { + user.PasswordHash = hashedPassword; + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public void EnsureDefaultSchema() + { + VerifyDefaultSchema(CreateContext().GetConnection()); + } + + internal static void VerifyDefaultSchema(DataConnection dbContext) + { + var sqlConn = dbContext.Connection; + + using (var db = new SqlConnection(sqlConn.ConnectionString)) + { + var ms = dbContext.MappingSchema; + var u = ms.GetEntityDescriptor(typeof(TUser)); + var r = ms.GetEntityDescriptor(typeof(TRole)); + var ur = ms.GetEntityDescriptor(typeof(IdentityUserRole)); + var uc = ms.GetEntityDescriptor(typeof(IdentityUserClaim)); + var ul = ms.GetEntityDescriptor(typeof(IdentityUserLogin)); + var ut = ms.GetEntityDescriptor(typeof(IdentityUserToken)); + + + db.Open(); + Assert.True(VerifyColumns(db, u.TableName, "Id", "UserName", "Email", "PasswordHash", "SecurityStamp", + "EmailConfirmed", "PhoneNumber", "PhoneNumberConfirmed", "TwoFactorEnabled", "LockoutEnabled", + "LockoutEnd", "AccessFailedCount", "ConcurrencyStamp", "NormalizedUserName", "NormalizedEmail")); + Assert.True(VerifyColumns(db, r.TableName, "Id", "Name", "NormalizedName", "ConcurrencyStamp")); + Assert.True(VerifyColumns(db, ur.TableName, "UserId", "RoleId")); + Assert.True(VerifyColumns(db, uc.TableName, "Id", "UserId", "ClaimType", "ClaimValue")); + Assert.True(VerifyColumns(db, ul.TableName, "UserId", "ProviderKey", "LoginProvider", "ProviderDisplayName")); + Assert.True(VerifyColumns(db, ut.TableName, "UserId", "LoginProvider", "Name", "Value")); + + db.Close(); + } + } + + internal static bool VerifyColumns(SqlConnection conn, string table, params string[] columns) + { + var count = 0; + using ( + var command = + new SqlCommand("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME=@Table", conn)) + { + command.Parameters.Add(new SqlParameter("Table", table)); + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + count++; + if (!columns.Contains(reader.GetString(0))) + return false; + } + return count == columns.Length; + } + } + } + + internal static void VerifyIndex(SqlConnection conn, string table, string index, bool isUnique = false) + { + using ( + var command = + new SqlCommand( + "SELECT COUNT(*) FROM sys.indexes where NAME=@Index AND object_id = OBJECT_ID(@Table) AND is_unique = @Unique", + conn)) + { + command.Parameters.Add(new SqlParameter("Index", index)); + command.Parameters.Add(new SqlParameter("Table", table)); + command.Parameters.Add(new SqlParameter("Unique", isUnique)); + using (var reader = command.ExecuteReader()) + { + Assert.True(reader.Read()); + Assert.True(reader.GetInt32(0) > 0); + } + } + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task DeleteRoleNonEmptySucceedsTest() + { + // Need fail if not empty? + var context = CreateTestContext(); + var userMgr = CreateManager(context); + var roleMgr = CreateRoleManager(context); + var roleName = "delete" + Guid.NewGuid(); + var role = CreateTestRole(roleName, 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.Equal(1, roles.Count()); + 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.Equal(0, roles.Count()); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task DeleteUserRemovesFromRoleTest() + { + // Need fail if not empty? + var userMgr = CreateManager(); + var roleMgr = CreateRoleManager(); + var roleName = "deleteUserRemove" + Guid.NewGuid(); + var role = CreateTestRole(roleName, 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.Equal(1, roles.Count()); + + IdentityResultAssert.IsSuccess(await userMgr.DeleteAsync(user)); + IdentityResultAssert.IsSuccess(await roleMgr.DeleteAsync(role)); + + roles = await userMgr.GetRolesAsync(user); + Assert.Equal(0, roles.Count()); + } + + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public void CanCreateUserUsingEF() + { + using (var db = CreateContext().GetConnection()) + { + var user = CreateTestUser(); + db.Insert(user); Assert.True(db.GetTable().Any(u => u.UserName == user.UserName)); - Assert.NotNull(db.GetTable().FirstOrDefault(u => u.UserName == user.UserName)); - } - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - 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 context = CreateContext(); - var manager = CreateManager(context); - var role = CreateRoleManager(context); - 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)); - } - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task LoadFromDbFindByIdTest() - { - var user = CreateTestUser(); - await LazyLoadTestSetup(user); - - var factory = CreateContext(); - var manager = CreateManager(factory); - - 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); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task LoadFromDbFindByNameTest() - { - var db = CreateContext(); - var user = CreateTestUser(); - await LazyLoadTestSetup(user); - - 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); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task LoadFromDbFindByLoginTest() - { - var db = CreateContext(); - var user = CreateTestUser(); - await LazyLoadTestSetup(user); - - 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); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task LoadFromDbFindByEmailTest() - { - var db = CreateContext(); - var user = CreateTestUser(); - user.Email = "fooz@fizzy.pop"; - await LazyLoadTestSetup(user); - - 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); - } - - } + Assert.NotNull(db.GetTable().FirstOrDefault(u => u.UserName == user.UserName)); + } + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + 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 context = CreateContext(); + var manager = CreateManager(context); + var role = CreateRoleManager(context); + var admin = CreateTestRole("Admin" + Guid.NewGuid()); + var local = CreateTestRole("Local" + Guid.NewGuid()); + 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)); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task LoadFromDbFindByIdTest() + { + var user = CreateTestUser(); + await LazyLoadTestSetup(user); + + var factory = CreateContext(); + var manager = CreateManager(factory); + + 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); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task LoadFromDbFindByNameTest() + { + var db = CreateContext(); + var user = CreateTestUser(); + await LazyLoadTestSetup(user); + + 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); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task LoadFromDbFindByLoginTest() + { + var db = CreateContext(); + var user = CreateTestUser(); + await LazyLoadTestSetup(user); + + 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); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task LoadFromDbFindByEmailTest() + { + var db = CreateContext(); + var user = CreateTestUser(); + user.Email = "fooz@fizzy.pop"; + await LazyLoadTestSetup(user); + + 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); + } + } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreGuidKeyTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreGuidKeyTest.cs index 52ef702bb..693144b40 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreGuidKeyTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreGuidKeyTest.cs @@ -7,53 +7,56 @@ using LinqToDB.Identity; using Microsoft.AspNetCore.Identity.Test; using Microsoft.Extensions.DependencyInjection; -using Xunit; namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test { - public class GuidUser : IdentityUser - { - public GuidUser() - { - Id = Guid.NewGuid(); - UserName = Id.ToString(); - } - } - - public class GuidRole : IdentityRole - { - public GuidRole() - { - Id = Guid.NewGuid(); - Name = Id.ToString(); - } - } - - public class UserStoreGuidTest : SqlStoreTestBase - { - public UserStoreGuidTest(ScratchDatabaseFixture fixture) - : base(fixture) - { - } - - public class ApplicationUserStore : UserStore - { - public ApplicationUserStore(IConnectionFactory factory) : base(factory) { } - } - - public class ApplicationRoleStore : RoleStore - { - public ApplicationRoleStore(IConnectionFactory factory) : base(factory) { } - } - - protected override void AddUserStore(IServiceCollection services, TestConnectionFactory context = null) - { - services.AddSingleton>(new ApplicationUserStore(context ?? CreateTestContext())); - } - - protected override void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null) - { - services.AddSingleton>(new ApplicationRoleStore(context ?? CreateTestContext())); - } - } + public class GuidUser : IdentityUser + { + public GuidUser() + { + Id = Guid.NewGuid(); + UserName = Id.ToString(); + } + } + + public class GuidRole : IdentityRole + { + public GuidRole() + { + Id = Guid.NewGuid(); + Name = Id.ToString(); + } + } + + public class UserStoreGuidTest : SqlStoreTestBase + { + public UserStoreGuidTest(ScratchDatabaseFixture fixture) + : base(fixture) + { + } + + protected override void AddUserStore(IServiceCollection services, TestConnectionFactory context = null) + { + services.AddSingleton>(new ApplicationUserStore(context ?? CreateTestContext())); + } + + protected override void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null) + { + services.AddSingleton>(new ApplicationRoleStore(context ?? CreateTestContext())); + } + + public class ApplicationUserStore : UserStore + { + public ApplicationUserStore(IConnectionFactory factory) : base(factory) + { + } + } + + public class ApplicationRoleStore : RoleStore + { + public ApplicationRoleStore(IConnectionFactory factory) : base(factory) + { + } + } + } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreIntKeyTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreIntKeyTest.cs index 01bb5e701..eb872ef72 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreIntKeyTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreIntKeyTest.cs @@ -6,31 +6,33 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test { - public class IntUser : IdentityUser - { - private static volatile int _id = 0; - public IntUser() - { - Id = ++_id; - UserName = Guid.NewGuid().ToString(); - } - } + public class IntUser : IdentityUser + { + private static volatile int _id; - public class IntRole : IdentityRole - { - private static volatile int _id = 0; - public IntRole() - { - Id = ++_id; - Name = Guid.NewGuid().ToString(); - } - } + public IntUser() + { + Id = ++_id; + UserName = Guid.NewGuid().ToString(); + } + } - public class UserStoreIntTest : SqlStoreTestBase - { - public UserStoreIntTest(ScratchDatabaseFixture fixture) - : base(fixture) - { - } - } + public class IntRole : IdentityRole + { + private static volatile int _id; + + public IntRole() + { + Id = ++_id; + Name = Guid.NewGuid().ToString(); + } + } + + public class UserStoreIntTest : SqlStoreTestBase + { + public UserStoreIntTest(ScratchDatabaseFixture fixture) + : base(fixture) + { + } + } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreStringKeyTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreStringKeyTest.cs index d32c18670..45eb9f65f 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreStringKeyTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreStringKeyTest.cs @@ -8,35 +8,35 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test { - public class StringUser : IdentityUser - { + public class StringUser : IdentityUser + { + public StringUser() + { + Id = Guid.NewGuid().ToString(); + UserName = Id; + } + [Column(DataType = DataType.VarChar, Length = 36, IsPrimaryKey = true, SkipOnUpdate = true, CanBeNull = false)] - public override string Id { get; set; } + public override string Id { get; set; } + } - public StringUser() - { - Id = Guid.NewGuid().ToString(); - UserName = Id; - } - } + public class StringRole : IdentityRole + { + public StringRole() + { + Id = Guid.NewGuid().ToString(); + Name = Id; + } - public class StringRole : IdentityRole - { [Column(DataType = DataType.VarChar, Length = 36, IsPrimaryKey = true, SkipOnUpdate = true, CanBeNull = false)] - public override string Id { get; set; } - - public StringRole() - { - Id = Guid.NewGuid().ToString(); - Name = Id; - } - } + public override string Id { get; set; } + } - public class UserStoreStringKeyTest : SqlStoreTestBase - { - public UserStoreStringKeyTest(ScratchDatabaseFixture fixture) - : base(fixture) - { - } - } + public class UserStoreStringKeyTest : SqlStoreTestBase + { + public UserStoreStringKeyTest(ScratchDatabaseFixture fixture) + : base(fixture) + { + } + } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreTest.cs index e60256082..d1fdeb0fe 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreTest.cs @@ -10,49 +10,51 @@ using LinqToDB.DataProvider.SqlServer; using LinqToDB.Identity; using Microsoft.AspNetCore.Identity.Test; -using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing; +using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.DependencyInjection; using Xunit; namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test { - public class UserStoreTest : UserManagerTestBase, IClassFixture - { - private readonly ScratchDatabaseFixture _fixture; - - public UserStoreTest(ScratchDatabaseFixture fixture) - { - _fixture = fixture; - } - - protected override bool ShouldSkipDbTests() - => TestPlatformHelper.IsMono || !TestPlatformHelper.IsWindows; - - //public class ApplicationDbContext : IdentityDataConnection - //{ - // public ApplicationDbContext() : base() - // { } - //} - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public void CanCreateUserUsingEF() - { - using (var db = CreateContext().GetConnection()) - { - var guid = Guid.NewGuid().ToString(); - db.Insert(new IdentityUser { Id = guid, UserName = guid }); + public class UserStoreTest : UserManagerTestBase, IClassFixture + { + public UserStoreTest(ScratchDatabaseFixture fixture) + { + _fixture = fixture; + } + + private readonly ScratchDatabaseFixture _fixture; + + protected override bool ShouldSkipDbTests() + { + return TestPlatformHelper.IsMono || !TestPlatformHelper.IsWindows; + } + + //public class ApplicationDbContext : IdentityDataConnection + //{ + // public ApplicationDbContext() : base() + // { } + //} + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public void CanCreateUserUsingEF() + { + using (var db = CreateContext().GetConnection()) + { + var guid = Guid.NewGuid().ToString(); + db.Insert(new IdentityUser {Id = guid, UserName = guid}); Assert.True(db.GetTable().Any(u => u.UserName == guid)); - Assert.NotNull(db.GetTable().FirstOrDefault(u => u.UserName == guid)); - } - } + Assert.NotNull(db.GetTable().FirstOrDefault(u => u.UserName == guid)); + } + } - public TestConnectionFactory CreateContext(bool delete = false) - { + public TestConnectionFactory CreateContext(bool delete = false) + { var factory = new TestConnectionFactory(new SqlServerDataProvider("*", SqlServerVersion.v2012), "Test", _fixture.ConnectionString); @@ -62,348 +64,377 @@ public TestConnectionFactory CreateContext(bool delete = false) } protected override TestConnectionFactory CreateTestContext() - { - return CreateContext(); - } - - public void EnsureDatabase() - { - CreateContext(); - } - - // public ApplicationDbContext CreateAppContext() - // { - //throw new NotImplementedException(); - // //var db = DbUtil.Create(_fixture.ConnectionString); - // //db.Database.EnsureCreated(); - // //return db; - // } - - protected override void AddUserStore(IServiceCollection services, TestConnectionFactory context = null) - { - services.AddSingleton>(new UserStore(context ?? CreateTestContext())); - } - - protected override void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null) - { - services.AddSingleton>(new RoleStore(context ?? CreateTestContext())); - } - - [Fact] - public async Task SqlUserStoreMethodsThrowWhenDisposedTest() - { - var store = new UserStore(CreateTestContext()); - store.Dispose(); - await Assert.ThrowsAsync(async () => await store.AddClaimsAsync(null, null)); - await Assert.ThrowsAsync(async () => await store.AddLoginAsync(null, null)); - await Assert.ThrowsAsync(async () => await store.AddToRoleAsync(null, null)); - await Assert.ThrowsAsync(async () => await store.GetClaimsAsync(null)); - await Assert.ThrowsAsync(async () => await store.GetLoginsAsync(null)); - await Assert.ThrowsAsync(async () => await store.GetRolesAsync(null)); - await Assert.ThrowsAsync(async () => await store.IsInRoleAsync(null, null)); - await Assert.ThrowsAsync(async () => await store.RemoveClaimsAsync(null, null)); - await Assert.ThrowsAsync(async () => await store.RemoveLoginAsync(null, null, null)); - await Assert.ThrowsAsync( - async () => await store.RemoveFromRoleAsync(null, null)); - await Assert.ThrowsAsync(async () => await store.RemoveClaimsAsync(null, null)); - await Assert.ThrowsAsync(async () => await store.ReplaceClaimAsync(null, null, null)); - await Assert.ThrowsAsync(async () => await store.FindByLoginAsync(null, null)); - await Assert.ThrowsAsync(async () => await store.FindByIdAsync(null)); - await Assert.ThrowsAsync(async () => await store.FindByNameAsync(null)); - await Assert.ThrowsAsync(async () => await store.CreateAsync(null)); - await Assert.ThrowsAsync(async () => await store.UpdateAsync(null)); - await Assert.ThrowsAsync(async () => await store.DeleteAsync(null)); - await Assert.ThrowsAsync( - async () => await store.SetEmailConfirmedAsync(null, true)); - await Assert.ThrowsAsync(async () => await store.GetEmailConfirmedAsync(null)); - await Assert.ThrowsAsync( - async () => await store.SetPhoneNumberConfirmedAsync(null, true)); - await Assert.ThrowsAsync( - async () => await store.GetPhoneNumberConfirmedAsync(null)); - } - - [Fact] - public async Task UserStorePublicNullCheckTest() - { - Assert.Throws("factory", () => new UserStore(null)); - var store = new UserStore(CreateTestContext()); - await Assert.ThrowsAsync("user", async () => await store.GetUserIdAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.GetUserNameAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.SetUserNameAsync(null, null)); - await Assert.ThrowsAsync("user", async () => await store.CreateAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.UpdateAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.DeleteAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.AddClaimsAsync(null, null)); - await Assert.ThrowsAsync("user", async () => await store.ReplaceClaimAsync(null, null, null)); - await Assert.ThrowsAsync("user", async () => await store.RemoveClaimsAsync(null, null)); - await Assert.ThrowsAsync("user", async () => await store.GetClaimsAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.GetLoginsAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.GetRolesAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.AddLoginAsync(null, null)); - await - Assert.ThrowsAsync("user", async () => await store.RemoveLoginAsync(null, null, null)); - await Assert.ThrowsAsync("user", async () => await store.AddToRoleAsync(null, null)); - await - Assert.ThrowsAsync("user", - async () => await store.RemoveFromRoleAsync(null, null)); - await Assert.ThrowsAsync("user", async () => await store.IsInRoleAsync(null, null)); - await Assert.ThrowsAsync("user", async () => await store.GetPasswordHashAsync(null)); - await - Assert.ThrowsAsync("user", - async () => await store.SetPasswordHashAsync(null, null)); - await Assert.ThrowsAsync("user", async () => await store.GetSecurityStampAsync(null)); - await Assert.ThrowsAsync("user", - async () => await store.SetSecurityStampAsync(null, null)); - await Assert.ThrowsAsync("login", async () => await store.AddLoginAsync(new IdentityUser("fake"), null)); - await Assert.ThrowsAsync("claims", - async () => await store.AddClaimsAsync(new IdentityUser("fake"), null)); - await Assert.ThrowsAsync("claims", - async () => await store.RemoveClaimsAsync(new IdentityUser("fake"), null)); - await Assert.ThrowsAsync("user", async () => await store.GetEmailConfirmedAsync(null)); - await Assert.ThrowsAsync("user", - async () => await store.SetEmailConfirmedAsync(null, true)); - await Assert.ThrowsAsync("user", async () => await store.GetEmailAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.SetEmailAsync(null, null)); - await Assert.ThrowsAsync("user", async () => await store.GetPhoneNumberAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.SetPhoneNumberAsync(null, null)); - await Assert.ThrowsAsync("user", - async () => await store.GetPhoneNumberConfirmedAsync(null)); - await Assert.ThrowsAsync("user", - async () => await store.SetPhoneNumberConfirmedAsync(null, true)); - await Assert.ThrowsAsync("user", async () => await store.GetTwoFactorEnabledAsync(null)); - await Assert.ThrowsAsync("user", - async () => await store.SetTwoFactorEnabledAsync(null, true)); - await Assert.ThrowsAsync("user", async () => await store.GetAccessFailedCountAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.GetLockoutEnabledAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.SetLockoutEnabledAsync(null, false)); - await Assert.ThrowsAsync("user", async () => await store.GetLockoutEndDateAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.SetLockoutEndDateAsync(null, new DateTimeOffset())); - await Assert.ThrowsAsync("user", async () => await store.ResetAccessFailedCountAsync(null)); - await Assert.ThrowsAsync("user", async () => await store.IncrementAccessFailedCountAsync(null)); - await Assert.ThrowsAsync("normalizedRoleName", async () => await store.AddToRoleAsync(new IdentityUser("fake"), null)); - await Assert.ThrowsAsync("normalizedRoleName", async () => await store.RemoveFromRoleAsync(new IdentityUser("fake"), null)); - await Assert.ThrowsAsync("normalizedRoleName", async () => await store.IsInRoleAsync(new IdentityUser("fake"), null)); - await Assert.ThrowsAsync("normalizedRoleName", async () => await store.AddToRoleAsync(new IdentityUser("fake"), "")); - await Assert.ThrowsAsync("normalizedRoleName", async () => await store.RemoveFromRoleAsync(new IdentityUser("fake"), "")); - await Assert.ThrowsAsync("normalizedRoleName", async () => await store.IsInRoleAsync(new IdentityUser("fake"), "")); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task CanCreateUsingManager() - { - var manager = CreateManager(); - var guid = Guid.NewGuid().ToString(); - var user = new IdentityUser { UserName = "New" + guid }; - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - IdentityResultAssert.IsSuccess(await manager.DeleteAsync(user)); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task TwoUsersSamePasswordDifferentHash() - { - var manager = CreateManager(); - var userA = new IdentityUser(Guid.NewGuid().ToString()); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(userA, "password")); - var userB = new IdentityUser(Guid.NewGuid().ToString()); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(userB, "password")); - - Assert.NotEqual(userA.PasswordHash, userB.PasswordHash); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task AddUserToUnknownRoleFails() - { - var manager = CreateManager(); - var u = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(u)); - await Assert.ThrowsAsync( - async () => await manager.AddToRoleAsync(u, "bogus")); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task ConcurrentUpdatesWillFail() - { - var user = CreateTestUser(); - var factory = CreateContext(); - - var manager = CreateManager(factory); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - - var manager1 = CreateManager(factory); - var manager2 = CreateManager(factory); - 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()); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task ConcurrentUpdatesWillFailWithDetachedUser() - { - var user = CreateTestUser(); - var factory = CreateContext(); - var manager = CreateManager(factory); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - - var manager1 = CreateManager(factory); - var manager2 = CreateManager(factory); - 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()); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task DeleteAModifiedUserWillFail() - { - var user = CreateTestUser(); - var factory = CreateContext(); - var manager = CreateManager(factory); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var manager1 = CreateManager(factory); - var manager2 = CreateManager(factory); - 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()); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task ConcurrentRoleUpdatesWillFail() - { - var role = new IdentityRole(Guid.NewGuid().ToString()); - var factory = CreateContext(); - - var manager = CreateRoleManager(factory); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(role)); - var manager1 = CreateRoleManager(factory); - var manager2 = CreateRoleManager(factory); - 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()); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task ConcurrentRoleUpdatesWillFailWithDetachedRole() - { - var role = new IdentityRole(Guid.NewGuid().ToString()); - var factory = CreateContext(); - var manager = CreateRoleManager(factory); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(role)); - var manager1 = CreateRoleManager(factory); - var manager2 = CreateRoleManager(factory); - 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()); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task DeleteAModifiedRoleWillFail() - { - var role = new IdentityRole(Guid.NewGuid().ToString()); - var factory = CreateContext(); - var manager = CreateRoleManager(factory); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(role)); - var manager1 = CreateRoleManager(factory); - var manager2 = CreateRoleManager(factory); - 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 IdentityUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "", - bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false) - { - return new IdentityUser - { - UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()), - Email = email, - PhoneNumber = phoneNumber, - LockoutEnabled = lockoutEnabled, - LockoutEnd = lockoutEnd - }; - } - - protected override IdentityRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false) - { - var roleName = useRoleNamePrefixAsRoleName ? roleNamePrefix : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid()); - return new IdentityRole(roleName); - } - - protected override void SetUserPasswordHash(IdentityUser user, string hashedPassword) - { - user.PasswordHash = hashedPassword; - } - - protected override Expression> UserNameEqualsPredicate(string userName) => u => u.UserName == userName; - - protected override Expression> RoleNameEqualsPredicate(string roleName) => r => r.Name == roleName; - - protected override Expression> RoleNameStartsWithPredicate(string roleName) => r => r.Name.StartsWith(roleName); - - protected override Expression> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName); - } - - public class ApplicationUser : IdentityUser { } + { + return CreateContext(); + } + + public void EnsureDatabase() + { + CreateContext(); + } + + // public ApplicationDbContext CreateAppContext() + // { + //throw new NotImplementedException(); + // //var db = DbUtil.Create(_fixture.ConnectionString); + // //db.Database.EnsureCreated(); + // //return db; + // } + + protected override void AddUserStore(IServiceCollection services, TestConnectionFactory context = null) + { + services.AddSingleton>( + new UserStore(context ?? CreateTestContext())); + } + + protected override void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null) + { + services.AddSingleton>( + new RoleStore(context ?? CreateTestContext())); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task CanCreateUsingManager() + { + var manager = CreateManager(); + var guid = Guid.NewGuid().ToString(); + var user = new IdentityUser {UserName = "New" + guid}; + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + IdentityResultAssert.IsSuccess(await manager.DeleteAsync(user)); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task TwoUsersSamePasswordDifferentHash() + { + var manager = CreateManager(); + var userA = new IdentityUser(Guid.NewGuid().ToString()); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(userA, "password")); + var userB = new IdentityUser(Guid.NewGuid().ToString()); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(userB, "password")); + + Assert.NotEqual(userA.PasswordHash, userB.PasswordHash); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task AddUserToUnknownRoleFails() + { + var manager = CreateManager(); + var u = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(u)); + await Assert.ThrowsAsync( + async () => await manager.AddToRoleAsync(u, "bogus")); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task ConcurrentUpdatesWillFail() + { + var user = CreateTestUser(); + var factory = CreateContext(); + + var manager = CreateManager(factory); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + + var manager1 = CreateManager(factory); + var manager2 = CreateManager(factory); + 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()); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task ConcurrentUpdatesWillFailWithDetachedUser() + { + var user = CreateTestUser(); + var factory = CreateContext(); + var manager = CreateManager(factory); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + + var manager1 = CreateManager(factory); + var manager2 = CreateManager(factory); + 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()); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task DeleteAModifiedUserWillFail() + { + var user = CreateTestUser(); + var factory = CreateContext(); + var manager = CreateManager(factory); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var manager1 = CreateManager(factory); + var manager2 = CreateManager(factory); + 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()); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task ConcurrentRoleUpdatesWillFail() + { + var role = new IdentityRole(Guid.NewGuid().ToString()); + var factory = CreateContext(); + + var manager = CreateRoleManager(factory); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(role)); + var manager1 = CreateRoleManager(factory); + var manager2 = CreateRoleManager(factory); + 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()); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task ConcurrentRoleUpdatesWillFailWithDetachedRole() + { + var role = new IdentityRole(Guid.NewGuid().ToString()); + var factory = CreateContext(); + var manager = CreateRoleManager(factory); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(role)); + var manager1 = CreateRoleManager(factory); + var manager2 = CreateRoleManager(factory); + 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()); + } + + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task DeleteAModifiedRoleWillFail() + { + var role = new IdentityRole(Guid.NewGuid().ToString()); + var factory = CreateContext(); + var manager = CreateRoleManager(factory); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(role)); + var manager1 = CreateRoleManager(factory); + var manager2 = CreateRoleManager(factory); + 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 IdentityUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "", + bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), + bool useNamePrefixAsUserName = false) + { + return new IdentityUser + { + UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()), + Email = email, + PhoneNumber = phoneNumber, + LockoutEnabled = lockoutEnabled, + LockoutEnd = lockoutEnd + }; + } + + protected override IdentityRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false) + { + var roleName = useRoleNamePrefixAsRoleName + ? roleNamePrefix + : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid()); + return new IdentityRole(roleName); + } + + protected override void SetUserPasswordHash(IdentityUser user, string hashedPassword) + { + user.PasswordHash = hashedPassword; + } + + protected override Expression> UserNameEqualsPredicate(string userName) + { + return u => u.UserName == userName; + } + + protected override Expression> RoleNameEqualsPredicate(string roleName) + { + return r => r.Name == roleName; + } + + protected override Expression> RoleNameStartsWithPredicate(string roleName) + { + return r => r.Name.StartsWith(roleName); + } + + protected override Expression> UserNameStartsWithPredicate(string userName) + { + return u => u.UserName.StartsWith(userName); + } + + [Fact] + public async Task SqlUserStoreMethodsThrowWhenDisposedTest() + { + var store = new UserStore(CreateTestContext()); + store.Dispose(); + await Assert.ThrowsAsync(async () => await store.AddClaimsAsync(null, null)); + await Assert.ThrowsAsync(async () => await store.AddLoginAsync(null, null)); + await Assert.ThrowsAsync(async () => await store.AddToRoleAsync(null, null)); + await Assert.ThrowsAsync(async () => await store.GetClaimsAsync(null)); + await Assert.ThrowsAsync(async () => await store.GetLoginsAsync(null)); + await Assert.ThrowsAsync(async () => await store.GetRolesAsync(null)); + await Assert.ThrowsAsync(async () => await store.IsInRoleAsync(null, null)); + await Assert.ThrowsAsync(async () => await store.RemoveClaimsAsync(null, null)); + await Assert.ThrowsAsync(async () => await store.RemoveLoginAsync(null, null, null)); + await Assert.ThrowsAsync( + async () => await store.RemoveFromRoleAsync(null, null)); + await Assert.ThrowsAsync(async () => await store.RemoveClaimsAsync(null, null)); + await Assert.ThrowsAsync(async () => await store.ReplaceClaimAsync(null, null, null)); + await Assert.ThrowsAsync(async () => await store.FindByLoginAsync(null, null)); + await Assert.ThrowsAsync(async () => await store.FindByIdAsync(null)); + await Assert.ThrowsAsync(async () => await store.FindByNameAsync(null)); + await Assert.ThrowsAsync(async () => await store.CreateAsync(null)); + await Assert.ThrowsAsync(async () => await store.UpdateAsync(null)); + await Assert.ThrowsAsync(async () => await store.DeleteAsync(null)); + await Assert.ThrowsAsync( + async () => await store.SetEmailConfirmedAsync(null, true)); + await Assert.ThrowsAsync(async () => await store.GetEmailConfirmedAsync(null)); + await Assert.ThrowsAsync( + async () => await store.SetPhoneNumberConfirmedAsync(null, true)); + await Assert.ThrowsAsync( + async () => await store.GetPhoneNumberConfirmedAsync(null)); + } + + [Fact] + public async Task UserStorePublicNullCheckTest() + { + Assert.Throws("factory", + () => new UserStore(null)); + var store = new UserStore(CreateTestContext()); + await Assert.ThrowsAsync("user", async () => await store.GetUserIdAsync(null)); + await Assert.ThrowsAsync("user", async () => await store.GetUserNameAsync(null)); + await Assert.ThrowsAsync("user", async () => await store.SetUserNameAsync(null, null)); + await Assert.ThrowsAsync("user", async () => await store.CreateAsync(null)); + await Assert.ThrowsAsync("user", async () => await store.UpdateAsync(null)); + await Assert.ThrowsAsync("user", async () => await store.DeleteAsync(null)); + await Assert.ThrowsAsync("user", async () => await store.AddClaimsAsync(null, null)); + await Assert.ThrowsAsync("user", async () => await store.ReplaceClaimAsync(null, null, null)); + await Assert.ThrowsAsync("user", async () => await store.RemoveClaimsAsync(null, null)); + await Assert.ThrowsAsync("user", async () => await store.GetClaimsAsync(null)); + await Assert.ThrowsAsync("user", async () => await store.GetLoginsAsync(null)); + await Assert.ThrowsAsync("user", async () => await store.GetRolesAsync(null)); + await Assert.ThrowsAsync("user", async () => await store.AddLoginAsync(null, null)); + await + Assert.ThrowsAsync("user", async () => await store.RemoveLoginAsync(null, null, null)); + await Assert.ThrowsAsync("user", async () => await store.AddToRoleAsync(null, null)); + await + Assert.ThrowsAsync("user", + async () => await store.RemoveFromRoleAsync(null, null)); + await Assert.ThrowsAsync("user", async () => await store.IsInRoleAsync(null, null)); + await Assert.ThrowsAsync("user", async () => await store.GetPasswordHashAsync(null)); + await + Assert.ThrowsAsync("user", + async () => await store.SetPasswordHashAsync(null, null)); + await Assert.ThrowsAsync("user", async () => await store.GetSecurityStampAsync(null)); + await Assert.ThrowsAsync("user", + async () => await store.SetSecurityStampAsync(null, null)); + await Assert.ThrowsAsync("login", + async () => await store.AddLoginAsync(new IdentityUser("fake"), null)); + await Assert.ThrowsAsync("claims", + async () => await store.AddClaimsAsync(new IdentityUser("fake"), null)); + await Assert.ThrowsAsync("claims", + async () => await store.RemoveClaimsAsync(new IdentityUser("fake"), null)); + await Assert.ThrowsAsync("user", async () => await store.GetEmailConfirmedAsync(null)); + await Assert.ThrowsAsync("user", + async () => await store.SetEmailConfirmedAsync(null, true)); + await Assert.ThrowsAsync("user", async () => await store.GetEmailAsync(null)); + await Assert.ThrowsAsync("user", async () => await store.SetEmailAsync(null, null)); + await Assert.ThrowsAsync("user", async () => await store.GetPhoneNumberAsync(null)); + await Assert.ThrowsAsync("user", async () => await store.SetPhoneNumberAsync(null, null)); + await Assert.ThrowsAsync("user", + async () => await store.GetPhoneNumberConfirmedAsync(null)); + await Assert.ThrowsAsync("user", + async () => await store.SetPhoneNumberConfirmedAsync(null, true)); + await Assert.ThrowsAsync("user", async () => await store.GetTwoFactorEnabledAsync(null)); + await Assert.ThrowsAsync("user", + async () => await store.SetTwoFactorEnabledAsync(null, true)); + await Assert.ThrowsAsync("user", async () => await store.GetAccessFailedCountAsync(null)); + await Assert.ThrowsAsync("user", async () => await store.GetLockoutEnabledAsync(null)); + await Assert.ThrowsAsync("user", async () => await store.SetLockoutEnabledAsync(null, false)); + await Assert.ThrowsAsync("user", async () => await store.GetLockoutEndDateAsync(null)); + await Assert.ThrowsAsync("user", + async () => await store.SetLockoutEndDateAsync(null, new DateTimeOffset())); + await Assert.ThrowsAsync("user", async () => await store.ResetAccessFailedCountAsync(null)); + await Assert.ThrowsAsync("user", + async () => await store.IncrementAccessFailedCountAsync(null)); + await Assert.ThrowsAsync("normalizedRoleName", + async () => await store.AddToRoleAsync(new IdentityUser("fake"), null)); + await Assert.ThrowsAsync("normalizedRoleName", + async () => await store.RemoveFromRoleAsync(new IdentityUser("fake"), null)); + await Assert.ThrowsAsync("normalizedRoleName", + async () => await store.IsInRoleAsync(new IdentityUser("fake"), null)); + await Assert.ThrowsAsync("normalizedRoleName", + async () => await store.AddToRoleAsync(new IdentityUser("fake"), "")); + await Assert.ThrowsAsync("normalizedRoleName", + async () => await store.RemoveFromRoleAsync(new IdentityUser("fake"), "")); + await Assert.ThrowsAsync("normalizedRoleName", + async () => await store.IsInRoleAsync(new IdentityUser("fake"), "")); + } + } + + public class ApplicationUser : IdentityUser + { + } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreWithGenericsTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreWithGenericsTest.cs index 445b089f4..59f10b5ec 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreWithGenericsTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreWithGenericsTest.cs @@ -18,347 +18,376 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test { - public class UserStoreWithGenericsTest : UserManagerTestBase, IClassFixture - { - private readonly ScratchDatabaseFixture _fixture; - - public UserStoreWithGenericsTest(ScratchDatabaseFixture fixture) - { - _fixture = fixture; - } - - public TestConnectionFactory CreateContext() - { - var factory = new TestConnectionFactory(new SqlServerDataProvider("*", SqlServerVersion.v2012), "UserStoreWithGenericsTest", + public class UserStoreWithGenericsTest : UserManagerTestBase, + IClassFixture + { + public UserStoreWithGenericsTest(ScratchDatabaseFixture fixture) + { + _fixture = fixture; + } + + private readonly ScratchDatabaseFixture _fixture; + + public TestConnectionFactory CreateContext() + { + var factory = new TestConnectionFactory(new SqlServerDataProvider("*", SqlServerVersion.v2012), + "UserStoreWithGenericsTest", _fixture.ConnectionString); CreateTables(factory, _fixture.ConnectionString); - factory.CreateTable(); - factory.CreateTable(); - factory.CreateTable(); - factory.CreateTable < IdentityUserTokenWithStuff>(); - factory.CreateTable(); - - - + factory.CreateTable(); + factory.CreateTable(); + factory.CreateTable(); + factory.CreateTable(); + factory.CreateTable(); return factory; - //var db = DbUtil.Create(_fixture.ConnectionString); - //db.Database.EnsureCreated(); - //return db; - } - - protected override TestConnectionFactory CreateTestContext() - { - return CreateContext(); - } - - protected override bool ShouldSkipDbTests() - { - return TestPlatformHelper.IsMono || !TestPlatformHelper.IsWindows; - } - - protected override void AddUserStore(IServiceCollection services, TestConnectionFactory context = null) - { - services.AddSingleton>(new UserStoreWithGenerics(context ?? CreateTestContext(), "TestContext")); - } - - protected override void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null) - { - services.AddSingleton>(new RoleStoreWithGenerics(context ?? CreateTestContext(), "TestContext")); - } - - protected override IdentityUserWithGenerics CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "", - bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false) - { - return new IdentityUserWithGenerics - { - UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()), - Email = email, - PhoneNumber = phoneNumber, - LockoutEnabled = lockoutEnabled, - LockoutEnd = lockoutEnd - }; - } - - protected override MyIdentityRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false) - { - var roleName = useRoleNamePrefixAsRoleName ? roleNamePrefix : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid()); - return new MyIdentityRole(roleName); - } - - protected override void SetUserPasswordHash(IdentityUserWithGenerics user, string hashedPassword) - { - user.PasswordHash = hashedPassword; - } - - protected override Expression> UserNameEqualsPredicate(string userName) => u => u.UserName == userName; - - protected override Expression> RoleNameEqualsPredicate(string roleName) => r => r.Name == roleName; - - protected override Expression> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName); - - protected override Expression> RoleNameStartsWithPredicate(string roleName) => r => r.Name.StartsWith(roleName); - - [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 - { - public static IEqualityComparer 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 : IdentityUser - { - public IdentityUserWithGenerics() - { - Id = Guid.NewGuid().ToString(); - } - } - - public class UserStoreWithGenerics : + //var db = DbUtil.Create(_fixture.ConnectionString); + //db.Database.EnsureCreated(); + //return db; + } + + protected override TestConnectionFactory CreateTestContext() + { + return CreateContext(); + } + + protected override bool ShouldSkipDbTests() + { + return TestPlatformHelper.IsMono || !TestPlatformHelper.IsWindows; + } + + protected override void AddUserStore(IServiceCollection services, TestConnectionFactory context = null) + { + services.AddSingleton>(new UserStoreWithGenerics(context ?? CreateTestContext(), + "TestContext")); + } + + protected override void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null) + { + services.AddSingleton>( + new RoleStoreWithGenerics(context ?? CreateTestContext(), "TestContext")); + } + + protected override IdentityUserWithGenerics CreateTestUser(string namePrefix = "", string email = "", + string phoneNumber = "", + bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), + bool useNamePrefixAsUserName = false) + { + return new IdentityUserWithGenerics + { + UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()), + Email = email, + PhoneNumber = phoneNumber, + LockoutEnabled = lockoutEnabled, + LockoutEnd = lockoutEnd + }; + } + + protected override MyIdentityRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false) + { + var roleName = useRoleNamePrefixAsRoleName + ? roleNamePrefix + : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid()); + return new MyIdentityRole(roleName); + } + + protected override void SetUserPasswordHash(IdentityUserWithGenerics user, string hashedPassword) + { + user.PasswordHash = hashedPassword; + } + + protected override Expression> UserNameEqualsPredicate(string userName) + { + return u => u.UserName == userName; + } + + protected override Expression> RoleNameEqualsPredicate(string roleName) + { + return r => r.Name == roleName; + } + + protected override Expression> UserNameStartsWithPredicate(string userName) + { + return u => u.UserName.StartsWith(userName); + } + + protected override Expression> RoleNameStartsWithPredicate(string roleName) + { + return r => r.Name.StartsWith(roleName); + } + + [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 (var 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 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); + var claim = new Claim("c", "b", "i"); + var oldClaim = userClaims.FirstOrDefault(); + IdentityResultAssert.IsSuccess(await manager.ReplaceClaimAsync(user, oldClaim, claim)); + var newUserClaims = await manager.GetClaimsAsync(user); + Assert.Equal(1, newUserClaims.Count); + var newClaim = newUserClaims.FirstOrDefault(); + Assert.Equal(claim.Type, newClaim.Type); + Assert.Equal(claim.Value, newClaim.Value); + Assert.Equal(claim.Issuer, newClaim.Issuer); + } + + [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 (var 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); + } + } + + public class ClaimEqualityComparer : IEqualityComparer + { + public static IEqualityComparer 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 : IdentityUser + { + public IdentityUserWithGenerics() + { + Id = Guid.NewGuid().ToString(); + } + } + + public class UserStoreWithGenerics : UserStore< - DataContext, - DataConnection, - IdentityUserWithGenerics, - MyIdentityRole, - string, - IdentityUserClaimWithIssuer, - IdentityUserRoleWithDate, - IdentityUserLoginWithContext, - IdentityUserTokenWithStuff, + DataContext, + DataConnection, + IdentityUserWithGenerics, + MyIdentityRole, + string, + IdentityUserClaimWithIssuer, + IdentityUserRoleWithDate, + IdentityUserLoginWithContext, + IdentityUserTokenWithStuff, IdentityRoleClaimWithIssuer> - { - public string LoginContext { get; set; } - - public UserStoreWithGenerics(IConnectionFactory fasctory, string loginContext) : base(fasctory) - { - 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 : RoleStore - { - private string _loginContext; - public RoleStoreWithGenerics(IConnectionFactory factory, string loginContext) : base(factory) - { - _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 - { - 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 - { - 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 - { - public DateTime Created { get; set; } - } - - public class MyIdentityRole : IdentityRole - { - public MyIdentityRole() : base() - { - Id = Guid.NewGuid().ToString(); - } - - public MyIdentityRole(string roleName) : this() - { - Name = roleName; - } - } - - public class IdentityUserTokenWithStuff : IdentityUserToken - { - public string Stuff { get; set; } - } - - public class IdentityUserLoginWithContext : IdentityUserLogin - { - public string Context { get; set; } - } - - //public class ContextWithGenerics : IdentityDataConnection - //{ - // public ContextWithGenerics() : base() { } - //} - - #endregion + { + public UserStoreWithGenerics(IConnectionFactory fasctory, + string loginContext) : base(fasctory) + { + LoginContext = loginContext; + } + + public string LoginContext { get; set; } + + 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 : RoleStore + { + private string _loginContext; + + public RoleStoreWithGenerics(IConnectionFactory factory, + string loginContext) : base(factory) + { + _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 + { + 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 + { + 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 + { + public DateTime Created { get; set; } + } + + public class MyIdentityRole : IdentityRole + { + public MyIdentityRole() + { + Id = Guid.NewGuid().ToString(); + } + + public MyIdentityRole(string roleName) : this() + { + Name = roleName; + } + } + + public class IdentityUserTokenWithStuff : IdentityUserToken + { + public string Stuff { get; set; } + } + + public class IdentityUserLoginWithContext : IdentityUserLogin + { + public string Context { get; set; } + } + + //public class ContextWithGenerics : IdentityDataConnection + //{ + // public ContextWithGenerics() : base() { } + //} + + #endregion } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/EntityFrameworkServiceBuilderExtension.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/EntityFrameworkServiceBuilderExtension.cs index fe7011c92..fb28125ad 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/EntityFrameworkServiceBuilderExtension.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/EntityFrameworkServiceBuilderExtension.cs @@ -4,9 +4,9 @@ namespace Microsoft.Extensions.DependencyInjection { - //public static class EntityFrameworkServiceBuilderExtension - //{ - // public static IServiceCollection ServiceCollection(this EntityFrameworkServicesBuilder services) - // => services.GetInfrastructure(); - //} -} + //public static class EntityFrameworkServiceBuilderExtension + //{ + // public static IServiceCollection ServiceCollection(this EntityFrameworkServicesBuilder services) + // => services.GetInfrastructure(); + //} +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/ScratchDatabaseFixture.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/ScratchDatabaseFixture.cs index 5a234a8c2..295b52a49 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/ScratchDatabaseFixture.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/ScratchDatabaseFixture.cs @@ -6,16 +6,16 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test { - public class ScratchDatabaseFixture : IDisposable - { - private SqlServerTestStore _testStore; - private SqlServerTestStore TestStore => _testStore ?? (_testStore = SqlServerTestStore.CreateScratch()); + public class ScratchDatabaseFixture : IDisposable + { + private SqlServerTestStore _testStore; + private SqlServerTestStore TestStore => _testStore ?? (_testStore = SqlServerTestStore.CreateScratch()); - public string ConnectionString => TestStore.Connection.ConnectionString; + public string ConnectionString => TestStore.Connection.ConnectionString; - public void Dispose() - { - _testStore?.Dispose(); - } - } + public void Dispose() + { + _testStore?.Dispose(); + } + } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/SqlServerTestStore.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/SqlServerTestStore.cs index d64561820..6e7794de6 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/SqlServerTestStore.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/SqlServerTestStore.cs @@ -9,166 +9,162 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.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) - { - var connectionString = CreateConnectionString("master"); - try - { - using (var master = new SqlConnection(connectionString)) - { - master.Open(); - Console.WriteLine(master.ConnectionString); - - using (var command = master.CreateCommand()) - { - command.CommandTimeout = CommandTimeout; - command.CommandText = $@"SELECT COUNT(*) FROM sys.databases WHERE name = N'{name}'"; - - return (int) command.ExecuteScalar() > 0; - } - } - } - catch (Exception ex) - { - throw new Exception(connectionString + " " + ex.Message, ex); - } - } - - 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}') + public class SqlServerTestStore : IDisposable + { + public const int CommandTimeout = 90; + private readonly string _name; + + private SqlConnection _connection; + private bool _deleteDatabase; + + private SqlServerTestStore(string name) + { + _name = name; + } + + public DbConnection Connection => _connection; + + public void Dispose() + { + _connection.Dispose(); + + if (_deleteDatabase) + DeleteDatabase(_name); + } + + public static string CreateConnectionString(string name) + { + var connStrBuilder = new SqlConnectionStringBuilder(TestEnvironment.Config["TestSqlServerDefaultConnectionString"]) + { + InitialCatalog = name + }; + + return connStrBuilder.ConnectionString; + } + + public static SqlServerTestStore CreateScratch(bool createDatabase = true) + { + return new SqlServerTestStore(GetScratchDbName()).CreateTransient(createDatabase); + } + + 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) + { + var connectionString = CreateConnectionString("master"); + try + { + using (var master = new SqlConnection(connectionString)) + { + master.Open(); + Console.WriteLine(master.ConnectionString); + + using (var command = master.CreateCommand()) + { + command.CommandTimeout = CommandTimeout; + command.CommandText = $@"SELECT COUNT(*) FROM sys.databases WHERE name = N'{name}'"; + + return (int) command.ExecuteScalar() > 0; + } + } + } + catch (Exception ex) + { + throw new Exception(connectionString + " " + ex.Message, ex); + } + } + + 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); - } - } - } -} + command.ExecuteNonQuery(); + } + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/TestEnvironment.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/TestEnvironment.cs index 6d069f38b..f8e12a399 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/TestEnvironment.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/Utilities/TestEnvironment.cs @@ -6,19 +6,19 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.Utilities { - public static class TestEnvironment - { - public static IConfiguration Config { get; } + public static class TestEnvironment + { + static TestEnvironment() + { + var configBuilder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("config.json", true) + .AddJsonFile("config.test.json", true) + .AddEnvironmentVariables(); - static TestEnvironment() - { - var configBuilder = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("config.json", optional: true) - .AddJsonFile("config.test.json", optional: true) - .AddEnvironmentVariables(); + Config = configBuilder.Build(); + } - Config = configBuilder.Build(); - } - } -} + public static IConfiguration Config { get; } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/config.json b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/config.json index a39052b5e..ddcb6a763 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/config.json +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/config.json @@ -1,7 +1,3 @@ { - "Test": { - "SqlServer": { - "DefaultConnectionString": "Server=(localdb)\\MSSqlLocaldb;Integrated Security=true;MultipleActiveResultSets=true;Connect Timeout=30" - } - } -} + "TestSqlServerDefaultConnectionString": "Server=(localdb)\\MSSqlLocaldb;Integrated Security=true;MultipleActiveResultSets=true;Connect Timeout=30" +} \ No newline at end of file diff --git a/test/Shared/ApiConsistencyTestBase.cs b/test/Shared/ApiConsistencyTestBase.cs index 29d75df9b..ee5f4b11d 100644 --- a/test/Shared/ApiConsistencyTestBase.cs +++ b/test/Shared/ApiConsistencyTestBase.cs @@ -10,88 +10,84 @@ 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(); + public abstract class ApiConsistencyTestBase + { + protected virtual IEnumerable GetCancellationTokenExceptions() + { + return Enumerable.Empty(); + } - Assert.False( - nonVirtualMethods.Any(), - "\r\n-- Missing virtual APIs --\r\n" + string.Join("\r\n", nonVirtualMethods)); - } + protected virtual IEnumerable GetAsyncSuffixExceptions() + { + return Enumerable.Empty(); + } - [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(); + protected abstract Assembly TargetAssembly { get; } - var missingSuffixMethods - = asyncMethods - .Where(method => !method.Name.EndsWith("Async")) - .Select(method => method.DeclaringType.Name + "." + method.Name) - .Except(GetAsyncSuffixExceptions()) - .ToList(); + protected virtual IEnumerable GetAllTypes(IEnumerable types) + { + foreach (var type in types) + { + yield return type; - Assert.False( - missingSuffixMethods.Any(), - "\r\n-- Missing async suffix --\r\n" + string.Join("\r\n", missingSuffixMethods)); - } + foreach (var nestedType in GetAllTypes(type.DeclaredNestedTypes)) + yield return nestedType; + } + } - protected virtual IEnumerable GetCancellationTokenExceptions() - { - return Enumerable.Empty(); - } + protected TypeInfo GetBasestTypeInAssembly(Type type) + { + while (type.GetTypeInfo()?.BaseType?.GetTypeInfo()?.Assembly == type.GetTypeInfo().Assembly) + type = type.GetTypeInfo().BaseType; - protected virtual IEnumerable GetAsyncSuffixExceptions() - { - return Enumerable.Empty(); - } + return type.GetTypeInfo(); + } - protected abstract Assembly TargetAssembly { get; } + [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(); - protected virtual IEnumerable GetAllTypes(IEnumerable types) - { - foreach (var type in types) - { - yield return type; + var missingSuffixMethods + = asyncMethods + .Where(method => !method.Name.EndsWith("Async")) + .Select(method => method.DeclaringType.Name + "." + method.Name) + .Except(GetAsyncSuffixExceptions()) + .ToList(); - foreach (var nestedType in GetAllTypes(type.DeclaredNestedTypes)) - { - yield return nestedType; - } - } - } + Assert.False( + missingSuffixMethods.Any(), + "\r\n-- Missing async suffix --\r\n" + string.Join("\r\n", missingSuffixMethods)); + } - protected TypeInfo GetBasestTypeInAssembly(Type type) - { - while (type.GetTypeInfo()?.BaseType?.GetTypeInfo()?.Assembly == type.GetTypeInfo().Assembly) - { - type = type.GetTypeInfo().BaseType; - } + [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(); - return type.GetTypeInfo(); - } - } -} + Assert.False( + nonVirtualMethods.Any(), + "\r\n-- Missing virtual APIs --\r\n" + string.Join("\r\n", nonVirtualMethods)); + } + } +} \ No newline at end of file diff --git a/test/Shared/IdentityResultAssert.cs b/test/Shared/IdentityResultAssert.cs index d7c7983cd..12dcc8484 100644 --- a/test/Shared/IdentityResultAssert.cs +++ b/test/Shared/IdentityResultAssert.cs @@ -1,53 +1,48 @@ // 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.Diagnostics; using System.Linq; using Microsoft.Extensions.Logging; using Xunit; namespace Microsoft.AspNetCore.Identity.Test { - public static class IdentityResultAssert - { - public static void IsSuccess(IdentityResult result) - { - Assert.NotNull(result); - Assert.True(result.Succeeded); - } + public static class IdentityResultAssert + { + public static void IsSuccess(IdentityResult result) + { + Assert.NotNull(result); + Assert.True(result.Succeeded); + } - public static void IsFailure(IdentityResult result) - { - Assert.NotNull(result); - Assert.False(result.Succeeded); - } + public static void IsFailure(IdentityResult result) + { + Assert.NotNull(result); + Assert.False(result.Succeeded); + } - public static void IsFailure(IdentityResult result, string error) - { - Assert.NotNull(result); - Assert.False(result.Succeeded); - Assert.Equal(error, result.Errors.First().Description); - } + public static void IsFailure(IdentityResult result, string error) + { + Assert.NotNull(result); + Assert.False(result.Succeeded); + Assert.Equal(error, result.Errors.First().Description); + } - 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); - } + 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); + } - 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"); - } - } - } + 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"); + } + } } \ No newline at end of file diff --git a/test/Shared/MockHelpers.cs b/test/Shared/MockHelpers.cs index ef612b2b7..c32105136 100644 --- a/test/Shared/MockHelpers.cs +++ b/test/Shared/MockHelpers.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; using System.Text; +using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -12,88 +12,86 @@ namespace Microsoft.AspNetCore.Identity.Test { - public static class MockHelpers - { - public static StringBuilder LogMessage = new StringBuilder(); - - public static Mock> MockUserManager() where TUser : class - { - var store = new Mock>(); - var mgr = new Mock>(store.Object, null, null, null, null, null, null, null, null); - mgr.Object.UserValidators.Add(new UserValidator()); - mgr.Object.PasswordValidators.Add(new PasswordValidator()); - return mgr; - } + public static class MockHelpers + { + public static StringBuilder LogMessage = new StringBuilder(); - public static Mock> MockRoleManager(IRoleStore store = null) where TRole : class - { - store = store ?? new Mock>().Object; - var roles = new List>(); - roles.Add(new RoleValidator()); - return new Mock>(store, roles, null, null, null, null); - } + public static Mock> MockUserManager() where TUser : class + { + var store = new Mock>(); + var mgr = new Mock>(store.Object, null, null, null, null, null, null, null, null); + mgr.Object.UserValidators.Add(new UserValidator()); + mgr.Object.PasswordValidators.Add(new PasswordValidator()); + return mgr; + } - public static Mock> MockILogger(StringBuilder logStore = null) where T : class - { - logStore = logStore ?? LogMessage; - var logger = new Mock>(); - logger.Setup(x => x.Log(It.IsAny(), It.IsAny(), It.IsAny(), - It.IsAny(), It.IsAny>())) - .Callback((LogLevel logLevel, EventId eventId, object state, Exception exception, Func formatter) => - { - if (formatter == null) - { - logStore.Append(state.ToString()); - } - else - { - logStore.Append(formatter(state, exception)); - } - logStore.Append(" "); - }); - logger.Setup(x => x.BeginScope(It.IsAny())).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); + public static Mock> MockRoleManager(IRoleStore store = null) where TRole : class + { + store = store ?? new Mock>().Object; + var roles = new List>(); + roles.Add(new RoleValidator()); + return new Mock>(store, roles, null, null, null, null); + } - return logger; - } + public static Mock> MockILogger(StringBuilder logStore = null) where T : class + { + logStore = logStore ?? LogMessage; + var logger = new Mock>(); + logger.Setup(x => x.Log(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny>())) + .Callback((LogLevel logLevel, EventId eventId, object state, Exception exception, + Func formatter) => + { + if (formatter == null) + logStore.Append(state); + else + logStore.Append(formatter(state, exception)); + logStore.Append(" "); + }); + logger.Setup(x => x.BeginScope(It.IsAny())) + .Callback((object state) => + { + logStore.Append(state); + logStore.Append(" "); + }); + logger.Setup(x => x.IsEnabled(LogLevel.Debug)).Returns(true); + logger.Setup(x => x.IsEnabled(LogLevel.Warning)).Returns(true); - public static UserManager TestUserManager(IUserStore store = null) where TUser : class - { - store = store ?? new Mock>().Object; - var options = new Mock>(); - var idOptions = new IdentityOptions(); - idOptions.Lockout.AllowedForNewUsers = false; - options.Setup(o => o.Value).Returns(idOptions); - var userValidators = new List>(); - var validator = new Mock>(); - userValidators.Add(validator.Object); - var pwdValidators = new List>(); - pwdValidators.Add(new PasswordValidator()); - var userManager = new UserManager(store, options.Object, new PasswordHasher(), - userValidators, pwdValidators, new UpperInvariantLookupNormalizer(), - new IdentityErrorDescriber(), null, - new Mock>>().Object); - validator.Setup(v => v.ValidateAsync(userManager, It.IsAny())) - .Returns(Task.FromResult(IdentityResult.Success)).Verifiable(); - return userManager; - } + return logger; + } - public static RoleManager TestRoleManager(IRoleStore store = null) where TRole : class - { - store = store ?? new Mock>().Object; - var roles = new List>(); - roles.Add(new RoleValidator()); - return new RoleManager(store, roles, - new UpperInvariantLookupNormalizer(), - new IdentityErrorDescriber(), - null, - null); - } + public static UserManager TestUserManager(IUserStore store = null) where TUser : class + { + store = store ?? new Mock>().Object; + var options = new Mock>(); + var idOptions = new IdentityOptions(); + idOptions.Lockout.AllowedForNewUsers = false; + options.Setup(o => o.Value).Returns(idOptions); + var userValidators = new List>(); + var validator = new Mock>(); + userValidators.Add(validator.Object); + var pwdValidators = new List>(); + pwdValidators.Add(new PasswordValidator()); + var userManager = new UserManager(store, options.Object, new PasswordHasher(), + userValidators, pwdValidators, new UpperInvariantLookupNormalizer(), + new IdentityErrorDescriber(), null, + new Mock>>().Object); + validator.Setup(v => v.ValidateAsync(userManager, It.IsAny())) + .Returns(Task.FromResult(IdentityResult.Success)) + .Verifiable(); + return userManager; + } - } -} + public static RoleManager TestRoleManager(IRoleStore store = null) where TRole : class + { + store = store ?? new Mock>().Object; + var roles = new List>(); + roles.Add(new RoleValidator()); + return new RoleManager(store, roles, + new UpperInvariantLookupNormalizer(), + new IdentityErrorDescriber(), + null, + null); + } + } +} \ No newline at end of file diff --git a/test/Shared/PasswordHasherOptionsAccessor.cs b/test/Shared/PasswordHasherOptionsAccessor.cs index ef9e9c58a..c481e1390 100644 --- a/test/Shared/PasswordHasherOptionsAccessor.cs +++ b/test/Shared/PasswordHasherOptionsAccessor.cs @@ -1,13 +1,12 @@ // 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.Options; namespace Microsoft.AspNetCore.Identity.Test { - internal class PasswordHasherOptionsAccessor : IOptions - { - public PasswordHasherOptions Value { get; } = new PasswordHasherOptions(); - } + internal class PasswordHasherOptionsAccessor : IOptions + { + public PasswordHasherOptions Value { get; } = new PasswordHasherOptions(); + } } \ No newline at end of file diff --git a/test/Shared/PriorityOrderer.cs b/test/Shared/PriorityOrderer.cs index d12866a2c..5a57283ad 100644 --- a/test/Shared/PriorityOrderer.cs +++ b/test/Shared/PriorityOrderer.cs @@ -1,59 +1,61 @@ // 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 Xunit.Abstractions; +using Xunit.Sdk; + namespace Microsoft.AspNetCore.Identity.Test { - using System; - using System.Collections.Generic; - using System.Linq; - using Xunit.Abstractions; - using Xunit.Sdk; - - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] - public class TestPriorityAttribute : Attribute - { - public TestPriorityAttribute(int priority) - { - Priority = priority; - } - - public int Priority { get; private set; } - } - - public class PriorityOrderer : ITestCaseOrderer - { - public IEnumerable OrderTestCases(IEnumerable testCases) where XunitTestCase : ITestCase - { - var sortedMethods = new SortedDictionary>(); - - foreach (XunitTestCase testCase in testCases) - { - int priority = 0; - - foreach (IAttributeInfo attr in testCase.TestMethod.Method.GetCustomAttributes((typeof(TestPriorityAttribute)).AssemblyQualifiedName)) - priority = attr.GetNamedArgument("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(IDictionary dictionary, TKey key) where TValue : new() - { - TValue result; - - if (dictionary.TryGetValue(key, out result)) return result; - - result = new TValue(); - dictionary[key] = result; - - return result; - } - } + [AttributeUsage(AttributeTargets.Method)] + public class TestPriorityAttribute : Attribute + { + public TestPriorityAttribute(int priority) + { + Priority = priority; + } + + public int Priority { get; } + } + + public class PriorityOrderer : ITestCaseOrderer + { + public IEnumerable OrderTestCases(IEnumerable testCases) + where XunitTestCase : ITestCase + { + var sortedMethods = new SortedDictionary>(); + + foreach (var testCase in testCases) + { + var priority = 0; + + foreach (var attr in testCase.TestMethod.Method.GetCustomAttributes(typeof(TestPriorityAttribute) + .AssemblyQualifiedName)) + priority = attr.GetNamedArgument("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 (var testCase in list) + yield return testCase; + } + } + + private static TValue GetOrCreate(IDictionary dictionary, TKey key) where TValue : new() + { + TValue result; + + if (dictionary.TryGetValue(key, out result)) return result; + + result = new TValue(); + dictionary[key] = result; + + return result; + } + } } \ No newline at end of file diff --git a/test/Shared/TestLogger.cs b/test/Shared/TestLogger.cs index fd699b137..a7f73ac5e 100644 --- a/test/Shared/TestLogger.cs +++ b/test/Shared/TestLogger.cs @@ -7,36 +7,33 @@ namespace Microsoft.AspNetCore.Identity.Test { - public interface ITestLogger - { - IList LogMessages { get; } - } + public interface ITestLogger + { + IList LogMessages { get; } + } - public class TestLogger : ILogger, ITestLogger - { - public IList LogMessages { get; } = new List(); + public class TestLogger : ILogger, ITestLogger + { + public IDisposable BeginScope(TState state) + { + LogMessages.Add(state?.ToString()); + return null; + } - public IDisposable BeginScope(TState state) - { - LogMessages.Add(state?.ToString()); - return null; - } + public bool IsEnabled(LogLevel logLevel) + { + return true; + } - public bool IsEnabled(LogLevel logLevel) - { - return true; - } + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, + Func formatter) + { + if (formatter == null) + LogMessages.Add(state.ToString()); + else + LogMessages.Add(formatter(state, exception)); + } - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - if (formatter == null) - { - LogMessages.Add(state.ToString()); - } - else - { - LogMessages.Add(formatter(state, exception)); - } - } - } + public IList LogMessages { get; } = new List(); + } } \ No newline at end of file diff --git a/test/Shared/TestRole.cs b/test/Shared/TestRole.cs index 21e491120..e2a8220fe 100644 --- a/test/Shared/TestRole.cs +++ b/test/Shared/TestRole.cs @@ -6,65 +6,68 @@ namespace Microsoft.AspNetCore.Identity.Test { - /// - /// Represents a Role entity - /// - public class TestRole : TestRole - { - /// - /// Constructor - /// - public TestRole() - { - Id = Guid.NewGuid().ToString(); - } + /// + /// Represents a Role entity + /// + public class TestRole : TestRole + { + /// + /// Constructor + /// + public TestRole() + { + Id = Guid.NewGuid().ToString(); + } - /// - /// Constructor - /// - /// - public TestRole(string roleName) : this() - { - Name = roleName; - } - } + /// + /// Constructor + /// + /// + public TestRole(string roleName) : this() + { + Name = roleName; + } + } - /// - /// Represents a Role entity - /// - /// - public class TestRole where TKey : IEquatable - { - public TestRole() { } + /// + /// Represents a Role entity + /// + /// + public class TestRole where TKey : IEquatable + { + public TestRole() + { + } - /// - /// Constructor - /// - /// - public TestRole(string roleName) : this() - { - Name = roleName; - } + /// + /// Constructor + /// + /// + public TestRole(string roleName) : this() + { + Name = roleName; + } - /// - /// Role id - /// - public virtual TKey Id { get; set; } + /// + /// Role id + /// + public virtual TKey Id { get; set; } - /// - /// Navigation property for claims in the role - /// - public virtual ICollection> Claims { get; private set; } = new List>(); + /// + /// Navigation property for claims in the role + /// + public virtual ICollection> Claims { get; } = new List>(); - /// - /// Role name - /// - public virtual string Name { get; set; } - public virtual string NormalizedName { get; set; } + /// + /// Role name + /// + public virtual string Name { get; set; } - /// - /// A random value that should change whenever a role is persisted to the store - /// - public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString(); - } + public virtual string NormalizedName { get; set; } + + /// + /// A random value that should change whenever a role is persisted to the store + /// + public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString(); + } } \ No newline at end of file diff --git a/test/Shared/TestRoleClaim.cs b/test/Shared/TestRoleClaim.cs index fbda17871..31ceedb6f 100644 --- a/test/Shared/TestRoleClaim.cs +++ b/test/Shared/TestRoleClaim.cs @@ -5,32 +5,34 @@ namespace Microsoft.AspNetCore.Identity.Test { - public class TestRoleClaim : TestRoleClaim { } + public class TestRoleClaim : TestRoleClaim + { + } - /// - /// EntityType that represents one specific role claim - /// - /// - public class TestRoleClaim where TKey : IEquatable - { - /// - /// Primary key - /// - public virtual int Id { get; set; } + /// + /// EntityType that represents one specific role claim + /// + /// + public class TestRoleClaim where TKey : IEquatable + { + /// + /// Primary key + /// + public virtual int Id { get; set; } - /// - /// User Id for the role this claim belongs to - /// - public virtual TKey RoleId { get; set; } + /// + /// User Id for the role this claim belongs to + /// + public virtual TKey RoleId { get; set; } - /// - /// Claim type - /// - public virtual string ClaimType { get; set; } + /// + /// Claim type + /// + public virtual string ClaimType { get; set; } - /// - /// Claim value - /// - public virtual string ClaimValue { get; set; } - } + /// + /// Claim value + /// + public virtual string ClaimValue { get; set; } + } } \ No newline at end of file diff --git a/test/Shared/TestUser.cs b/test/Shared/TestUser.cs index 744fa3d01..f153ce702 100644 --- a/test/Shared/TestUser.cs +++ b/test/Shared/TestUser.cs @@ -6,92 +6,94 @@ namespace Microsoft.AspNetCore.Identity.Test { - public class TestUser : TestUser - { - public TestUser() - { - Id = Guid.NewGuid().ToString(); - } - - public TestUser(string userName) : this() - { - UserName = userName; - } - } - - public class TestUser where TKey : IEquatable - { - public TestUser() { } - - public TestUser(string userName) : this() - { - UserName = userName; - } - - public virtual TKey Id { get; set; } - public virtual string UserName { get; set; } - public virtual string NormalizedUserName { get; set; } - - /// - /// Email - /// - public virtual string Email { get; set; } - - public virtual string NormalizedEmail { get; set; } - - /// - /// True if the email is confirmed, default is false - /// - public virtual bool EmailConfirmed { get; set; } - - /// - /// The salted/hashed form of the user password - /// - public virtual string PasswordHash { get; set; } - - /// - /// A random value that should change whenever a users credentials change (password changed, login removed) - /// - public virtual string SecurityStamp { get; set; } - - /// - /// A random value that should change whenever a user is persisted to the store - /// - public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString(); - - /// - /// PhoneNumber for the user - /// - public virtual string PhoneNumber { get; set; } - - /// - /// True if the phone number is confirmed, default is false - /// - public virtual bool PhoneNumberConfirmed { get; set; } - - /// - /// Is two factor enabled for the user - /// - public virtual bool TwoFactorEnabled { get; set; } - - /// - /// DateTime in UTC when lockout ends, any time in the past is considered not locked out. - /// - public virtual DateTimeOffset? LockoutEnd { get; set; } - - /// - /// Is lockout enabled for this user - /// - public virtual bool LockoutEnabled { get; set; } - - /// - /// Used to record failures for the purposes of lockout - /// - public virtual int AccessFailedCount { get; set; } - - public virtual ICollection> Roles { get; private set; } = new List>(); - public virtual ICollection> Claims { get; private set; } = new List>(); - public virtual ICollection> Logins { get; private set; } = new List>(); - public virtual ICollection> Tokens { get; private set; } = new List>(); - } -} + public class TestUser : TestUser + { + public TestUser() + { + Id = Guid.NewGuid().ToString(); + } + + public TestUser(string userName) : this() + { + UserName = userName; + } + } + + public class TestUser where TKey : IEquatable + { + public TestUser() + { + } + + public TestUser(string userName) : this() + { + UserName = userName; + } + + public virtual TKey Id { get; set; } + public virtual string UserName { get; set; } + public virtual string NormalizedUserName { get; set; } + + /// + /// Email + /// + public virtual string Email { get; set; } + + public virtual string NormalizedEmail { get; set; } + + /// + /// True if the email is confirmed, default is false + /// + public virtual bool EmailConfirmed { get; set; } + + /// + /// The salted/hashed form of the user password + /// + public virtual string PasswordHash { get; set; } + + /// + /// A random value that should change whenever a users credentials change (password changed, login removed) + /// + public virtual string SecurityStamp { get; set; } + + /// + /// A random value that should change whenever a user is persisted to the store + /// + public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString(); + + /// + /// PhoneNumber for the user + /// + public virtual string PhoneNumber { get; set; } + + /// + /// True if the phone number is confirmed, default is false + /// + public virtual bool PhoneNumberConfirmed { get; set; } + + /// + /// Is two factor enabled for the user + /// + public virtual bool TwoFactorEnabled { get; set; } + + /// + /// DateTime in UTC when lockout ends, any time in the past is considered not locked out. + /// + public virtual DateTimeOffset? LockoutEnd { get; set; } + + /// + /// Is lockout enabled for this user + /// + public virtual bool LockoutEnabled { get; set; } + + /// + /// Used to record failures for the purposes of lockout + /// + public virtual int AccessFailedCount { get; set; } + + public virtual ICollection> Roles { get; } = new List>(); + public virtual ICollection> Claims { get; } = new List>(); + public virtual ICollection> Logins { get; } = new List>(); + public virtual ICollection> Tokens { get; } = new List>(); + } +} \ No newline at end of file diff --git a/test/Shared/TestUserClaim.cs b/test/Shared/TestUserClaim.cs index d34e99349..945648f54 100644 --- a/test/Shared/TestUserClaim.cs +++ b/test/Shared/TestUserClaim.cs @@ -5,32 +5,34 @@ namespace Microsoft.AspNetCore.Identity.Test { - public class TestUserClaim : TestUserClaim { } + public class TestUserClaim : TestUserClaim + { + } - /// - /// EntityType that represents one specific user claim - /// - /// - public class TestUserClaim where TKey : IEquatable - { - /// - /// Primary key - /// - public virtual int Id { get; set; } + /// + /// EntityType that represents one specific user claim + /// + /// + public class TestUserClaim where TKey : IEquatable + { + /// + /// Primary key + /// + public virtual int Id { get; set; } - /// - /// User Id for the user who owns this claim - /// - public virtual TKey UserId { get; set; } + /// + /// User Id for the user who owns this claim + /// + public virtual TKey UserId { get; set; } - /// - /// Claim type - /// - public virtual string ClaimType { get; set; } + /// + /// Claim type + /// + public virtual string ClaimType { get; set; } - /// - /// Claim value - /// - public virtual string ClaimValue { get; set; } - } + /// + /// Claim value + /// + public virtual string ClaimValue { get; set; } + } } \ No newline at end of file diff --git a/test/Shared/TestUserLogin.cs b/test/Shared/TestUserLogin.cs index 9ad2fd9ff..ca6ca315c 100644 --- a/test/Shared/TestUserLogin.cs +++ b/test/Shared/TestUserLogin.cs @@ -5,32 +5,34 @@ namespace Microsoft.AspNetCore.Identity.Test { - public class TestUserLogin : TestUserLogin { } + public class TestUserLogin : TestUserLogin + { + } - /// - /// Entity type for a user's login (i.e. facebook, google) - /// - /// - public class TestUserLogin where TKey : IEquatable - { - /// - /// The login provider for the login (i.e. facebook, google) - /// - public virtual string LoginProvider { get; set; } + /// + /// Entity type for a user's login (i.e. facebook, google) + /// + /// + public class TestUserLogin where TKey : IEquatable + { + /// + /// The login provider for the login (i.e. facebook, google) + /// + public virtual string LoginProvider { get; set; } - /// - /// Key representing the login for the provider - /// - public virtual string ProviderKey { get; set; } + /// + /// Key representing the login for the provider + /// + public virtual string ProviderKey { get; set; } - /// - /// Display name for the login - /// - public virtual string ProviderDisplayName { get; set; } + /// + /// Display name for the login + /// + public virtual string ProviderDisplayName { get; set; } - /// - /// User Id for the user who owns this login - /// - public virtual TKey UserId { get; set; } - } + /// + /// User Id for the user who owns this login + /// + public virtual TKey UserId { get; set; } + } } \ No newline at end of file diff --git a/test/Shared/TestUserRole.cs b/test/Shared/TestUserRole.cs index 9a3207bda..62946d8fb 100644 --- a/test/Shared/TestUserRole.cs +++ b/test/Shared/TestUserRole.cs @@ -5,22 +5,24 @@ namespace Microsoft.AspNetCore.Identity.Test { - public class TestUserRole : TestUserRole { } + public class TestUserRole : TestUserRole + { + } - /// - /// EntityType that represents a user belonging to a role - /// - /// - public class TestUserRole where TKey : IEquatable - { - /// - /// UserId for the user that is in the role - /// - public virtual TKey UserId { get; set; } + /// + /// EntityType that represents a user belonging to a role + /// + /// + public class TestUserRole where TKey : IEquatable + { + /// + /// UserId for the user that is in the role + /// + public virtual TKey UserId { get; set; } - /// - /// RoleId for the role - /// - public virtual TKey RoleId { get; set; } - } + /// + /// RoleId for the role + /// + public virtual TKey RoleId { get; set; } + } } \ No newline at end of file diff --git a/test/Shared/TestUserToken.cs b/test/Shared/TestUserToken.cs index 8e9adfa18..f9cf6978e 100644 --- a/test/Shared/TestUserToken.cs +++ b/test/Shared/TestUserToken.cs @@ -5,32 +5,34 @@ namespace Microsoft.AspNetCore.Identity.Test { - public class TestUserToken : TestUserToken { } + public class TestUserToken : TestUserToken + { + } - /// - /// Entity type for a user's login (i.e. facebook, google) - /// - /// - public class TestUserToken where TKey : IEquatable - { - /// - /// The login provider for the login (i.e. facebook, google) - /// - public virtual string LoginProvider { get; set; } + /// + /// Entity type for a user's login (i.e. facebook, google) + /// + /// + public class TestUserToken where TKey : IEquatable + { + /// + /// The login provider for the login (i.e. facebook, google) + /// + public virtual string LoginProvider { get; set; } - /// - /// Key representing the login for the provider - /// - public virtual string TokenName { get; set; } + /// + /// Key representing the login for the provider + /// + public virtual string TokenName { get; set; } - /// - /// Display name for the login - /// - public virtual string TokenValue { get; set; } + /// + /// Display name for the login + /// + public virtual string TokenValue { get; set; } - /// - /// User Id for the user who owns this login - /// - public virtual TKey UserId { get; set; } - } + /// + /// User Id for the user who owns this login + /// + public virtual TKey UserId { get; set; } + } } \ No newline at end of file diff --git a/test/Shared/UserManagerTestBase.cs b/test/Shared/UserManagerTestBase.cs index 87c621c4b..85045e334 100644 --- a/test/Shared/UserManagerTestBase.cs +++ b/test/Shared/UserManagerTestBase.cs @@ -8,8 +8,11 @@ using System.Security.Claims; using System.Threading.Tasks; using LinqToDB; +using LinqToDB.Common; using LinqToDB.Data; +using LinqToDB.DataProvider; using LinqToDB.Identity; +using LinqToDB.Mapping; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Testing; @@ -17,40 +20,43 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Xunit; -using LinqToDB.DataProvider; -using LinqToDB.Mapping; namespace Microsoft.AspNetCore.Identity.Test { public class TestConnectionFactory : IConnectionFactory { - private string _configuration; - private string _connectionString; - private string _key; - - private static Dictionary> _tables = new Dictionary>(); - private IDataProvider _provider; + private static readonly Dictionary> _tables = new Dictionary>(); + private readonly string _configuration; + private readonly string _connectionString; + private readonly string _key; + private readonly IDataProvider _provider; public TestConnectionFactory(IDataProvider provider, string configuration, string connectionString) { _provider = provider; - LinqToDB.Common.Configuration.Linq.AllowMultipleQuery = true; + Configuration.Linq.AllowMultipleQuery = true; //DataConnection.AddConfiguration(configuration, connectionString, provider); _configuration = configuration; _connectionString = connectionString; _key = _configuration + "$$" + _connectionString; } - public DataContext GetContext() => new DataContext(_provider, _connectionString); + public DataContext GetContext() + { + return new DataContext(_provider, _connectionString); + } - public DataConnection GetConnection() => new DataConnection(_provider, _connectionString); + public DataConnection GetConnection() + { + return new DataConnection(_provider, _connectionString); + } public void CreateTable() { var dc = GetContext(); var e = dc.MappingSchema.GetEntityDescriptor(typeof(T)); HashSet set; - + lock (_tables) { if (!_tables.TryGetValue(_key, out set)) @@ -108,14 +114,15 @@ public void DropTable() // Common functionality tests that all verifies user manager functionality regardless of store implementation public abstract class UserManagerTestBase : UserManagerTestBase - where TUser : class, IIdentityUser + where TUser : class, IIdentityUser where TRole : class, IIdentityRole - { } + { + } - public abstract class UserManagerTestBase - where TUser : class, IIdentityUser - where TRole : class, IIdentityRole - where TKey : IEquatable + public abstract class UserManagerTestBase + where TUser : class, IIdentityUser + where TRole : class, IIdentityRole + where TKey : IEquatable { static UserManagerTestBase() { @@ -131,7 +138,6 @@ static UserManagerTestBase() .Property(_ => _.Id) .HasLength(255) .IsNullable(false); - } protected void CreateTables(TestConnectionFactory factory, string connectionString) @@ -142,299 +148,275 @@ protected void CreateTables(TestConnectionFactory factory, string connectionStri private const string NullValue = "(null)"; - private readonly IdentityErrorDescriber _errorDescriber = new IdentityErrorDescriber(); + private readonly IdentityErrorDescriber _errorDescriber = new IdentityErrorDescriber(); - protected virtual bool ShouldSkipDbTests() - { - return false; - } + protected virtual bool ShouldSkipDbTests() + { + return false; + } - protected virtual void SetupIdentityServices(IServiceCollection services, TestConnectionFactory context = null) - { - services.AddSingleton(); - services.AddIdentity(options => - { - options.Password.RequireDigit = false; - options.Password.RequireLowercase = false; - options.Password.RequireNonAlphanumeric = false; - options.Password.RequireUppercase = false; - options.User.AllowedUserNameCharacters = null; - }).AddDefaultTokenProviders(); - AddUserStore(services, context); - AddRoleStore(services, context); - services.AddLogging(); - services.AddSingleton>>(new TestLogger>()); - services.AddSingleton>>(new TestLogger>()); - } + protected virtual void SetupIdentityServices(IServiceCollection services, TestConnectionFactory context = null) + { + services.AddSingleton(); + services.AddIdentity(options => + { + options.Password.RequireDigit = false; + options.Password.RequireLowercase = false; + options.Password.RequireNonAlphanumeric = false; + options.Password.RequireUppercase = false; + options.User.AllowedUserNameCharacters = null; + }) + .AddDefaultTokenProviders(); + AddUserStore(services, context); + AddRoleStore(services, context); + services.AddLogging(); + services.AddSingleton>>(new TestLogger>()); + services.AddSingleton>>(new TestLogger>()); + } - protected virtual UserManager CreateManager(TestConnectionFactory context = null, IServiceCollection services = null, Action configureServices = null) - { - if (services == null) - { - services = new ServiceCollection(); - } - if (context == null) - { - context = CreateTestContext(); - } + protected virtual UserManager CreateManager(TestConnectionFactory context = null, + IServiceCollection services = null, Action configureServices = null) + { + if (services == null) + services = new ServiceCollection(); + if (context == null) + context = CreateTestContext(); - services.AddSingleton>(context); + services.AddSingleton>(context); - SetupIdentityServices(services, context); - if (configureServices != null) - { - configureServices(services); - } + SetupIdentityServices(services, context); + if (configureServices != null) + configureServices(services); - return services.BuildServiceProvider().GetService>(); - } + return services.BuildServiceProvider().GetService>(); + } - protected RoleManager CreateRoleManager(TestConnectionFactory context = null, IServiceCollection services = null) - { - if (services == null) - { - services = new ServiceCollection(); - } - if (context == null) - { - context = CreateTestContext(); - } - SetupIdentityServices(services, context); - return services.BuildServiceProvider().GetService>(); - } + protected RoleManager CreateRoleManager(TestConnectionFactory context = null, + IServiceCollection services = null) + { + if (services == null) + services = new ServiceCollection(); + if (context == null) + context = CreateTestContext(); + SetupIdentityServices(services, context); + return services.BuildServiceProvider().GetService>(); + } - protected abstract TestConnectionFactory CreateTestContext(); + protected abstract TestConnectionFactory CreateTestContext(); - protected abstract void AddUserStore(IServiceCollection services, TestConnectionFactory context = null); - protected abstract void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null); + protected abstract void AddUserStore(IServiceCollection services, TestConnectionFactory context = null); + protected abstract void AddRoleStore(IServiceCollection services, TestConnectionFactory context = null); - protected abstract void SetUserPasswordHash(TUser user, string hashedPassword); + protected abstract void SetUserPasswordHash(TUser user, string hashedPassword); - protected abstract TUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "", - bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = null, bool useNamePrefixAsUserName = false); + protected abstract TUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "", + bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = null, bool useNamePrefixAsUserName = false); - protected abstract TRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false); + protected abstract TRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false); - protected abstract Expression> UserNameEqualsPredicate(string userName); - protected abstract Expression> UserNameStartsWithPredicate(string userName); + protected abstract Expression> UserNameEqualsPredicate(string userName); + protected abstract Expression> UserNameStartsWithPredicate(string userName); - protected abstract Expression> RoleNameEqualsPredicate(string roleName); - protected abstract Expression> RoleNameStartsWithPredicate(string roleName); + protected abstract Expression> RoleNameEqualsPredicate(string roleName); + protected abstract Expression> RoleNameStartsWithPredicate(string roleName); - [Fact] - public async Task CanDeleteUser() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var userId = await manager.GetUserIdAsync(user); - IdentityResultAssert.IsSuccess(await manager.DeleteAsync(user)); - Assert.Null(await manager.FindByIdAsync(userId)); - } + [Fact] + public async Task CanDeleteUser() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var userId = await manager.GetUserIdAsync(user); + IdentityResultAssert.IsSuccess(await manager.DeleteAsync(user)); + Assert.Null(await manager.FindByIdAsync(userId)); + } - [Fact] - public async Task CanUpdateUserName() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var name = Guid.NewGuid().ToString(); - var user = CreateTestUser(name); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var newName = Guid.NewGuid().ToString(); - Assert.Null(await manager.FindByNameAsync(newName)); - IdentityResultAssert.IsSuccess(await manager.SetUserNameAsync(user, newName)); - IdentityResultAssert.IsSuccess(await manager.UpdateAsync(user)); - Assert.NotNull(await manager.FindByNameAsync(newName)); - Assert.Null(await manager.FindByNameAsync(name)); - } + [Fact] + public async Task CanUpdateUserName() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var name = Guid.NewGuid().ToString(); + var user = CreateTestUser(name); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var newName = Guid.NewGuid().ToString(); + Assert.Null(await manager.FindByNameAsync(newName)); + IdentityResultAssert.IsSuccess(await manager.SetUserNameAsync(user, newName)); + IdentityResultAssert.IsSuccess(await manager.UpdateAsync(user)); + Assert.NotNull(await manager.FindByNameAsync(newName)); + Assert.Null(await manager.FindByNameAsync(name)); + } - [Fact] - public async Task CheckSetUserNameValidatesUser() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var username = "UpdateAsync" + Guid.NewGuid().ToString(); - var newUsername = "New" + Guid.NewGuid().ToString(); - var user = CreateTestUser(username, useNamePrefixAsUserName: true); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - Assert.Null(await manager.FindByNameAsync(newUsername)); - IdentityResultAssert.IsSuccess(await manager.SetUserNameAsync(user, newUsername)); - Assert.NotNull(await manager.FindByNameAsync(newUsername)); - Assert.Null(await manager.FindByNameAsync(username)); - - var newUser = CreateTestUser(username, useNamePrefixAsUserName: true); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(newUser)); - var error = _errorDescriber.InvalidUserName(""); - IdentityResultAssert.IsFailure(await manager.SetUserNameAsync(newUser, ""), error); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"User {await manager.GetUserIdAsync(newUser)} validation failed: {error.Code}."); - - error = _errorDescriber.DuplicateUserName(newUsername); - IdentityResultAssert.IsFailure(await manager.SetUserNameAsync(newUser, newUsername), error); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"User {await manager.GetUserIdAsync(newUser)} validation failed: {error.Code}."); - } + [Fact] + public async Task CheckSetUserNameValidatesUser() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var username = "UpdateAsync" + Guid.NewGuid(); + var newUsername = "New" + Guid.NewGuid(); + var user = CreateTestUser(username, useNamePrefixAsUserName: true); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + Assert.Null(await manager.FindByNameAsync(newUsername)); + IdentityResultAssert.IsSuccess(await manager.SetUserNameAsync(user, newUsername)); + Assert.NotNull(await manager.FindByNameAsync(newUsername)); + Assert.Null(await manager.FindByNameAsync(username)); + + var newUser = CreateTestUser(username, useNamePrefixAsUserName: true); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(newUser)); + var error = _errorDescriber.InvalidUserName(""); + IdentityResultAssert.IsFailure(await manager.SetUserNameAsync(newUser, ""), error); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"User {await manager.GetUserIdAsync(newUser)} validation failed: {error.Code}."); + + error = _errorDescriber.DuplicateUserName(newUsername); + IdentityResultAssert.IsFailure(await manager.SetUserNameAsync(newUser, newUsername), error); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"User {await manager.GetUserIdAsync(newUser)} validation failed: {error.Code}."); + } - [Fact] - public async Task SetUserNameUpdatesSecurityStamp() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var username = "UpdateAsync" + Guid.NewGuid().ToString(); - var newUsername = "New" + Guid.NewGuid().ToString(); - var user = CreateTestUser(username, useNamePrefixAsUserName: true); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var stamp = await manager.GetSecurityStampAsync(user); - Assert.Null(await manager.FindByNameAsync(newUsername)); - IdentityResultAssert.IsSuccess(await manager.SetUserNameAsync(user, newUsername)); - Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task SetUserNameUpdatesSecurityStamp() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var username = "UpdateAsync" + Guid.NewGuid(); + var newUsername = "New" + Guid.NewGuid(); + var user = CreateTestUser(username, useNamePrefixAsUserName: true); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var stamp = await manager.GetSecurityStampAsync(user); + Assert.Null(await manager.FindByNameAsync(newUsername)); + IdentityResultAssert.IsSuccess(await manager.SetUserNameAsync(user, newUsername)); + Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task CreateUpdatesSecurityStamp() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var username = "Create" + Guid.NewGuid().ToString(); - var user = CreateTestUser(username, useNamePrefixAsUserName: true); - var stamp = await manager.GetSecurityStampAsync(user); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - Assert.NotNull(await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task CreateUpdatesSecurityStamp() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var username = "Create" + Guid.NewGuid(); + var user = CreateTestUser(username, useNamePrefixAsUserName: true); + var stamp = await manager.GetSecurityStampAsync(user); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + Assert.NotNull(await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task CheckSetEmailValidatesUser() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - manager.Options.User.RequireUniqueEmail = true; - manager.UserValidators.Add(new UserValidator()); - var random = new Random(); - var email = "foo" + random.Next() + "@example.com"; - var newEmail = "bar" + random.Next() + "@example.com"; - var user = CreateTestUser(email: email); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, newEmail)); - - var newUser = CreateTestUser(email: email); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(newUser)); - IdentityResultAssert.IsFailure(await manager.SetEmailAsync(newUser, newEmail), _errorDescriber.DuplicateEmail(newEmail)); - IdentityResultAssert.IsFailure(await manager.SetEmailAsync(newUser, ""), _errorDescriber.InvalidEmail("")); - } + [Fact] + public async Task CheckSetEmailValidatesUser() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + manager.Options.User.RequireUniqueEmail = true; + manager.UserValidators.Add(new UserValidator()); + var random = new Random(); + var email = "foo" + random.Next() + "@example.com"; + var newEmail = "bar" + random.Next() + "@example.com"; + var user = CreateTestUser(email: email); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, newEmail)); + + var newUser = CreateTestUser(email: email); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(newUser)); + IdentityResultAssert.IsFailure(await manager.SetEmailAsync(newUser, newEmail), + _errorDescriber.DuplicateEmail(newEmail)); + IdentityResultAssert.IsFailure(await manager.SetEmailAsync(newUser, ""), _errorDescriber.InvalidEmail("")); + } - [Fact] - public async Task CanUpdatePasswordUsingHasher() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser("UpdatePassword"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "password")); - Assert.True(await manager.CheckPasswordAsync(user, "password")); - var userId = await manager.GetUserIdAsync(user); - - SetUserPasswordHash(user, manager.PasswordHasher.HashPassword(user, "New")); - IdentityResultAssert.IsSuccess(await manager.UpdateAsync(user)); - Assert.False(await manager.CheckPasswordAsync(user, "password")); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"Invalid password for user {await manager.GetUserIdAsync(user)}."); - Assert.True(await manager.CheckPasswordAsync(user, "New")); - } + [Fact] + public async Task CanUpdatePasswordUsingHasher() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser("UpdatePassword"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "password")); + Assert.True(await manager.CheckPasswordAsync(user, "password")); + var userId = await manager.GetUserIdAsync(user); - [Fact] - public async Task CanFindById() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - Assert.NotNull(await manager.FindByIdAsync(await manager.GetUserIdAsync(user))); - } + SetUserPasswordHash(user, manager.PasswordHasher.HashPassword(user, "New")); + IdentityResultAssert.IsSuccess(await manager.UpdateAsync(user)); + Assert.False(await manager.CheckPasswordAsync(user, "password")); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"Invalid password for user {await manager.GetUserIdAsync(user)}."); + Assert.True(await manager.CheckPasswordAsync(user, "New")); + } - [Fact] - public async Task UserValidatorCanBlockCreate() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - manager.UserValidators.Clear(); - manager.UserValidators.Add(new AlwaysBadValidator()); - IdentityResultAssert.IsFailure(await manager.CreateAsync(user), AlwaysBadValidator.ErrorMessage); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"User {await manager.GetUserIdAsync(user) ?? NullValue} validation failed: {AlwaysBadValidator.ErrorMessage.Code}."); - } + [Fact] + public async Task CanFindById() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + Assert.NotNull(await manager.FindByIdAsync(await manager.GetUserIdAsync(user))); + } - [Fact] - public async Task UserValidatorCanBlockUpdate() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - manager.UserValidators.Clear(); - manager.UserValidators.Add(new AlwaysBadValidator()); - IdentityResultAssert.IsFailure(await manager.UpdateAsync(user), AlwaysBadValidator.ErrorMessage); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"User {await manager.GetUserIdAsync(user) ?? NullValue} validation failed: {AlwaysBadValidator.ErrorMessage.Code}."); - } + [Fact] + public async Task UserValidatorCanBlockCreate() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + manager.UserValidators.Clear(); + manager.UserValidators.Add(new AlwaysBadValidator()); + IdentityResultAssert.IsFailure(await manager.CreateAsync(user), AlwaysBadValidator.ErrorMessage); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"User {await manager.GetUserIdAsync(user) ?? NullValue} validation failed: {AlwaysBadValidator.ErrorMessage.Code}."); + } - [Fact] - public async Task CanChainUserValidators() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - manager.UserValidators.Clear(); - var user = CreateTestUser(); - manager.UserValidators.Add(new AlwaysBadValidator()); - manager.UserValidators.Add(new AlwaysBadValidator()); - var result = await manager.CreateAsync(user); - IdentityResultAssert.IsFailure(result, AlwaysBadValidator.ErrorMessage); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"User {await manager.GetUserIdAsync(user) ?? NullValue} validation failed: {AlwaysBadValidator.ErrorMessage.Code};{AlwaysBadValidator.ErrorMessage.Code}."); - Assert.Equal(2, result.Errors.Count()); - } + [Fact] + public async Task UserValidatorCanBlockUpdate() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + manager.UserValidators.Clear(); + manager.UserValidators.Add(new AlwaysBadValidator()); + IdentityResultAssert.IsFailure(await manager.UpdateAsync(user), AlwaysBadValidator.ErrorMessage); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"User {await manager.GetUserIdAsync(user) ?? NullValue} validation failed: {AlwaysBadValidator.ErrorMessage.Code}."); + } - [ConditionalTheory] - [InlineData("")] - [InlineData(null)] - public async Task UserValidatorBlocksShortEmailsWhenRequiresUniqueEmail(string email) - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - manager.Options.User.RequireUniqueEmail = true; - IdentityResultAssert.IsFailure(await manager.CreateAsync(user), _errorDescriber.InvalidEmail(email)); - } + [Fact] + public async Task CanChainUserValidators() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + manager.UserValidators.Clear(); + var user = CreateTestUser(); + manager.UserValidators.Add(new AlwaysBadValidator()); + manager.UserValidators.Add(new AlwaysBadValidator()); + var result = await manager.CreateAsync(user); + IdentityResultAssert.IsFailure(result, AlwaysBadValidator.ErrorMessage); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"User {await manager.GetUserIdAsync(user) ?? NullValue} validation failed: {AlwaysBadValidator.ErrorMessage.Code};{AlwaysBadValidator.ErrorMessage.Code}."); + Assert.Equal(2, result.Errors.Count()); + } + + [ConditionalTheory] + [InlineData("")] + [InlineData(null)] + public async Task UserValidatorBlocksShortEmailsWhenRequiresUniqueEmail(string email) + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + manager.Options.User.RequireUniqueEmail = true; + IdentityResultAssert.IsFailure(await manager.CreateAsync(user), _errorDescriber.InvalidEmail(email)); + } #if NET451 [Theory] @@ -453,1809 +435,1653 @@ public async Task UserValidatorBlocksInvalidEmailsWhenRequiresUniqueEmail(string } #endif - [Fact] - public async Task PasswordValidatorCanBlockAddPassword() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - manager.PasswordValidators.Clear(); - manager.PasswordValidators.Add(new AlwaysBadValidator()); - IdentityResultAssert.IsFailure(await manager.AddPasswordAsync(user, "password"), - AlwaysBadValidator.ErrorMessage); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"User {await manager.GetUserIdAsync(user)} password validation failed: {AlwaysBadValidator.ErrorMessage.Code}."); - } + [Fact] + public async Task PasswordValidatorCanBlockAddPassword() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + manager.PasswordValidators.Clear(); + manager.PasswordValidators.Add(new AlwaysBadValidator()); + IdentityResultAssert.IsFailure(await manager.AddPasswordAsync(user, "password"), + AlwaysBadValidator.ErrorMessage); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"User {await manager.GetUserIdAsync(user)} password validation failed: {AlwaysBadValidator.ErrorMessage.Code}."); + } - [Fact] - public async Task CanChainPasswordValidators() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - manager.PasswordValidators.Clear(); - manager.PasswordValidators.Add(new AlwaysBadValidator()); - manager.PasswordValidators.Add(new AlwaysBadValidator()); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var result = await manager.AddPasswordAsync(user, "pwd"); - IdentityResultAssert.IsFailure(result, AlwaysBadValidator.ErrorMessage); - Assert.Equal(2, result.Errors.Count()); - } + [Fact] + public async Task CanChainPasswordValidators() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + manager.PasswordValidators.Clear(); + manager.PasswordValidators.Add(new AlwaysBadValidator()); + manager.PasswordValidators.Add(new AlwaysBadValidator()); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var result = await manager.AddPasswordAsync(user, "pwd"); + IdentityResultAssert.IsFailure(result, AlwaysBadValidator.ErrorMessage); + Assert.Equal(2, result.Errors.Count()); + } - [Fact] - public async Task PasswordValidatorCanBlockChangePassword() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "password")); - manager.PasswordValidators.Clear(); - manager.PasswordValidators.Add(new AlwaysBadValidator()); - IdentityResultAssert.IsFailure(await manager.ChangePasswordAsync(user, "password", "new"), - AlwaysBadValidator.ErrorMessage); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"User {await manager.GetUserIdAsync(user) ?? NullValue} password validation failed: {AlwaysBadValidator.ErrorMessage.Code}."); - } + [Fact] + public async Task PasswordValidatorCanBlockChangePassword() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "password")); + manager.PasswordValidators.Clear(); + manager.PasswordValidators.Add(new AlwaysBadValidator()); + IdentityResultAssert.IsFailure(await manager.ChangePasswordAsync(user, "password", "new"), + AlwaysBadValidator.ErrorMessage); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"User {await manager.GetUserIdAsync(user) ?? NullValue} password validation failed: {AlwaysBadValidator.ErrorMessage.Code}."); + } - [Fact] - public async Task PasswordValidatorCanBlockCreateUser() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - manager.PasswordValidators.Clear(); - manager.PasswordValidators.Add(new AlwaysBadValidator()); - IdentityResultAssert.IsFailure(await manager.CreateAsync(user, "password"), AlwaysBadValidator.ErrorMessage); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"User {await manager.GetUserIdAsync(user) ?? NullValue} password validation failed: {AlwaysBadValidator.ErrorMessage.Code}."); - } + [Fact] + public async Task PasswordValidatorCanBlockCreateUser() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + manager.PasswordValidators.Clear(); + manager.PasswordValidators.Add(new AlwaysBadValidator()); + IdentityResultAssert.IsFailure(await manager.CreateAsync(user, "password"), AlwaysBadValidator.ErrorMessage); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"User {await manager.GetUserIdAsync(user) ?? NullValue} password validation failed: {AlwaysBadValidator.ErrorMessage.Code}."); + } - [Fact] - public async Task CanCreateUserNoPassword() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var username = "CreateUserTest" + Guid.NewGuid(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(CreateTestUser(username, useNamePrefixAsUserName: true))); - var user = await manager.FindByNameAsync(username); - Assert.NotNull(user); - Assert.False(await manager.HasPasswordAsync(user)); - Assert.False(await manager.CheckPasswordAsync(user, "whatever")); - var logins = await manager.GetLoginsAsync(user); - Assert.NotNull(logins); - Assert.Equal(0, logins.Count()); - } + [Fact] + public async Task CanCreateUserNoPassword() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var username = "CreateUserTest" + Guid.NewGuid(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(CreateTestUser(username, useNamePrefixAsUserName: true))); + var user = await manager.FindByNameAsync(username); + Assert.NotNull(user); + Assert.False(await manager.HasPasswordAsync(user)); + Assert.False(await manager.CheckPasswordAsync(user, "whatever")); + var logins = await manager.GetLoginsAsync(user); + Assert.NotNull(logins); + Assert.Equal(0, logins.Count()); + } - [Fact] - public async Task CanCreateUserAddLogin() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - const string provider = "ZzAuth"; - const string display = "display"; - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var providerKey = await manager.GetUserIdAsync(user); - IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, new UserLoginInfo(provider, providerKey, display))); - var logins = await manager.GetLoginsAsync(user); - Assert.NotNull(logins); - Assert.Equal(1, logins.Count()); - Assert.Equal(provider, logins.First().LoginProvider); - Assert.Equal(providerKey, logins.First().ProviderKey); - Assert.Equal(display, logins.First().ProviderDisplayName); - } + [Fact] + public async Task CanCreateUserAddLogin() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + const string provider = "ZzAuth"; + const string display = "display"; + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var providerKey = await manager.GetUserIdAsync(user); + IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, new UserLoginInfo(provider, providerKey, display))); + var logins = await manager.GetLoginsAsync(user); + Assert.NotNull(logins); + Assert.Equal(1, logins.Count()); + Assert.Equal(provider, logins.First().LoginProvider); + Assert.Equal(providerKey, logins.First().ProviderKey); + Assert.Equal(display, logins.First().ProviderDisplayName); + } - [Fact] - public async Task CanCreateUserLoginAndAddPassword() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var userId = await manager.GetUserIdAsync(user); - var login = new UserLoginInfo("Provider", userId, "display"); - IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, login)); - Assert.False(await manager.HasPasswordAsync(user)); - IdentityResultAssert.IsSuccess(await manager.AddPasswordAsync(user, "password")); - Assert.True(await manager.HasPasswordAsync(user)); - var logins = await manager.GetLoginsAsync(user); - Assert.NotNull(logins); - Assert.Equal(1, logins.Count()); - Assert.Equal(user.Id, (await manager.FindByLoginAsync(login.LoginProvider, login.ProviderKey)).Id); - Assert.True(await manager.CheckPasswordAsync(user, "password")); - } + [Fact] + public async Task CanCreateUserLoginAndAddPassword() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var userId = await manager.GetUserIdAsync(user); + var login = new UserLoginInfo("Provider", userId, "display"); + IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, login)); + Assert.False(await manager.HasPasswordAsync(user)); + IdentityResultAssert.IsSuccess(await manager.AddPasswordAsync(user, "password")); + Assert.True(await manager.HasPasswordAsync(user)); + var logins = await manager.GetLoginsAsync(user); + Assert.NotNull(logins); + Assert.Equal(1, logins.Count()); + Assert.Equal(user.Id, (await manager.FindByLoginAsync(login.LoginProvider, login.ProviderKey)).Id); + Assert.True(await manager.CheckPasswordAsync(user, "password")); + } - [Fact] - public async Task AddPasswordFailsIfAlreadyHave() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "Password")); - Assert.True(await manager.HasPasswordAsync(user)); - IdentityResultAssert.IsFailure(await manager.AddPasswordAsync(user, "password"), - "User already has a password set."); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"User {await manager.GetUserIdAsync(user)} already has a password."); - } + [Fact] + public async Task AddPasswordFailsIfAlreadyHave() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "Password")); + Assert.True(await manager.HasPasswordAsync(user)); + IdentityResultAssert.IsFailure(await manager.AddPasswordAsync(user, "password"), + "User already has a password set."); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"User {await manager.GetUserIdAsync(user)} already has a password."); + } - [Fact] - public async Task CanCreateUserAddRemoveLogin() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - var result = await manager.CreateAsync(user); - Assert.NotNull(user); - var userId = await manager.GetUserIdAsync(user); - var login = new UserLoginInfo("Provider", userId, "display"); - IdentityResultAssert.IsSuccess(result); - IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, login)); - Assert.Equal(user.Id, (await manager.FindByLoginAsync(login.LoginProvider, login.ProviderKey)).Id); - var logins = await manager.GetLoginsAsync(user); - Assert.NotNull(logins); - Assert.Equal(1, logins.Count()); - Assert.Equal(login.LoginProvider, logins.Last().LoginProvider); - Assert.Equal(login.ProviderKey, logins.Last().ProviderKey); - Assert.Equal(login.ProviderDisplayName, logins.Last().ProviderDisplayName); - var stamp = await manager.GetSecurityStampAsync(user); - IdentityResultAssert.IsSuccess(await manager.RemoveLoginAsync(user, login.LoginProvider, login.ProviderKey)); - Assert.Null(await manager.FindByLoginAsync(login.LoginProvider, login.ProviderKey)); - logins = await manager.GetLoginsAsync(user); - Assert.NotNull(logins); - Assert.Equal(0, logins.Count()); - Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task CanCreateUserAddRemoveLogin() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + var result = await manager.CreateAsync(user); + Assert.NotNull(user); + var userId = await manager.GetUserIdAsync(user); + var login = new UserLoginInfo("Provider", userId, "display"); + IdentityResultAssert.IsSuccess(result); + IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, login)); + Assert.Equal(user.Id, (await manager.FindByLoginAsync(login.LoginProvider, login.ProviderKey)).Id); + var logins = await manager.GetLoginsAsync(user); + Assert.NotNull(logins); + Assert.Equal(1, logins.Count()); + Assert.Equal(login.LoginProvider, logins.Last().LoginProvider); + Assert.Equal(login.ProviderKey, logins.Last().ProviderKey); + Assert.Equal(login.ProviderDisplayName, logins.Last().ProviderDisplayName); + var stamp = await manager.GetSecurityStampAsync(user); + IdentityResultAssert.IsSuccess(await manager.RemoveLoginAsync(user, login.LoginProvider, login.ProviderKey)); + Assert.Null(await manager.FindByLoginAsync(login.LoginProvider, login.ProviderKey)); + logins = await manager.GetLoginsAsync(user); + Assert.NotNull(logins); + Assert.Equal(0, logins.Count()); + Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task CanRemovePassword() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser("CanRemovePassword"); - const string password = "password"; - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password)); - var stamp = await manager.GetSecurityStampAsync(user); - var username = await manager.GetUserNameAsync(user); - IdentityResultAssert.IsSuccess(await manager.RemovePasswordAsync(user)); - var u = await manager.FindByNameAsync(username); - Assert.NotNull(u); - Assert.False(await manager.HasPasswordAsync(user)); - Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task CanRemovePassword() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser("CanRemovePassword"); + const string password = "password"; + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password)); + var stamp = await manager.GetSecurityStampAsync(user); + var username = await manager.GetUserNameAsync(user); + IdentityResultAssert.IsSuccess(await manager.RemovePasswordAsync(user)); + var u = await manager.FindByNameAsync(username); + Assert.NotNull(u); + Assert.False(await manager.HasPasswordAsync(user)); + Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task CanChangePassword() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - const string password = "password"; - const string newPassword = "newpassword"; - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password)); - var stamp = await manager.GetSecurityStampAsync(user); - Assert.NotNull(stamp); - IdentityResultAssert.IsSuccess(await manager.ChangePasswordAsync(user, password, newPassword)); - Assert.False(await manager.CheckPasswordAsync(user, password)); - Assert.True(await manager.CheckPasswordAsync(user, newPassword)); - Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); - } - - [Fact] - public async Task CanAddRemoveUserClaim() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - Claim[] claims = { new Claim("c", "v"), new Claim("c2", "v2"), new Claim("c2", "v3") }; - 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); - 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 CanChangePassword() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + const string password = "password"; + const string newPassword = "newpassword"; + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password)); + var stamp = await manager.GetSecurityStampAsync(user); + Assert.NotNull(stamp); + IdentityResultAssert.IsSuccess(await manager.ChangePasswordAsync(user, password, newPassword)); + Assert.False(await manager.CheckPasswordAsync(user, password)); + Assert.True(await manager.CheckPasswordAsync(user, newPassword)); + Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task CanAddRemoveUserClaim2() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - Claim[] claims = { new Claim("c", "v"), new Claim("c2", "v2"), new Claim("c2", "v3") }; - IdentityResultAssert.IsSuccess(await manager.AddClaimsAsync(user, claims)); + [Fact] + public async Task CanAddRemoveUserClaim() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + Claim[] claims = {new Claim("c", "v"), new Claim("c2", "v2"), new Claim("c2", "v3")}; + foreach (var 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); - IdentityResultAssert.IsSuccess(await manager.RemoveClaimsAsync(user, claims)); - userClaims = await manager.GetClaimsAsync(user); - Assert.Equal(0, userClaims.Count); - } - - [Fact] - public async Task RemoveClaimOnlyAffectsUser() - { - 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"), new Claim("c2", "v2"), new Claim("c2", "v3") }; - 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 CanReplaceUserClaim() - { - 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"))); - var userClaims = await manager.GetClaimsAsync(user); - Assert.Equal(1, userClaims.Count); - Claim claim = new Claim("c", "b"); - 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); - } - - [Fact] - public async Task ReplaceUserClaimOnlyAffectsUser() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - var user2 = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user2)); - IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, new Claim("c", "a"))); - IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user2, new Claim("c", "a"))); - var userClaims = await manager.GetClaimsAsync(user); - Assert.Equal(1, userClaims.Count); - var userClaims2 = await manager.GetClaimsAsync(user); - Assert.Equal(1, userClaims2.Count); - Claim claim = new Claim("c", "b"); - 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); - userClaims2 = await manager.GetClaimsAsync(user2); - Assert.Equal(1, userClaims2.Count); - Claim oldClaim2 = userClaims2.FirstOrDefault(); - Assert.Equal("c", oldClaim2.Type); - Assert.Equal("a", oldClaim2.Value); - } - - [Fact] - public async Task ChangePasswordFallsIfPasswordWrong() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "password")); - var result = await manager.ChangePasswordAsync(user, "bogus", "newpassword"); - IdentityResultAssert.IsFailure(result, "Incorrect password."); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"Change password failed for user {await manager.GetUserIdAsync(user)}."); - } + 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); + } - [Fact] - public async Task AddDupeUserNameFails() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var username = "AddDupeUserNameFails" + Guid.NewGuid(); - var user = CreateTestUser(username, useNamePrefixAsUserName: true); - var user2 = CreateTestUser(username, useNamePrefixAsUserName: true); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - IdentityResultAssert.IsFailure(await manager.CreateAsync(user2), _errorDescriber.DuplicateUserName(username)); - } + [Fact] + public async Task CanAddRemoveUserClaim2() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + Claim[] claims = {new Claim("c", "v"), new Claim("c2", "v2"), new Claim("c2", "v3")}; + IdentityResultAssert.IsSuccess(await manager.AddClaimsAsync(user, claims)); + var userId = await manager.GetUserIdAsync(user); + var userClaims = await manager.GetClaimsAsync(user); + Assert.Equal(3, userClaims.Count); + IdentityResultAssert.IsSuccess(await manager.RemoveClaimsAsync(user, claims)); + userClaims = await manager.GetClaimsAsync(user); + Assert.Equal(0, userClaims.Count); + } - [Fact] - public async Task AddDupeEmailAllowedByDefault() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(email: "yup@yup.com"); - var user2 = CreateTestUser(email: "yup@yup.com"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user2)); - IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user2, await manager.GetEmailAsync(user))); - } + [Fact] + public async Task RemoveClaimOnlyAffectsUser() + { + 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"), new Claim("c2", "v2"), new Claim("c2", "v3")}; + foreach (var 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 AddDupeEmailFailsWhenUniqueEmailRequired() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - manager.Options.User.RequireUniqueEmail = true; - var user = CreateTestUser(email: "FooUser@yup.com"); - var user2 = CreateTestUser(email: "FooUser@yup.com"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - IdentityResultAssert.IsFailure(await manager.CreateAsync(user2), _errorDescriber.DuplicateEmail("FooUser@yup.com")); - } + [Fact] + public async Task CanReplaceUserClaim() + { + 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"))); + var userClaims = await manager.GetClaimsAsync(user); + Assert.Equal(1, userClaims.Count); + var claim = new Claim("c", "b"); + var oldClaim = userClaims.FirstOrDefault(); + IdentityResultAssert.IsSuccess(await manager.ReplaceClaimAsync(user, oldClaim, claim)); + var newUserClaims = await manager.GetClaimsAsync(user); + Assert.Equal(1, newUserClaims.Count); + var newClaim = newUserClaims.FirstOrDefault(); + Assert.Equal(claim.Type, newClaim.Type); + Assert.Equal(claim.Value, newClaim.Value); + } - [Fact] - public async Task UpdateSecurityStampActuallyChanges() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - Assert.Null(await manager.GetSecurityStampAsync(user)); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var stamp = await manager.GetSecurityStampAsync(user); - Assert.NotNull(stamp); - IdentityResultAssert.IsSuccess(await manager.UpdateSecurityStampAsync(user)); - Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task ReplaceUserClaimOnlyAffectsUser() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + var user2 = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user2)); + IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, new Claim("c", "a"))); + IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user2, new Claim("c", "a"))); + var userClaims = await manager.GetClaimsAsync(user); + Assert.Equal(1, userClaims.Count); + var userClaims2 = await manager.GetClaimsAsync(user); + Assert.Equal(1, userClaims2.Count); + var claim = new Claim("c", "b"); + var oldClaim = userClaims.FirstOrDefault(); + IdentityResultAssert.IsSuccess(await manager.ReplaceClaimAsync(user, oldClaim, claim)); + var newUserClaims = await manager.GetClaimsAsync(user); + Assert.Equal(1, newUserClaims.Count); + var newClaim = newUserClaims.FirstOrDefault(); + Assert.Equal(claim.Type, newClaim.Type); + Assert.Equal(claim.Value, newClaim.Value); + userClaims2 = await manager.GetClaimsAsync(user2); + Assert.Equal(1, userClaims2.Count); + var oldClaim2 = userClaims2.FirstOrDefault(); + Assert.Equal("c", oldClaim2.Type); + Assert.Equal("a", oldClaim2.Value); + } - [Fact] - public async Task AddDupeLoginFails() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - var login = new UserLoginInfo("Provider", "key", "display"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, login)); - var result = await manager.AddLoginAsync(user, login); - IdentityResultAssert.IsFailure(result, _errorDescriber.LoginAlreadyAssociated()); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"AddLogin for user {await manager.GetUserIdAsync(user)} failed because it was already assocated with another user."); - } + [Fact] + public async Task ChangePasswordFallsIfPasswordWrong() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "password")); + var result = await manager.ChangePasswordAsync(user, "bogus", "newpassword"); + IdentityResultAssert.IsFailure(result, "Incorrect password."); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"Change password failed for user {await manager.GetUserIdAsync(user)}."); + } - // Email tests - [Fact] - public async Task CanFindByEmail() - { - if (ShouldSkipDbTests()) - { - return; - } - var email = "foouser@test.com"; - var manager = CreateManager(); - var user = CreateTestUser(email: email); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var fetch = await manager.FindByEmailAsync(email); - Assert.Equal(user.Id, fetch.Id); - } + [Fact] + public async Task AddDupeUserNameFails() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var username = "AddDupeUserNameFails" + Guid.NewGuid(); + var user = CreateTestUser(username, useNamePrefixAsUserName: true); + var user2 = CreateTestUser(username, useNamePrefixAsUserName: true); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + IdentityResultAssert.IsFailure(await manager.CreateAsync(user2), _errorDescriber.DuplicateUserName(username)); + } - [Fact] - public async Task CanFindUsersViaUserQuerable() - { - if (ShouldSkipDbTests()) - { - return; - } - var mgr = CreateManager(); - if (mgr.SupportsQueryableUsers) - { - var users = GenerateUsers("CanFindUsersViaUserQuerable", 4); - foreach (var u in users) - { - IdentityResultAssert.IsSuccess(await mgr.CreateAsync(u)); - } - Assert.Equal(users.Count, mgr.Users.Count(UserNameStartsWithPredicate("CanFindUsersViaUserQuerable"))); - Assert.Null(mgr.Users.FirstOrDefault(UserNameEqualsPredicate("bogus"))); - } - } + [Fact] + public async Task AddDupeEmailAllowedByDefault() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(email: "yup@yup.com"); + var user2 = CreateTestUser(email: "yup@yup.com"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user2)); + IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user2, await manager.GetEmailAsync(user))); + } - [Fact] - public async Task ConfirmEmailFalseByDefaultTest() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - Assert.False(await manager.IsEmailConfirmedAsync(user)); - } + [Fact] + public async Task AddDupeEmailFailsWhenUniqueEmailRequired() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + manager.Options.User.RequireUniqueEmail = true; + var user = CreateTestUser(email: "FooUser@yup.com"); + var user2 = CreateTestUser(email: "FooUser@yup.com"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + IdentityResultAssert.IsFailure(await manager.CreateAsync(user2), _errorDescriber.DuplicateEmail("FooUser@yup.com")); + } - private class StaticTokenProvider : IUserTwoFactorTokenProvider - { - public async Task GenerateAsync(string purpose, UserManager manager, TUser user) - { - return MakeToken(purpose, await manager.GetUserIdAsync(user)); - } + [Fact] + public async Task UpdateSecurityStampActuallyChanges() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + Assert.Null(await manager.GetSecurityStampAsync(user)); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var stamp = await manager.GetSecurityStampAsync(user); + Assert.NotNull(stamp); + IdentityResultAssert.IsSuccess(await manager.UpdateSecurityStampAsync(user)); + Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); + } - public async Task ValidateAsync(string purpose, string token, UserManager manager, TUser user) - { - return token == MakeToken(purpose, await manager.GetUserIdAsync(user)); - } + [Fact] + public async Task AddDupeLoginFails() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + var login = new UserLoginInfo("Provider", "key", "display"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, login)); + var result = await manager.AddLoginAsync(user, login); + IdentityResultAssert.IsFailure(result, _errorDescriber.LoginAlreadyAssociated()); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"AddLogin for user {await manager.GetUserIdAsync(user)} failed because it was already assocated with another user."); + } - public Task CanGenerateTwoFactorTokenAsync(UserManager manager, TUser user) - { - return Task.FromResult(true); - } + // Email tests + [Fact] + public async Task CanFindByEmail() + { + if (ShouldSkipDbTests()) + return; + var email = "foouser@test.com"; + var manager = CreateManager(); + var user = CreateTestUser(email: email); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var fetch = await manager.FindByEmailAsync(email); + Assert.Equal(user.Id, fetch.Id); + } - private static string MakeToken(string purpose, string userId) - { - return string.Join(":", userId, purpose, "ImmaToken"); - } - } + [Fact] + public async Task CanFindUsersViaUserQuerable() + { + if (ShouldSkipDbTests()) + return; + var mgr = CreateManager(); + if (mgr.SupportsQueryableUsers) + { + var users = GenerateUsers("CanFindUsersViaUserQuerable", 4); + foreach (var u in users) + IdentityResultAssert.IsSuccess(await mgr.CreateAsync(u)); + Assert.Equal(users.Count, mgr.Users.Count(UserNameStartsWithPredicate("CanFindUsersViaUserQuerable"))); + Assert.Null(mgr.Users.FirstOrDefault(UserNameEqualsPredicate("bogus"))); + } + } - [Fact] - public async Task CanResetPasswordWithStaticTokenProvider() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - manager.RegisterTokenProvider("Static", new StaticTokenProvider()); - manager.Options.Tokens.PasswordResetTokenProvider = "Static"; - var user = CreateTestUser(); - const string password = "password"; - const string newPassword = "newpassword"; - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password)); - var stamp = await manager.GetSecurityStampAsync(user); - Assert.NotNull(stamp); - var token = await manager.GeneratePasswordResetTokenAsync(user); - Assert.NotNull(token); - var userId = await manager.GetUserIdAsync(user); - IdentityResultAssert.IsSuccess(await manager.ResetPasswordAsync(user, token, newPassword)); - Assert.False(await manager.CheckPasswordAsync(user, password)); - Assert.True(await manager.CheckPasswordAsync(user, newPassword)); - Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task ConfirmEmailFalseByDefaultTest() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + Assert.False(await manager.IsEmailConfirmedAsync(user)); + } - [Fact] - public async Task PasswordValidatorCanBlockResetPasswordWithStaticTokenProvider() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - manager.RegisterTokenProvider("Static", new StaticTokenProvider()); - manager.Options.Tokens.PasswordResetTokenProvider = "Static"; - var user = CreateTestUser(); - const string password = "password"; - const string newPassword = "newpassword"; - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password)); - var stamp = await manager.GetSecurityStampAsync(user); - Assert.NotNull(stamp); - var token = await manager.GeneratePasswordResetTokenAsync(user); - Assert.NotNull(token); - manager.PasswordValidators.Add(new AlwaysBadValidator()); - IdentityResultAssert.IsFailure(await manager.ResetPasswordAsync(user, token, newPassword), - AlwaysBadValidator.ErrorMessage); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"User {await manager.GetUserIdAsync(user)} password validation failed: {AlwaysBadValidator.ErrorMessage.Code}."); - Assert.True(await manager.CheckPasswordAsync(user, password)); - Assert.Equal(stamp, await manager.GetSecurityStampAsync(user)); - } + private class StaticTokenProvider : IUserTwoFactorTokenProvider + { + public async Task GenerateAsync(string purpose, UserManager manager, TUser user) + { + return MakeToken(purpose, await manager.GetUserIdAsync(user)); + } - [Fact] - public async Task ResetPasswordWithStaticTokenProviderFailsWithWrongToken() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - manager.RegisterTokenProvider("Static", new StaticTokenProvider()); - manager.Options.Tokens.PasswordResetTokenProvider = "Static"; - var user = CreateTestUser(); - const string password = "password"; - const string newPassword = "newpassword"; - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password)); - var stamp = await manager.GetSecurityStampAsync(user); - Assert.NotNull(stamp); - IdentityResultAssert.IsFailure(await manager.ResetPasswordAsync(user, "bogus", newPassword), "Invalid token."); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyUserTokenAsync() failed with purpose: ResetPassword for user { await manager.GetUserIdAsync(user)}."); - Assert.True(await manager.CheckPasswordAsync(user, password)); - Assert.Equal(stamp, await manager.GetSecurityStampAsync(user)); - } + public async Task ValidateAsync(string purpose, string token, UserManager manager, TUser user) + { + return token == MakeToken(purpose, await manager.GetUserIdAsync(user)); + } - [Fact] - public async Task CanGenerateAndVerifyUserTokenWithStaticTokenProvider() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - manager.RegisterTokenProvider("Static", new StaticTokenProvider()); - var user = CreateTestUser(); - var user2 = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user2)); - var userId = await manager.GetUserIdAsync(user); - var token = await manager.GenerateUserTokenAsync(user, "Static", "test"); + public Task CanGenerateTwoFactorTokenAsync(UserManager manager, TUser user) + { + return Task.FromResult(true); + } - Assert.True(await manager.VerifyUserTokenAsync(user, "Static", "test", token)); + private static string MakeToken(string purpose, string userId) + { + return string.Join(":", userId, purpose, "ImmaToken"); + } + } - Assert.False(await manager.VerifyUserTokenAsync(user, "Static", "test2", token)); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyUserTokenAsync() failed with purpose: test2 for user { await manager.GetUserIdAsync(user)}."); + [Fact] + public async Task CanResetPasswordWithStaticTokenProvider() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + manager.RegisterTokenProvider("Static", new StaticTokenProvider()); + manager.Options.Tokens.PasswordResetTokenProvider = "Static"; + var user = CreateTestUser(); + const string password = "password"; + const string newPassword = "newpassword"; + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password)); + var stamp = await manager.GetSecurityStampAsync(user); + Assert.NotNull(stamp); + var token = await manager.GeneratePasswordResetTokenAsync(user); + Assert.NotNull(token); + var userId = await manager.GetUserIdAsync(user); + IdentityResultAssert.IsSuccess(await manager.ResetPasswordAsync(user, token, newPassword)); + Assert.False(await manager.CheckPasswordAsync(user, password)); + Assert.True(await manager.CheckPasswordAsync(user, newPassword)); + Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); + } - Assert.False(await manager.VerifyUserTokenAsync(user, "Static", "test", token + "a")); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyUserTokenAsync() failed with purpose: test for user { await manager.GetUserIdAsync(user)}."); + [Fact] + public async Task PasswordValidatorCanBlockResetPasswordWithStaticTokenProvider() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + manager.RegisterTokenProvider("Static", new StaticTokenProvider()); + manager.Options.Tokens.PasswordResetTokenProvider = "Static"; + var user = CreateTestUser(); + const string password = "password"; + const string newPassword = "newpassword"; + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password)); + var stamp = await manager.GetSecurityStampAsync(user); + Assert.NotNull(stamp); + var token = await manager.GeneratePasswordResetTokenAsync(user); + Assert.NotNull(token); + manager.PasswordValidators.Add(new AlwaysBadValidator()); + IdentityResultAssert.IsFailure(await manager.ResetPasswordAsync(user, token, newPassword), + AlwaysBadValidator.ErrorMessage); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"User {await manager.GetUserIdAsync(user)} password validation failed: {AlwaysBadValidator.ErrorMessage.Code}."); + Assert.True(await manager.CheckPasswordAsync(user, password)); + Assert.Equal(stamp, await manager.GetSecurityStampAsync(user)); + } - Assert.False(await manager.VerifyUserTokenAsync(user2, "Static", "test", token)); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyUserTokenAsync() failed with purpose: test for user { await manager.GetUserIdAsync(user2)}."); - } + [Fact] + public async Task ResetPasswordWithStaticTokenProviderFailsWithWrongToken() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + manager.RegisterTokenProvider("Static", new StaticTokenProvider()); + manager.Options.Tokens.PasswordResetTokenProvider = "Static"; + var user = CreateTestUser(); + const string password = "password"; + const string newPassword = "newpassword"; + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password)); + var stamp = await manager.GetSecurityStampAsync(user); + Assert.NotNull(stamp); + IdentityResultAssert.IsFailure(await manager.ResetPasswordAsync(user, "bogus", newPassword), "Invalid token."); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyUserTokenAsync() failed with purpose: ResetPassword for user {await manager.GetUserIdAsync(user)}."); + Assert.True(await manager.CheckPasswordAsync(user, password)); + Assert.Equal(stamp, await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task CanConfirmEmailWithStaticToken() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - manager.RegisterTokenProvider("Static", new StaticTokenProvider()); - manager.Options.Tokens.EmailConfirmationTokenProvider = "Static"; - var user = CreateTestUser(); - Assert.False(await manager.IsEmailConfirmedAsync(user)); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var token = await manager.GenerateEmailConfirmationTokenAsync(user); - Assert.NotNull(token); - var userId = await manager.GetUserIdAsync(user); - IdentityResultAssert.IsSuccess(await manager.ConfirmEmailAsync(user, token)); - Assert.True(await manager.IsEmailConfirmedAsync(user)); - IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, null)); - Assert.False(await manager.IsEmailConfirmedAsync(user)); - } + [Fact] + public async Task CanGenerateAndVerifyUserTokenWithStaticTokenProvider() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + manager.RegisterTokenProvider("Static", new StaticTokenProvider()); + var user = CreateTestUser(); + var user2 = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user2)); + var userId = await manager.GetUserIdAsync(user); + var token = await manager.GenerateUserTokenAsync(user, "Static", "test"); - [Fact] - public async Task ConfirmEmailWithStaticTokenFailsWithWrongToken() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - manager.RegisterTokenProvider("Static", new StaticTokenProvider()); - manager.Options.Tokens.EmailConfirmationTokenProvider = "Static"; - var user = CreateTestUser(); - Assert.False(await manager.IsEmailConfirmedAsync(user)); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - IdentityResultAssert.IsFailure(await manager.ConfirmEmailAsync(user, "bogus"), "Invalid token."); - Assert.False(await manager.IsEmailConfirmedAsync(user)); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyUserTokenAsync() failed with purpose: EmailConfirmation for user { await manager.GetUserIdAsync(user)}."); - } + Assert.True(await manager.VerifyUserTokenAsync(user, "Static", "test", token)); - [Fact] - public async Task ConfirmTokenFailsAfterPasswordChange() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(namePrefix: "Test"); - Assert.False(await manager.IsEmailConfirmedAsync(user)); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "password")); - var token = await manager.GenerateEmailConfirmationTokenAsync(user); - Assert.NotNull(token); - IdentityResultAssert.IsSuccess(await manager.ChangePasswordAsync(user, "password", "newpassword")); - IdentityResultAssert.IsFailure(await manager.ConfirmEmailAsync(user, token), "Invalid token."); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyUserTokenAsync() failed with purpose: EmailConfirmation for user { await manager.GetUserIdAsync(user)}."); - Assert.False(await manager.IsEmailConfirmedAsync(user)); - } + Assert.False(await manager.VerifyUserTokenAsync(user, "Static", "test2", token)); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyUserTokenAsync() failed with purpose: test2 for user {await manager.GetUserIdAsync(user)}."); - // Lockout tests + Assert.False(await manager.VerifyUserTokenAsync(user, "Static", "test", token + "a")); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyUserTokenAsync() failed with purpose: test for user {await manager.GetUserIdAsync(user)}."); - [Fact] - public async Task SingleFailureLockout() - { - if (ShouldSkipDbTests()) - { - return; - } - var mgr = CreateManager(); - mgr.Options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromHours(1); - mgr.Options.Lockout.MaxFailedAccessAttempts = 0; - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); - Assert.True(await mgr.GetLockoutEnabledAsync(user)); - Assert.False(await mgr.IsLockedOutAsync(user)); - IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); - Assert.True(await mgr.IsLockedOutAsync(user)); - Assert.True(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); - IdentityResultAssert.VerifyLogMessage(mgr.Logger, $"User {await mgr.GetUserIdAsync(user)} is locked out."); - - Assert.Equal(0, await mgr.GetAccessFailedCountAsync(user)); - } + Assert.False(await manager.VerifyUserTokenAsync(user2, "Static", "test", token)); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyUserTokenAsync() failed with purpose: test for user {await manager.GetUserIdAsync(user2)}."); + } - [Fact] - public async Task TwoFailureLockout() - { - if (ShouldSkipDbTests()) - { - return; - } - var mgr = CreateManager(); - mgr.Options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromHours(1); - mgr.Options.Lockout.MaxFailedAccessAttempts = 2; - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); - Assert.True(await mgr.GetLockoutEnabledAsync(user)); - Assert.False(await mgr.IsLockedOutAsync(user)); - IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); - Assert.False(await mgr.IsLockedOutAsync(user)); - Assert.False(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); - Assert.Equal(1, await mgr.GetAccessFailedCountAsync(user)); - IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); - Assert.True(await mgr.IsLockedOutAsync(user)); - Assert.True(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); - IdentityResultAssert.VerifyLogMessage(mgr.Logger, $"User {await mgr.GetUserIdAsync(user)} is locked out."); - Assert.Equal(0, await mgr.GetAccessFailedCountAsync(user)); - } + [Fact] + public async Task CanConfirmEmailWithStaticToken() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + manager.RegisterTokenProvider("Static", new StaticTokenProvider()); + manager.Options.Tokens.EmailConfirmationTokenProvider = "Static"; + var user = CreateTestUser(); + Assert.False(await manager.IsEmailConfirmedAsync(user)); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var token = await manager.GenerateEmailConfirmationTokenAsync(user); + Assert.NotNull(token); + var userId = await manager.GetUserIdAsync(user); + IdentityResultAssert.IsSuccess(await manager.ConfirmEmailAsync(user, token)); + Assert.True(await manager.IsEmailConfirmedAsync(user)); + IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, null)); + Assert.False(await manager.IsEmailConfirmedAsync(user)); + } - [Fact] - public async Task ResetAccessCountPreventsLockout() - { - if (ShouldSkipDbTests()) - { - return; - } - var mgr = CreateManager(); - mgr.Options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromHours(1); - mgr.Options.Lockout.MaxFailedAccessAttempts = 2; - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); - Assert.True(await mgr.GetLockoutEnabledAsync(user)); - Assert.False(await mgr.IsLockedOutAsync(user)); - IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); - Assert.False(await mgr.IsLockedOutAsync(user)); - Assert.False(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); - Assert.Equal(1, await mgr.GetAccessFailedCountAsync(user)); - IdentityResultAssert.IsSuccess(await mgr.ResetAccessFailedCountAsync(user)); - Assert.Equal(0, await mgr.GetAccessFailedCountAsync(user)); - Assert.False(await mgr.IsLockedOutAsync(user)); - Assert.False(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); - IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); - Assert.False(await mgr.IsLockedOutAsync(user)); - Assert.False(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); - Assert.Equal(1, await mgr.GetAccessFailedCountAsync(user)); - } + [Fact] + public async Task ConfirmEmailWithStaticTokenFailsWithWrongToken() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + manager.RegisterTokenProvider("Static", new StaticTokenProvider()); + manager.Options.Tokens.EmailConfirmationTokenProvider = "Static"; + var user = CreateTestUser(); + Assert.False(await manager.IsEmailConfirmedAsync(user)); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + IdentityResultAssert.IsFailure(await manager.ConfirmEmailAsync(user, "bogus"), "Invalid token."); + Assert.False(await manager.IsEmailConfirmedAsync(user)); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyUserTokenAsync() failed with purpose: EmailConfirmation for user {await manager.GetUserIdAsync(user)}."); + } - [Fact] - public async Task CanEnableLockoutManuallyAndLockout() - { - if (ShouldSkipDbTests()) - { - return; - } - var mgr = CreateManager(); - mgr.Options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromHours(1); - mgr.Options.Lockout.AllowedForNewUsers = false; - mgr.Options.Lockout.MaxFailedAccessAttempts = 2; - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); - Assert.False(await mgr.GetLockoutEnabledAsync(user)); - IdentityResultAssert.IsSuccess(await mgr.SetLockoutEnabledAsync(user, true)); - Assert.True(await mgr.GetLockoutEnabledAsync(user)); - Assert.False(await mgr.IsLockedOutAsync(user)); - IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); - Assert.False(await mgr.IsLockedOutAsync(user)); - Assert.False(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); - Assert.Equal(1, await mgr.GetAccessFailedCountAsync(user)); - IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); - Assert.True(await mgr.IsLockedOutAsync(user)); - Assert.True(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); - IdentityResultAssert.VerifyLogMessage(mgr.Logger, $"User {await mgr.GetUserIdAsync(user)} is locked out."); - Assert.Equal(0, await mgr.GetAccessFailedCountAsync(user)); - } + [Fact] + public async Task ConfirmTokenFailsAfterPasswordChange() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser("Test"); + Assert.False(await manager.IsEmailConfirmedAsync(user)); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "password")); + var token = await manager.GenerateEmailConfirmationTokenAsync(user); + Assert.NotNull(token); + IdentityResultAssert.IsSuccess(await manager.ChangePasswordAsync(user, "password", "newpassword")); + IdentityResultAssert.IsFailure(await manager.ConfirmEmailAsync(user, token), "Invalid token."); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyUserTokenAsync() failed with purpose: EmailConfirmation for user {await manager.GetUserIdAsync(user)}."); + Assert.False(await manager.IsEmailConfirmedAsync(user)); + } - [Fact] - public async Task UserNotLockedOutWithNullDateTimeAndIsSetToNullDate() - { - if (ShouldSkipDbTests()) - { - return; - } - var mgr = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); - Assert.True(await mgr.GetLockoutEnabledAsync(user)); - IdentityResultAssert.IsSuccess(await mgr.SetLockoutEndDateAsync(user, new DateTimeOffset())); - Assert.False(await mgr.IsLockedOutAsync(user)); - Assert.Equal(new DateTimeOffset(), await mgr.GetLockoutEndDateAsync(user)); - } + // Lockout tests - [Fact] - public async Task LockoutFailsIfNotEnabled() - { - if (ShouldSkipDbTests()) - { - return; - } - var mgr = CreateManager(); - mgr.Options.Lockout.AllowedForNewUsers = false; - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); - Assert.False(await mgr.GetLockoutEnabledAsync(user)); - IdentityResultAssert.IsFailure(await mgr.SetLockoutEndDateAsync(user, new DateTimeOffset()), - "Lockout is not enabled for this user."); - IdentityResultAssert.VerifyLogMessage(mgr.Logger, $"Lockout for user {await mgr.GetUserIdAsync(user)} failed because lockout is not enabled for this user."); - Assert.False(await mgr.IsLockedOutAsync(user)); - } + [Fact] + public async Task SingleFailureLockout() + { + if (ShouldSkipDbTests()) + return; + var mgr = CreateManager(); + mgr.Options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromHours(1); + mgr.Options.Lockout.MaxFailedAccessAttempts = 0; + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); + Assert.True(await mgr.GetLockoutEnabledAsync(user)); + Assert.False(await mgr.IsLockedOutAsync(user)); + IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); + Assert.True(await mgr.IsLockedOutAsync(user)); + Assert.True(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); + IdentityResultAssert.VerifyLogMessage(mgr.Logger, $"User {await mgr.GetUserIdAsync(user)} is locked out."); + + Assert.Equal(0, await mgr.GetAccessFailedCountAsync(user)); + } - [Fact] - public async Task LockoutEndToUtcNowMinus1SecInUserShouldNotBeLockedOut() - { - if (ShouldSkipDbTests()) - { - return; - } - var mgr = CreateManager(); - var user = CreateTestUser(lockoutEnd: DateTimeOffset.UtcNow.AddSeconds(-1)); - IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); - Assert.True(await mgr.GetLockoutEnabledAsync(user)); - Assert.False(await mgr.IsLockedOutAsync(user)); - } + [Fact] + public async Task TwoFailureLockout() + { + if (ShouldSkipDbTests()) + return; + var mgr = CreateManager(); + mgr.Options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromHours(1); + mgr.Options.Lockout.MaxFailedAccessAttempts = 2; + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); + Assert.True(await mgr.GetLockoutEnabledAsync(user)); + Assert.False(await mgr.IsLockedOutAsync(user)); + IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); + Assert.False(await mgr.IsLockedOutAsync(user)); + Assert.False(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); + Assert.Equal(1, await mgr.GetAccessFailedCountAsync(user)); + IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); + Assert.True(await mgr.IsLockedOutAsync(user)); + Assert.True(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); + IdentityResultAssert.VerifyLogMessage(mgr.Logger, $"User {await mgr.GetUserIdAsync(user)} is locked out."); + Assert.Equal(0, await mgr.GetAccessFailedCountAsync(user)); + } - [Fact] - public async Task LockoutEndToUtcNowSubOneSecondWithManagerShouldNotBeLockedOut() - { - if (ShouldSkipDbTests()) - { - return; - } - var mgr = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); - Assert.True(await mgr.GetLockoutEnabledAsync(user)); - IdentityResultAssert.IsSuccess(await mgr.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.AddSeconds(-1))); - Assert.False(await mgr.IsLockedOutAsync(user)); - } + [Fact] + public async Task ResetAccessCountPreventsLockout() + { + if (ShouldSkipDbTests()) + return; + var mgr = CreateManager(); + mgr.Options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromHours(1); + mgr.Options.Lockout.MaxFailedAccessAttempts = 2; + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); + Assert.True(await mgr.GetLockoutEnabledAsync(user)); + Assert.False(await mgr.IsLockedOutAsync(user)); + IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); + Assert.False(await mgr.IsLockedOutAsync(user)); + Assert.False(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); + Assert.Equal(1, await mgr.GetAccessFailedCountAsync(user)); + IdentityResultAssert.IsSuccess(await mgr.ResetAccessFailedCountAsync(user)); + Assert.Equal(0, await mgr.GetAccessFailedCountAsync(user)); + Assert.False(await mgr.IsLockedOutAsync(user)); + Assert.False(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); + IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); + Assert.False(await mgr.IsLockedOutAsync(user)); + Assert.False(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); + Assert.Equal(1, await mgr.GetAccessFailedCountAsync(user)); + } - [Fact] - public async Task LockoutEndToUtcNowPlus5ShouldBeLockedOut() - { - if (ShouldSkipDbTests()) - { - return; - } - var mgr = CreateManager(); - var lockoutEnd = DateTimeOffset.UtcNow.AddMinutes(5); - var user = CreateTestUser(lockoutEnd: lockoutEnd); - IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); - Assert.True(await mgr.GetLockoutEnabledAsync(user)); - Assert.True(await mgr.IsLockedOutAsync(user)); - } + [Fact] + public async Task CanEnableLockoutManuallyAndLockout() + { + if (ShouldSkipDbTests()) + return; + var mgr = CreateManager(); + mgr.Options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromHours(1); + mgr.Options.Lockout.AllowedForNewUsers = false; + mgr.Options.Lockout.MaxFailedAccessAttempts = 2; + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); + Assert.False(await mgr.GetLockoutEnabledAsync(user)); + IdentityResultAssert.IsSuccess(await mgr.SetLockoutEnabledAsync(user, true)); + Assert.True(await mgr.GetLockoutEnabledAsync(user)); + Assert.False(await mgr.IsLockedOutAsync(user)); + IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); + Assert.False(await mgr.IsLockedOutAsync(user)); + Assert.False(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); + Assert.Equal(1, await mgr.GetAccessFailedCountAsync(user)); + IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user)); + Assert.True(await mgr.IsLockedOutAsync(user)); + Assert.True(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55)); + IdentityResultAssert.VerifyLogMessage(mgr.Logger, $"User {await mgr.GetUserIdAsync(user)} is locked out."); + Assert.Equal(0, await mgr.GetAccessFailedCountAsync(user)); + } - [Fact] - public async Task UserLockedOutWithDateTimeLocalKindNowPlus30() - { - if (ShouldSkipDbTests()) - { - return; - } - var mgr = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); - Assert.True(await mgr.GetLockoutEnabledAsync(user)); - var lockoutEnd = new DateTimeOffset(DateTime.Now.AddMinutes(30).ToLocalTime()); - IdentityResultAssert.IsSuccess(await mgr.SetLockoutEndDateAsync(user, lockoutEnd)); - Assert.True(await mgr.IsLockedOutAsync(user)); - var end = await mgr.GetLockoutEndDateAsync(user); - Assert.Equal(lockoutEnd, end); - } + [Fact] + public async Task UserNotLockedOutWithNullDateTimeAndIsSetToNullDate() + { + if (ShouldSkipDbTests()) + return; + var mgr = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); + Assert.True(await mgr.GetLockoutEnabledAsync(user)); + IdentityResultAssert.IsSuccess(await mgr.SetLockoutEndDateAsync(user, new DateTimeOffset())); + Assert.False(await mgr.IsLockedOutAsync(user)); + Assert.Equal(new DateTimeOffset(), await mgr.GetLockoutEndDateAsync(user)); + } - // Role Tests - [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)); - } + [Fact] + public async Task LockoutFailsIfNotEnabled() + { + if (ShouldSkipDbTests()) + return; + var mgr = CreateManager(); + mgr.Options.Lockout.AllowedForNewUsers = false; + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); + Assert.False(await mgr.GetLockoutEnabledAsync(user)); + IdentityResultAssert.IsFailure(await mgr.SetLockoutEndDateAsync(user, new DateTimeOffset()), + "Lockout is not enabled for this user."); + IdentityResultAssert.VerifyLogMessage(mgr.Logger, + $"Lockout for user {await mgr.GetUserIdAsync(user)} failed because lockout is not enabled for this user."); + Assert.False(await mgr.IsLockedOutAsync(user)); + } - private class AlwaysBadValidator : IUserValidator, IRoleValidator, - IPasswordValidator - { - public static readonly IdentityError ErrorMessage = new IdentityError { Description = "I'm Bad.", Code = "BadValidator" }; + [Fact] + public async Task LockoutEndToUtcNowMinus1SecInUserShouldNotBeLockedOut() + { + if (ShouldSkipDbTests()) + return; + var mgr = CreateManager(); + var user = CreateTestUser(lockoutEnd: DateTimeOffset.UtcNow.AddSeconds(-1)); + IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); + Assert.True(await mgr.GetLockoutEnabledAsync(user)); + Assert.False(await mgr.IsLockedOutAsync(user)); + } - public Task ValidateAsync(UserManager manager, TUser user, string password) - { - return Task.FromResult(IdentityResult.Failed(ErrorMessage)); - } + [Fact] + public async Task LockoutEndToUtcNowSubOneSecondWithManagerShouldNotBeLockedOut() + { + if (ShouldSkipDbTests()) + return; + var mgr = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); + Assert.True(await mgr.GetLockoutEnabledAsync(user)); + IdentityResultAssert.IsSuccess(await mgr.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.AddSeconds(-1))); + Assert.False(await mgr.IsLockedOutAsync(user)); + } - public Task ValidateAsync(RoleManager manager, TRole role) - { - return Task.FromResult(IdentityResult.Failed(ErrorMessage)); - } + [Fact] + public async Task LockoutEndToUtcNowPlus5ShouldBeLockedOut() + { + if (ShouldSkipDbTests()) + return; + var mgr = CreateManager(); + var lockoutEnd = DateTimeOffset.UtcNow.AddMinutes(5); + var user = CreateTestUser(lockoutEnd: lockoutEnd); + IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); + Assert.True(await mgr.GetLockoutEnabledAsync(user)); + Assert.True(await mgr.IsLockedOutAsync(user)); + } - public Task ValidateAsync(UserManager manager, TUser user) - { - return Task.FromResult(IdentityResult.Failed(ErrorMessage)); - } - } + [Fact] + public async Task UserLockedOutWithDateTimeLocalKindNowPlus30() + { + if (ShouldSkipDbTests()) + return; + var mgr = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); + Assert.True(await mgr.GetLockoutEnabledAsync(user)); + var lockoutEnd = new DateTimeOffset(DateTime.Now.AddMinutes(30).ToLocalTime()); + IdentityResultAssert.IsSuccess(await mgr.SetLockoutEndDateAsync(user, lockoutEnd)); + Assert.True(await mgr.IsLockedOutAsync(user)); + var end = await mgr.GetLockoutEndDateAsync(user); + Assert.Equal(lockoutEnd, end); + } - [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}."); - } + // Role Tests + [Fact] + public async Task CanCreateRoleTest() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateRoleManager(); + var roleName = "create" + Guid.NewGuid(); + var role = CreateTestRole(roleName, true); + Assert.False(await manager.RoleExistsAsync(roleName)); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(role)); + Assert.True(await manager.RoleExistsAsync(roleName)); + } - [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()); - } + private class AlwaysBadValidator : IUserValidator, IRoleValidator, + IPasswordValidator + { + public static readonly IdentityError ErrorMessage = + new IdentityError {Description = "I'm Bad.", Code = "BadValidator"}; - [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}."); - } + public Task ValidateAsync(UserManager manager, TUser user, string password) + { + return Task.FromResult(IdentityResult.Failed(ErrorMessage)); + } - [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)); - } + public Task ValidateAsync(RoleManager manager, TRole role) + { + return Task.FromResult(IdentityResult.Failed(ErrorMessage)); + } - [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); - } + public Task ValidateAsync(UserManager manager, TUser user) + { + return Task.FromResult(IdentityResult.Failed(ErrorMessage)); + } + } - [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); - } + [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}."); + } - [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); - } + [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()); + } - [Fact] - public async Task CanUpdateRoleName() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateRoleManager(); - var roleName = "update" + 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, "Changed")); - IdentityResultAssert.IsSuccess(await manager.UpdateAsync(role)); - Assert.False(await manager.RoleExistsAsync("update")); - Assert.Equal(role.Id, (await manager.FindByNameAsync("Changed")).Id); - } + [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}."); + } - [Fact] - public async Task CanQueryableRoles() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateRoleManager(); - if (manager.SupportsQueryableRoles) - { - var roles = GenerateRoles("CanQuerableRolesTest", 4); - foreach (var r in roles) - { - IdentityResultAssert.IsSuccess(await manager.CreateAsync(r)); - } - Assert.Equal(roles.Count, manager.Roles.Count(RoleNameStartsWithPredicate("CanQuerableRolesTest"))); - Assert.Null(manager.Roles.FirstOrDefault(RoleNameEqualsPredicate("bogus"))); - } - } + [Fact] + public async Task CanDeleteRole() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateRoleManager(); + var roleName = "delete" + Guid.NewGuid(); + var role = CreateTestRole(roleName, 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)); + } - [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)); - } + [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 (var 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); + } - [Fact] - public async Task CanAddUsersToRole() - { - if (ShouldSkipDbTests()) - { - return; - } - var context = CreateTestContext(); - var manager = CreateManager(context); - var roleManager = CreateRoleManager(context); - 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)); - } - } + [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); + } - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Fails due to threading bugs in Mono")] - public async Task CanGetRolesForUser() - { - if (ShouldSkipDbTests()) - { - return; - } + [Fact] + public async Task CanRoleFindByName() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateRoleManager(); + var roleName = "FindByNameAsync" + Guid.NewGuid(); + var role = CreateTestRole(roleName, 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); + } - var context = CreateTestContext(); - var userManager = CreateManager(context); - var roleManager = CreateRoleManager(context); - var users = GenerateUsers("CanGetRolesForUser", 4); - var roles = GenerateRoles("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))); - } - } + [Fact] + public async Task CanUpdateRoleName() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateRoleManager(); + var roleName = "update" + Guid.NewGuid(); + var role = CreateTestRole(roleName, 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, "Changed")); + IdentityResultAssert.IsSuccess(await manager.UpdateAsync(role)); + Assert.False(await manager.RoleExistsAsync("update")); + Assert.Equal(role.Id, (await manager.FindByNameAsync("Changed")).Id); + } - 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)); - } - } - } + [Fact] + public async Task CanQueryableRoles() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateRoleManager(); + if (manager.SupportsQueryableRoles) + { + var roles = GenerateRoles("CanQuerableRolesTest", 4); + foreach (var r in roles) + IdentityResultAssert.IsSuccess(await manager.CreateAsync(r)); + Assert.Equal(roles.Count, manager.Roles.Count(RoleNameStartsWithPredicate("CanQuerableRolesTest"))); + Assert.Null(manager.Roles.FirstOrDefault(RoleNameEqualsPredicate("bogus"))); + } + } - [Fact] - public async Task RemoveUserFromRoleWithMultipleRoles() - { - if (ShouldSkipDbTests()) - { - return; - } - var context = CreateTestContext(); - var userManager = CreateManager(context); - var roleManager = CreateRoleManager(context); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user)); - var roles = GenerateRoles("RemoveUserFromRoleWithMultipleRoles", 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]))); - } + [Fact] + public async Task CreateRoleFailsIfExists() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateRoleManager(); + var roleName = "dupeRole" + Guid.NewGuid(); + var role = CreateTestRole(roleName, true); + Assert.False(await manager.RoleExistsAsync(roleName)); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(role)); + Assert.True(await manager.RoleExistsAsync(roleName)); + var role2 = CreateTestRole(roleName, true); + IdentityResultAssert.IsFailure(await manager.CreateAsync(role2)); + } - [Fact] - public async Task CanRemoveUsersFromRole() - { - if (ShouldSkipDbTests()) - { - return; - } - var context = CreateTestContext(); - var userManager = CreateManager(context); - var roleManager = CreateRoleManager(context); - var users = GenerateUsers("CanRemoveUsersFromRole", 4); - foreach (var u in users) - { - IdentityResultAssert.IsSuccess(await userManager.CreateAsync(u)); - } - var r = CreateTestRole("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)); - } - } + [Fact] + public async Task CanAddUsersToRole() + { + if (ShouldSkipDbTests()) + return; + var context = CreateTestContext(); + var manager = CreateManager(context); + var roleManager = CreateRoleManager(context); + var roleName = "AddUserTest" + Guid.NewGuid(); + var role = CreateTestRole(roleName, 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)); + } + } - [Fact] - public async Task RemoveUserNotInRoleFails() - { - if (ShouldSkipDbTests()) - { - return; - } - var context = CreateTestContext(); - var userMgr = CreateManager(context); - var roleMgr = CreateRoleManager(context); - 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}."); - } + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Fails due to threading bugs in Mono")] + public async Task CanGetRolesForUser() + { + if (ShouldSkipDbTests()) + return; + + var context = CreateTestContext(); + var userManager = CreateManager(context); + var roleManager = CreateRoleManager(context); + var users = GenerateUsers("CanGetRolesForUser", 4); + var roles = GenerateRoles("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))); + } + } - [Fact] - public async Task AddUserToRoleFailsIfAlreadyInRole() - { - if (ShouldSkipDbTests()) - { - return; - } - var context = CreateTestContext(); - var userMgr = CreateManager(context); - var roleMgr = CreateRoleManager(context); - 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}."); - } + 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)); + } + } + } - [Fact] - public async Task AddUserToRolesIgnoresDuplicates() - { - if (ShouldSkipDbTests()) - { - return; - } - var context = CreateTestContext(); - var userMgr = CreateManager(context); - var roleMgr = CreateRoleManager(context); - 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)); - } + [Fact] + public async Task RemoveUserFromRoleWithMultipleRoles() + { + if (ShouldSkipDbTests()) + return; + var context = CreateTestContext(); + var userManager = CreateManager(context); + var roleManager = CreateRoleManager(context); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user)); + var roles = GenerateRoles("RemoveUserFromRoleWithMultipleRoles", 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]))); + } - [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)); - } + [Fact] + public async Task CanRemoveUsersFromRole() + { + if (ShouldSkipDbTests()) + return; + var context = CreateTestContext(); + var userManager = CreateManager(context); + var roleManager = CreateRoleManager(context); + var users = GenerateUsers("CanRemoveUsersFromRole", 4); + foreach (var u in users) + IdentityResultAssert.IsSuccess(await userManager.CreateAsync(u)); + var r = CreateTestRole("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)); + } + } - [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))); - } + [Fact] + public async Task RemoveUserNotInRoleFails() + { + if (ShouldSkipDbTests()) + return; + var context = CreateTestContext(); + var userMgr = CreateManager(context); + var roleMgr = CreateRoleManager(context); + var roleName = "addUserDupeTest" + Guid.NewGuid(); + var role = CreateTestRole(roleName, 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}."); + } - [Fact] - public async Task SetPhoneNumberTest() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(phoneNumber: "123-456-7890"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var stamp = await manager.GetSecurityStampAsync(user); - Assert.Equal(await manager.GetPhoneNumberAsync(user), "123-456-7890"); - IdentityResultAssert.IsSuccess(await manager.SetPhoneNumberAsync(user, "111-111-1111")); - Assert.Equal(await manager.GetPhoneNumberAsync(user), "111-111-1111"); - Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task AddUserToRoleFailsIfAlreadyInRole() + { + if (ShouldSkipDbTests()) + return; + var context = CreateTestContext(); + var userMgr = CreateManager(context); + var roleMgr = CreateRoleManager(context); + var roleName = "addUserDupeTest" + Guid.NewGuid(); + var role = CreateTestRole(roleName, 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}."); + } - [Fact] - public async Task CanChangePhoneNumber() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(phoneNumber: "123-456-7890"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - Assert.False(await manager.IsPhoneNumberConfirmedAsync(user)); - var stamp = await manager.GetSecurityStampAsync(user); - var token1 = await manager.GenerateChangePhoneNumberTokenAsync(user, "111-111-1111"); - IdentityResultAssert.IsSuccess(await manager.ChangePhoneNumberAsync(user, "111-111-1111", token1)); - Assert.True(await manager.IsPhoneNumberConfirmedAsync(user)); - Assert.Equal(await manager.GetPhoneNumberAsync(user), "111-111-1111"); - Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task AddUserToRolesIgnoresDuplicates() + { + if (ShouldSkipDbTests()) + return; + var context = CreateTestContext(); + var userMgr = CreateManager(context); + var roleMgr = CreateRoleManager(context); + var roleName = "addUserDupeTest" + Guid.NewGuid(); + var role = CreateTestRole(roleName, 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)); + } - [Fact] - public async Task ChangePhoneNumberFailsWithWrongToken() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(phoneNumber: "123-456-7890"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - Assert.False(await manager.IsPhoneNumberConfirmedAsync(user)); - var stamp = await manager.GetSecurityStampAsync(user); - IdentityResultAssert.IsFailure(await manager.ChangePhoneNumberAsync(user, "111-111-1111", "bogus"), - "Invalid token."); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyChangePhoneNumberTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); - Assert.False(await manager.IsPhoneNumberConfirmedAsync(user)); - Assert.Equal(await manager.GetPhoneNumberAsync(user), "123-456-7890"); - Assert.Equal(stamp, await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task CanFindRoleByNameWithManager() + { + if (ShouldSkipDbTests()) + return; + var roleMgr = CreateRoleManager(); + var roleName = "findRoleByNameTest" + Guid.NewGuid(); + var role = CreateTestRole(roleName, true); + IdentityResultAssert.IsSuccess(await roleMgr.CreateAsync(role)); + Assert.NotNull(await roleMgr.FindByNameAsync(roleName)); + } - [Fact] - public async Task ChangePhoneNumberFailsWithWrongPhoneNumber() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(phoneNumber: "123-456-7890"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - Assert.False(await manager.IsPhoneNumberConfirmedAsync(user)); - var stamp = await manager.GetSecurityStampAsync(user); - var token1 = await manager.GenerateChangePhoneNumberTokenAsync(user, "111-111-1111"); - IdentityResultAssert.IsFailure(await manager.ChangePhoneNumberAsync(user, "bogus", token1), - "Invalid token."); - Assert.False(await manager.IsPhoneNumberConfirmedAsync(user)); - Assert.Equal(await manager.GetPhoneNumberAsync(user), "123-456-7890"); - Assert.Equal(stamp, await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task CanFindRoleWithManager() + { + if (ShouldSkipDbTests()) + return; + var roleMgr = CreateRoleManager(); + var roleName = "findRoleTest" + Guid.NewGuid(); + var role = CreateTestRole(roleName, true); + IdentityResultAssert.IsSuccess(await roleMgr.CreateAsync(role)); + Assert.Equal(roleName, await roleMgr.GetRoleNameAsync(await roleMgr.FindByNameAsync(roleName))); + } - [Fact] - public async Task CanVerifyPhoneNumber() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - const string num1 = "111-123-4567"; - const string num2 = "111-111-1111"; - var userId = await manager.GetUserIdAsync(user); - var token1 = await manager.GenerateChangePhoneNumberTokenAsync(user, num1); - - var token2 = await manager.GenerateChangePhoneNumberTokenAsync(user, num2); - Assert.NotEqual(token1, token2); - Assert.True(await manager.VerifyChangePhoneNumberTokenAsync(user, token1, num1)); - Assert.True(await manager.VerifyChangePhoneNumberTokenAsync(user, token2, num2)); - Assert.False(await manager.VerifyChangePhoneNumberTokenAsync(user, token2, num1)); - Assert.False(await manager.VerifyChangePhoneNumberTokenAsync(user, token1, num2)); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyChangePhoneNumberTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); - } + [Fact] + public async Task SetPhoneNumberTest() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(phoneNumber: "123-456-7890"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var stamp = await manager.GetSecurityStampAsync(user); + Assert.Equal(await manager.GetPhoneNumberAsync(user), "123-456-7890"); + IdentityResultAssert.IsSuccess(await manager.SetPhoneNumberAsync(user, "111-111-1111")); + Assert.Equal(await manager.GetPhoneNumberAsync(user), "111-111-1111"); + Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task CanChangeEmail() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser("foouser"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var email = await manager.GetUserNameAsync(user) + "@diddly.bop"; - IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, email)); - Assert.False(await manager.IsEmailConfirmedAsync(user)); - var stamp = await manager.GetSecurityStampAsync(user); - var newEmail = await manager.GetUserNameAsync(user) + "@en.vec"; - var token1 = await manager.GenerateChangeEmailTokenAsync(user, newEmail); - IdentityResultAssert.IsSuccess(await manager.ChangeEmailAsync(user, newEmail, token1)); - Assert.True(await manager.IsEmailConfirmedAsync(user)); - Assert.Equal(await manager.GetEmailAsync(user), newEmail); - Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task CanChangePhoneNumber() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(phoneNumber: "123-456-7890"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + Assert.False(await manager.IsPhoneNumberConfirmedAsync(user)); + var stamp = await manager.GetSecurityStampAsync(user); + var token1 = await manager.GenerateChangePhoneNumberTokenAsync(user, "111-111-1111"); + IdentityResultAssert.IsSuccess(await manager.ChangePhoneNumberAsync(user, "111-111-1111", token1)); + Assert.True(await manager.IsPhoneNumberConfirmedAsync(user)); + Assert.Equal(await manager.GetPhoneNumberAsync(user), "111-111-1111"); + Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task CanChangeEmailWithDifferentTokenProvider() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(context: null, services: null, - configureServices: s => s.Configure( - o => o.Tokens.ProviderMap["NewProvider2"] = new TokenProviderDescriptor(typeof(EmailTokenProvider)))); - manager.Options.Tokens.ChangeEmailTokenProvider = "NewProvider2"; - var user = CreateTestUser("foouser"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var email = await manager.GetUserNameAsync(user) + "@diddly.bop"; - IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, email)); - Assert.False(await manager.IsEmailConfirmedAsync(user)); - var stamp = await manager.GetSecurityStampAsync(user); - var newEmail = await manager.GetUserNameAsync(user) + "@en.vec"; - var token1 = await manager.GenerateChangeEmailTokenAsync(user, newEmail); - IdentityResultAssert.IsSuccess(await manager.ChangeEmailAsync(user, newEmail, token1)); - Assert.True(await manager.IsEmailConfirmedAsync(user)); - Assert.Equal(await manager.GetEmailAsync(user), newEmail); - Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task ChangePhoneNumberFailsWithWrongToken() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(phoneNumber: "123-456-7890"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + Assert.False(await manager.IsPhoneNumberConfirmedAsync(user)); + var stamp = await manager.GetSecurityStampAsync(user); + IdentityResultAssert.IsFailure(await manager.ChangePhoneNumberAsync(user, "111-111-1111", "bogus"), + "Invalid token."); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyChangePhoneNumberTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); + Assert.False(await manager.IsPhoneNumberConfirmedAsync(user)); + Assert.Equal(await manager.GetPhoneNumberAsync(user), "123-456-7890"); + Assert.Equal(stamp, await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task ChangeEmailFailsWithWrongToken() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser("foouser"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var email = await manager.GetUserNameAsync(user) + "@diddly.bop"; - IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, email)); - string oldEmail = email; - Assert.False(await manager.IsEmailConfirmedAsync(user)); - var stamp = await manager.GetSecurityStampAsync(user); - IdentityResultAssert.IsFailure(await manager.ChangeEmailAsync(user, "whatevah@foo.barf", "bogus"), - "Invalid token."); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyUserTokenAsync() failed with purpose: ChangeEmail:whatevah@foo.barf for user { await manager.GetUserIdAsync(user)}."); - Assert.False(await manager.IsEmailConfirmedAsync(user)); - Assert.Equal(await manager.GetEmailAsync(user), oldEmail); - Assert.Equal(stamp, await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task ChangePhoneNumberFailsWithWrongPhoneNumber() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(phoneNumber: "123-456-7890"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + Assert.False(await manager.IsPhoneNumberConfirmedAsync(user)); + var stamp = await manager.GetSecurityStampAsync(user); + var token1 = await manager.GenerateChangePhoneNumberTokenAsync(user, "111-111-1111"); + IdentityResultAssert.IsFailure(await manager.ChangePhoneNumberAsync(user, "bogus", token1), + "Invalid token."); + Assert.False(await manager.IsPhoneNumberConfirmedAsync(user)); + Assert.Equal(await manager.GetPhoneNumberAsync(user), "123-456-7890"); + Assert.Equal(stamp, await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task ChangeEmailFailsWithEmail() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser("foouser"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var email = await manager.GetUserNameAsync(user) + "@diddly.bop"; - IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, email)); - string oldEmail = email; - Assert.False(await manager.IsEmailConfirmedAsync(user)); - var stamp = await manager.GetSecurityStampAsync(user); - var token1 = await manager.GenerateChangeEmailTokenAsync(user, "forgot@alrea.dy"); - IdentityResultAssert.IsFailure(await manager.ChangeEmailAsync(user, "oops@foo.barf", token1), - "Invalid token."); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyUserTokenAsync() failed with purpose: ChangeEmail:oops@foo.barf for user { await manager.GetUserIdAsync(user)}."); - Assert.False(await manager.IsEmailConfirmedAsync(user)); - Assert.Equal(await manager.GetEmailAsync(user), oldEmail); - Assert.Equal(stamp, await manager.GetSecurityStampAsync(user)); - } + [Fact] + public async Task CanVerifyPhoneNumber() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + const string num1 = "111-123-4567"; + const string num2 = "111-111-1111"; + var userId = await manager.GetUserIdAsync(user); + var token1 = await manager.GenerateChangePhoneNumberTokenAsync(user, num1); + + var token2 = await manager.GenerateChangePhoneNumberTokenAsync(user, num2); + Assert.NotEqual(token1, token2); + Assert.True(await manager.VerifyChangePhoneNumberTokenAsync(user, token1, num1)); + Assert.True(await manager.VerifyChangePhoneNumberTokenAsync(user, token2, num2)); + Assert.False(await manager.VerifyChangePhoneNumberTokenAsync(user, token2, num1)); + Assert.False(await manager.VerifyChangePhoneNumberTokenAsync(user, token1, num2)); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyChangePhoneNumberTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); + } - [Fact] - public async Task EmailFactorFailsAfterSecurityStampChangeTest() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - string factorId = "Email"; //default - var user = CreateTestUser("foouser"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var email = await manager.GetUserNameAsync(user) + "@diddly.bop"; - IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, email)); - var token = await manager.GenerateEmailConfirmationTokenAsync(user); - await manager.ConfirmEmailAsync(user, token); - - var stamp = await manager.GetSecurityStampAsync(user); - Assert.NotNull(stamp); - token = await manager.GenerateTwoFactorTokenAsync(user, factorId); - Assert.NotNull(token); - IdentityResultAssert.IsSuccess(await manager.UpdateSecurityStampAsync(user)); - Assert.False(await manager.VerifyTwoFactorTokenAsync(user, factorId, token)); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyTwoFactorTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); - } + [Fact] + public async Task CanChangeEmail() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser("foouser"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var email = await manager.GetUserNameAsync(user) + "@diddly.bop"; + IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, email)); + Assert.False(await manager.IsEmailConfirmedAsync(user)); + var stamp = await manager.GetSecurityStampAsync(user); + var newEmail = await manager.GetUserNameAsync(user) + "@en.vec"; + var token1 = await manager.GenerateChangeEmailTokenAsync(user, newEmail); + IdentityResultAssert.IsSuccess(await manager.ChangeEmailAsync(user, newEmail, token1)); + Assert.True(await manager.IsEmailConfirmedAsync(user)); + Assert.Equal(await manager.GetEmailAsync(user), newEmail); + Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task EnableTwoFactorChangesSecurityStamp() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var stamp = await manager.GetSecurityStampAsync(user); - Assert.NotNull(stamp); - IdentityResultAssert.IsSuccess(await manager.SetTwoFactorEnabledAsync(user, true)); - Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); - Assert.True(await manager.GetTwoFactorEnabledAsync(user)); - } + [Fact] + public async Task CanChangeEmailWithDifferentTokenProvider() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(null, null, + s => s.Configure( + o => o.Tokens.ProviderMap["NewProvider2"] = new TokenProviderDescriptor(typeof(EmailTokenProvider)))); + manager.Options.Tokens.ChangeEmailTokenProvider = "NewProvider2"; + var user = CreateTestUser("foouser"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var email = await manager.GetUserNameAsync(user) + "@diddly.bop"; + IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, email)); + Assert.False(await manager.IsEmailConfirmedAsync(user)); + var stamp = await manager.GetSecurityStampAsync(user); + var newEmail = await manager.GetUserNameAsync(user) + "@en.vec"; + var token1 = await manager.GenerateChangeEmailTokenAsync(user, newEmail); + IdentityResultAssert.IsSuccess(await manager.ChangeEmailAsync(user, newEmail, token1)); + Assert.True(await manager.IsEmailConfirmedAsync(user)); + Assert.Equal(await manager.GetEmailAsync(user), newEmail); + Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task GenerateTwoFactorWithUnknownFactorProviderWillThrow() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - const string error = "No IUserTokenProvider named 'bogus' is registered."; - await - ExceptionAssert.ThrowsAsync( - () => manager.GenerateTwoFactorTokenAsync(user, "bogus"), error); - await ExceptionAssert.ThrowsAsync( - () => manager.VerifyTwoFactorTokenAsync(user, "bogus", "bogus"), error); - } + [Fact] + public async Task ChangeEmailFailsWithWrongToken() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser("foouser"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var email = await manager.GetUserNameAsync(user) + "@diddly.bop"; + IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, email)); + var oldEmail = email; + Assert.False(await manager.IsEmailConfirmedAsync(user)); + var stamp = await manager.GetSecurityStampAsync(user); + IdentityResultAssert.IsFailure(await manager.ChangeEmailAsync(user, "whatevah@foo.barf", "bogus"), + "Invalid token."); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyUserTokenAsync() failed with purpose: ChangeEmail:whatevah@foo.barf for user {await manager.GetUserIdAsync(user)}."); + Assert.False(await manager.IsEmailConfirmedAsync(user)); + Assert.Equal(await manager.GetEmailAsync(user), oldEmail); + Assert.Equal(stamp, await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task GetValidTwoFactorTestEmptyWithNoProviders() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var factors = await manager.GetValidTwoFactorProvidersAsync(user); - Assert.NotNull(factors); - Assert.True(!factors.Any()); - } + [Fact] + public async Task ChangeEmailFailsWithEmail() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser("foouser"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var email = await manager.GetUserNameAsync(user) + "@diddly.bop"; + IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, email)); + var oldEmail = email; + Assert.False(await manager.IsEmailConfirmedAsync(user)); + var stamp = await manager.GetSecurityStampAsync(user); + var token1 = await manager.GenerateChangeEmailTokenAsync(user, "forgot@alrea.dy"); + IdentityResultAssert.IsFailure(await manager.ChangeEmailAsync(user, "oops@foo.barf", token1), + "Invalid token."); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyUserTokenAsync() failed with purpose: ChangeEmail:oops@foo.barf for user {await manager.GetUserIdAsync(user)}."); + Assert.False(await manager.IsEmailConfirmedAsync(user)); + Assert.Equal(await manager.GetEmailAsync(user), oldEmail); + Assert.Equal(stamp, await manager.GetSecurityStampAsync(user)); + } - [Fact] - public async Task CanGetSetUpdateAndRemoveUserToken() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - Assert.Null(await manager.GetAuthenticationTokenAsync(user, "provider", "name")); - IdentityResultAssert.IsSuccess(await manager.SetAuthenticationTokenAsync(user, "provider", "name", "value")); - Assert.Equal("value", await manager.GetAuthenticationTokenAsync(user, "provider", "name")); + [Fact] + public async Task EmailFactorFailsAfterSecurityStampChangeTest() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var factorId = "Email"; //default + var user = CreateTestUser("foouser"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var email = await manager.GetUserNameAsync(user) + "@diddly.bop"; + IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, email)); + var token = await manager.GenerateEmailConfirmationTokenAsync(user); + await manager.ConfirmEmailAsync(user, token); + + var stamp = await manager.GetSecurityStampAsync(user); + Assert.NotNull(stamp); + token = await manager.GenerateTwoFactorTokenAsync(user, factorId); + Assert.NotNull(token); + IdentityResultAssert.IsSuccess(await manager.UpdateSecurityStampAsync(user)); + Assert.False(await manager.VerifyTwoFactorTokenAsync(user, factorId, token)); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyTwoFactorTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); + } - IdentityResultAssert.IsSuccess(await manager.SetAuthenticationTokenAsync(user, "provider", "name", "value2")); - Assert.Equal("value2", await manager.GetAuthenticationTokenAsync(user, "provider", "name")); + [Fact] + public async Task EnableTwoFactorChangesSecurityStamp() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var stamp = await manager.GetSecurityStampAsync(user); + Assert.NotNull(stamp); + IdentityResultAssert.IsSuccess(await manager.SetTwoFactorEnabledAsync(user, true)); + Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); + Assert.True(await manager.GetTwoFactorEnabledAsync(user)); + } - IdentityResultAssert.IsSuccess(await manager.RemoveAuthenticationTokenAsync(user, "whatevs", "name")); - Assert.Equal("value2", await manager.GetAuthenticationTokenAsync(user, "provider", "name")); + [Fact] + public async Task GenerateTwoFactorWithUnknownFactorProviderWillThrow() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + const string error = "No IUserTokenProvider named 'bogus' is registered."; + await + ExceptionAssert.ThrowsAsync( + () => manager.GenerateTwoFactorTokenAsync(user, "bogus"), error); + await ExceptionAssert.ThrowsAsync( + () => manager.VerifyTwoFactorTokenAsync(user, "bogus", "bogus"), error); + } - IdentityResultAssert.IsSuccess(await manager.RemoveAuthenticationTokenAsync(user, "provider", "name")); - Assert.Null(await manager.GetAuthenticationTokenAsync(user, "provider", "name")); - } + [Fact] + public async Task GetValidTwoFactorTestEmptyWithNoProviders() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var factors = await manager.GetValidTwoFactorProvidersAsync(user); + Assert.NotNull(factors); + Assert.True(!factors.Any()); + } - [Fact] - public async Task CanGetValidTwoFactor() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var userId = await manager.GetUserIdAsync(user); - var factors = await manager.GetValidTwoFactorProvidersAsync(user); - Assert.NotNull(factors); - Assert.False(factors.Any()); - IdentityResultAssert.IsSuccess(await manager.SetPhoneNumberAsync(user, "111-111-1111")); - var token = await manager.GenerateChangePhoneNumberTokenAsync(user, "111-111-1111"); - IdentityResultAssert.IsSuccess(await manager.ChangePhoneNumberAsync(user, "111-111-1111", token)); - await manager.UpdateAsync(user); - factors = await manager.GetValidTwoFactorProvidersAsync(user); - Assert.NotNull(factors); - Assert.Equal(1, factors.Count()); - Assert.Equal("Phone", factors[0]); - IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, "test@test.com")); - token = await manager.GenerateEmailConfirmationTokenAsync(user); - await manager.ConfirmEmailAsync(user, token); - factors = await manager.GetValidTwoFactorProvidersAsync(user); - Assert.NotNull(factors); - Assert.Equal(2, factors.Count()); - IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, null)); - factors = await manager.GetValidTwoFactorProvidersAsync(user); - Assert.NotNull(factors); - Assert.Equal(1, factors.Count()); - Assert.Equal("Phone", factors[0]); - } + [Fact] + public async Task CanGetSetUpdateAndRemoveUserToken() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + Assert.Null(await manager.GetAuthenticationTokenAsync(user, "provider", "name")); + IdentityResultAssert.IsSuccess(await manager.SetAuthenticationTokenAsync(user, "provider", "name", "value")); + Assert.Equal("value", await manager.GetAuthenticationTokenAsync(user, "provider", "name")); + + IdentityResultAssert.IsSuccess(await manager.SetAuthenticationTokenAsync(user, "provider", "name", "value2")); + Assert.Equal("value2", await manager.GetAuthenticationTokenAsync(user, "provider", "name")); + + IdentityResultAssert.IsSuccess(await manager.RemoveAuthenticationTokenAsync(user, "whatevs", "name")); + Assert.Equal("value2", await manager.GetAuthenticationTokenAsync(user, "provider", "name")); + + IdentityResultAssert.IsSuccess(await manager.RemoveAuthenticationTokenAsync(user, "provider", "name")); + Assert.Null(await manager.GetAuthenticationTokenAsync(user, "provider", "name")); + } - [Fact] - public async Task PhoneFactorFailsAfterSecurityStampChangeTest() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var factorId = "Phone"; // default - var user = CreateTestUser(phoneNumber: "4251234567"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var stamp = await manager.GetSecurityStampAsync(user); - Assert.NotNull(stamp); - var token = await manager.GenerateTwoFactorTokenAsync(user, factorId); - Assert.NotNull(token); - IdentityResultAssert.IsSuccess(await manager.UpdateSecurityStampAsync(user)); - Assert.False(await manager.VerifyTwoFactorTokenAsync(user, factorId, token)); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyTwoFactorTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); - } + [Fact] + public async Task CanGetValidTwoFactor() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var userId = await manager.GetUserIdAsync(user); + var factors = await manager.GetValidTwoFactorProvidersAsync(user); + Assert.NotNull(factors); + Assert.False(factors.Any()); + IdentityResultAssert.IsSuccess(await manager.SetPhoneNumberAsync(user, "111-111-1111")); + var token = await manager.GenerateChangePhoneNumberTokenAsync(user, "111-111-1111"); + IdentityResultAssert.IsSuccess(await manager.ChangePhoneNumberAsync(user, "111-111-1111", token)); + await manager.UpdateAsync(user); + factors = await manager.GetValidTwoFactorProvidersAsync(user); + Assert.NotNull(factors); + Assert.Equal(1, factors.Count()); + Assert.Equal("Phone", factors[0]); + IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, "test@test.com")); + token = await manager.GenerateEmailConfirmationTokenAsync(user); + await manager.ConfirmEmailAsync(user, token); + factors = await manager.GetValidTwoFactorProvidersAsync(user); + Assert.NotNull(factors); + Assert.Equal(2, factors.Count()); + IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, null)); + factors = await manager.GetValidTwoFactorProvidersAsync(user); + Assert.NotNull(factors); + Assert.Equal(1, factors.Count()); + Assert.Equal("Phone", factors[0]); + } - [Fact] - public async Task VerifyTokenFromWrongTokenProviderFails() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(phoneNumber: "4251234567"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - var token = await manager.GenerateTwoFactorTokenAsync(user, "Phone"); - Assert.NotNull(token); - Assert.False(await manager.VerifyTwoFactorTokenAsync(user, "Email", token)); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyTwoFactorTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); - } + [Fact] + public async Task PhoneFactorFailsAfterSecurityStampChangeTest() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var factorId = "Phone"; // default + var user = CreateTestUser(phoneNumber: "4251234567"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var stamp = await manager.GetSecurityStampAsync(user); + Assert.NotNull(stamp); + var token = await manager.GenerateTwoFactorTokenAsync(user, factorId); + Assert.NotNull(token); + IdentityResultAssert.IsSuccess(await manager.UpdateSecurityStampAsync(user)); + Assert.False(await manager.VerifyTwoFactorTokenAsync(user, factorId, token)); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyTwoFactorTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); + } - [Fact] - public async Task VerifyWithWrongSmsTokenFails() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); - var user = CreateTestUser(phoneNumber: "4251234567"); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - Assert.False(await manager.VerifyTwoFactorTokenAsync(user, "Phone", "bogus")); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyTwoFactorTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); - } + [Fact] + public async Task VerifyTokenFromWrongTokenProviderFails() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(phoneNumber: "4251234567"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var token = await manager.GenerateTwoFactorTokenAsync(user, "Phone"); + Assert.NotNull(token); + Assert.False(await manager.VerifyTwoFactorTokenAsync(user, "Email", token)); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyTwoFactorTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); + } - [Fact] - public async Task NullableDateTimeOperationTest() - { - if (ShouldSkipDbTests()) - { - return; - } - var userMgr = CreateManager(); - var user = CreateTestUser(lockoutEnabled: true); - IdentityResultAssert.IsSuccess(await userMgr.CreateAsync(user)); + [Fact] + public async Task VerifyWithWrongSmsTokenFails() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); + var user = CreateTestUser(phoneNumber: "4251234567"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + Assert.False(await manager.VerifyTwoFactorTokenAsync(user, "Phone", "bogus")); + IdentityResultAssert.VerifyLogMessage(manager.Logger, + $"VerifyTwoFactorTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); + } - Assert.Null(await userMgr.GetLockoutEndDateAsync(user)); + [Fact] + public async Task NullableDateTimeOperationTest() + { + if (ShouldSkipDbTests()) + return; + var userMgr = CreateManager(); + var user = CreateTestUser(lockoutEnabled: true); + IdentityResultAssert.IsSuccess(await userMgr.CreateAsync(user)); - // set LockoutDateEndDate to null - await userMgr.SetLockoutEndDateAsync(user, null); - Assert.Null(await userMgr.GetLockoutEndDateAsync(user)); + Assert.Null(await userMgr.GetLockoutEndDateAsync(user)); - // set to a valid value - await userMgr.SetLockoutEndDateAsync(user, DateTimeOffset.Parse("01/01/2014")); - Assert.Equal(DateTimeOffset.Parse("01/01/2014"), await userMgr.GetLockoutEndDateAsync(user)); - } + // set LockoutDateEndDate to null + await userMgr.SetLockoutEndDateAsync(user, null); + Assert.Null(await userMgr.GetLockoutEndDateAsync(user)); - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Fails due to threading bugs in Mono")] - public async Task CanGetUsersWithClaims() - { - if (ShouldSkipDbTests()) - { - return; - } - var manager = CreateManager(); + // set to a valid value + await userMgr.SetLockoutEndDateAsync(user, DateTimeOffset.Parse("01/01/2014")); + Assert.Equal(DateTimeOffset.Parse("01/01/2014"), await userMgr.GetLockoutEndDateAsync(user)); + } - for (int i = 0; i < 6; i++) - { - var user = CreateTestUser(); - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Fails due to threading bugs in Mono")] + public async Task CanGetUsersWithClaims() + { + if (ShouldSkipDbTests()) + return; + var manager = CreateManager(); - if ((i % 2) == 0) - { - IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, new Claim("foo", "bar"))); - } - } + for (var i = 0; i < 6; i++) + { + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - Assert.Equal(3, (await manager.GetUsersForClaimAsync(new Claim("foo", "bar"))).Count); + if (i % 2 == 0) + IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, new Claim("foo", "bar"))); + } - Assert.Equal(0, (await manager.GetUsersForClaimAsync(new Claim("123", "456"))).Count); - } + Assert.Equal(3, (await manager.GetUsersForClaimAsync(new Claim("foo", "bar"))).Count); - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Fails due to threading bugs in Mono")] - public async Task CanGetUsersInRole() - { - if (ShouldSkipDbTests()) - { - return; - } - var context = CreateTestContext(); - var manager = CreateManager(context); - var roleManager = CreateRoleManager(context); - var roles = GenerateRoles("UsersInRole", 4); - var roleNameList = new List(); + Assert.Equal(0, (await manager.GetUsersForClaimAsync(new Claim("123", "456"))).Count); + } - foreach (var role in roles) - { - IdentityResultAssert.IsSuccess(await roleManager.CreateAsync(role)); - roleNameList.Add(await roleManager.GetRoleNameAsync(role)); - } + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Fails due to threading bugs in Mono")] + public async Task CanGetUsersInRole() + { + if (ShouldSkipDbTests()) + return; + var context = CreateTestContext(); + var manager = CreateManager(context); + var roleManager = CreateRoleManager(context); + var roles = GenerateRoles("UsersInRole", 4); + var roleNameList = new List(); + + 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)); + for (var 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)); - } - } + 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); - } + foreach (var role in roles) + Assert.Equal(3, (await manager.GetUsersInRoleAsync(await roleManager.GetRoleNameAsync(role))).Count); - Assert.Equal(0, (await manager.GetUsersInRoleAsync("123456")).Count); - } + Assert.Equal(0, (await manager.GetUsersInRoleAsync("123456")).Count); + } - public List GenerateUsers(string userNamePrefix, int count) - { - var users = new List(count); - for (var i = 0; i < count; i++) - { - users.Add(CreateTestUser(userNamePrefix + i)); - } - return users; - } + public List GenerateUsers(string userNamePrefix, int count) + { + var users = new List(count); + for (var i = 0; i < count; i++) + users.Add(CreateTestUser(userNamePrefix + i)); + return users; + } - public List GenerateRoles(string namePrefix, int count) - { - var roles = new List(count); - for (var i = 0; i < count; i++) - { - roles.Add(CreateTestRole(namePrefix + i)); - } - return roles; - } - } -} + public List GenerateRoles(string namePrefix, int count) + { + var roles = new List(count); + for (var i = 0; i < count; i++) + roles.Add(CreateTestRole(namePrefix + i)); + return roles; + } + } +} \ No newline at end of file From 38c77992b08e5dc3d1320c6b58a930b924bd49e5 Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Wed, 17 May 2017 15:53:33 +0500 Subject: [PATCH 8/8] version --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 944147f3d..e9ea40807 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ cache: - '%USERPROFILE%\.nuget\packages -> **\project.json' environment: - nugetVersion: 1.0.0 + nugetVersion: 1.1.1 version: $(nugetVersion).{build}