diff --git a/.gitignore b/.gitignore index 356b77737..e056f7d87 100644 --- a/.gitignore +++ b/.gitignore @@ -275,9 +275,9 @@ __pycache__/ /src/Skoruba.IdentityServer4.Admin/Data/Migrations/ # Don't ignore these log folders -!/src/Skoruba.IdentityServer4.Admin/Resources/Views/Log/ +!/src/Skoruba.IdentityServer4.Admin.UI/Resources/Views/Log/ !/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Log/ -!/src/Skoruba.IdentityServer4.Admin/Views/Log/ +!**/Views/Log/ !/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/Log/ /src/Skoruba.IdentityServer4.Admin.Api/appsettings.Production.json diff --git a/README.md b/README.md index a282b927e..a7e9a668f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Skoruba.IdentityServer4.Admin -> The administration of the IdentityServer4 and Asp.Net Core Identity +> The administration for the IdentityServer4 and Asp.Net Core Identity ## Project Status @@ -10,30 +10,22 @@ [![Build Status](https://dev.azure.com/skoruba/IdentityServer4.Admin/_apis/build/status/IdentityServer4.Admin-CI?branchName=master)](https://dev.azure.com/skoruba/IdentityServer4.Admin/_build/latest?definitionId=2?branchName=master) [![Join the chat at https://gitter.im/skoruba/IdentityServer4.Admin](https://badges.gitter.im/skoruba/IdentityServer4.Admin.svg)](https://gitter.im/skoruba/IdentityServer4.Admin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -The application is written in the **Asp.Net Core MVC - using .NET Core 3.1** +The application is written in the **Asp.Net Core MVC - using .NET 5** ## Requirements -- [Install](https://www.microsoft.com/net/download/windows#/current) the latest .NET Core 3.x SDK (using older versions may lead to 502.5 errors when hosted on IIS or application exiting immediately after starting when self-hosted) +- [Install](https://www.microsoft.com/net/download/windows#/current) the latest .NET 5 SDK (using older versions may lead to 502.5 errors when hosted on IIS or application exiting immediately after starting when self-hosted) ## Installation via dotnet new template - Install the dotnet new template: -### Stable version 1.0.0 works with **IdentityServer4 version 3** 🚀 - -```sh -dotnet new -i Skoruba.IdentityServer4.Admin.Templates::1.0.0 -``` - -### Beta version 2.0.0 works with **IdentityServer4 version 4** 🚀 +### Version 2.0.0 works with **IdentityServer4 version 4** 🚀 - 🔒 **NOTE:** This version affects your database data if you use the default database migrations that are part of the project - double check the migrations according to your database provider and create a database backup -- The source code for version **2.0.0** is available in the branch [release/2.0.0-beta1](https://github.com/skoruba/IdentityServer4.Admin/tree/release/2.0.0-beta1) - ```sh -dotnet new -i Skoruba.IdentityServer4.Admin.Templates::2.0.0-beta1 +dotnet new -i Skoruba.IdentityServer4.Admin.Templates::2.0.0 ``` ### Create new project: @@ -79,17 +71,21 @@ Project template options: - This administration uses bootstrap 4 -- Admin UI +### Admin UI - Light mode 🌞 + +![Admin-preview](docs/Images/App/1.PNG) -![Admin-preview](docs/Images/App/Skoruba-Home-Preview.PNG) +### Admin UI - Dark mode 🌙 -- Security token service (STS) +![Admin-preview](docs/Images/App/2.PNG) -![Admin-preview](docs/Images/App/Skoruba-STS-Home-Preview.PNG) +### Security token service (STS) -- Forms: +![Admin-preview](docs/Images/App/4.PNG) -![Admin-preview-form](docs/Images/App/Skoruba-Forms-Preview.PNG) +### Forms + +![Admin-preview-form](docs/Images/App/3.png) ## Cloning @@ -170,21 +166,12 @@ docker-compose up -d ### Docker images - Docker images will be available also in [docker hub](https://hub.docker.com/u/skoruba) - - AdminUI: - - **Stable version:** - - `skoruba/identityserver4-admin:1.0.0` - - **Beta version:** - - `skoruba/identityserver4-admin:2.0.0-beta1` + - AdminUI: + - `skoruba/identityserver4-admin:2.0.0` - Admin Api: - - **Stable version:** - - `skoruba/identityserver4-admin-api:1.0.0` - - **Beta version:** - - `skoruba/identityserver4-admin-api:2.0.0-beta1` + - `skoruba/identityserver4-admin-api:2.0.0` - STS: - - **Stable version:** - - `skoruba/identityserver4-sts-identity:1.0.0` - - **Beta version:** - - `skoruba/identityserver4-sts-identity:2.0.0-beta1` + - `skoruba/identityserver4-sts-identity:2.0.0` ### Publish Docker images to Docker hub - Check the script in `build/publish-docker-images.ps1` - change the profile name according to your requirements. @@ -208,6 +195,7 @@ The following Gulp commands are available: - `gulp scripts` - bundle and minify JS - `gulp clean` - remove the `dist` folder - `gulp build` - run the `styles` and `scripts` tasks +- `gulp watch` - watch all changes in all sass files ## EF Core & Data Access @@ -397,6 +385,8 @@ Admin and STS can be customized without editing code in `appsettings.json` under Ui can be customized using themes integrated from [bootswatch](https://bootswatch.com). +From version 2.0.0 is possible to change theme from UI. 🎈 + By default, configuration value is null to use default theme. if you want to use a theme, just fill the lowercase theme name as configuration value of `Theme` key. You can also use your custom theme by integrating it in your project or hosting css on your place to pass the url in `CustomThemeCss` key. (Note that custom theme override standard theme) @@ -600,7 +590,9 @@ Integration tests use StartupTest class which is pre-configured with: - Admin UI: - - `Skoruba.IdentityServer4.Admin` - ASP.NET Core MVC application that contains Admin UI + - `Skoruba.IdentityServer4.Admin.UI` - ASP.NET Core MVC application that contains Admin UI + + - `Skoruba.IdentityServer4.Admin` - ASP.NET Core MVC application that uses Admin UI package and it's only for application bootstrap - `Skoruba.IdentityServer4.Admin.BusinessLogic` - project that contains Dtos, Repositories, Services and Mappers for the IdentityServer4 @@ -608,10 +600,14 @@ Integration tests use StartupTest class which is pre-configured with: - `Skoruba.IdentityServer4.Admin.BusinessLogic.Shared` - project that contains shared Dtos and ExceptionHandling for the Business Logic layer of the IdentityServer4 and Asp.Net Core Identity - - `Skoruba.IdentityServer4.Shared` - Shared common layer for Admin UI, Admin UI Api and STS + - `Skoruba.IdentityServer4.Shared` - Shared common Identity DTOS for Admin UI, Admin UI Api and STS + + - `Skoruba.IdentityServer4.Shared.Configuration` - Shared common layer for Admin UI, Admin UI Api and STS - `Skoruba.IdentityServer4.Admin.EntityFramework` - EF Core data layer that contains Entities for the IdentityServer4 + - `Skoruba.IdentityServer4.Admin.EntityFramework.Configuration` - EF Core data layer that contains configurations + - `Skoruba.IdentityServer4.Admin.EntityFramework.Identity` - EF Core data layer that contains Repositories for the Asp.Net Core Identity - `Skoruba.IdentityServer4.Admin.EntityFramework.Extensions` - project that contains extensions related to EntityFramework @@ -648,7 +644,7 @@ It is possible to define the configuration according the client type - by defaul - Empty - Web Application - Server side - Authorization Code Flow with PKCE - Single Page Application - Javascript - Authorization Code Flow with PKCE -- Native Application - Mobile/Desktop - Hybrid flow +- Native Application - Mobile/Desktop - Authorization Code Flow with PKCE - Machine/Robot - Client Credentials flow - TV and Limited-Input Device Application - Device flow @@ -742,12 +738,16 @@ It is possible to define the configuration according the client type - by defaul ### 2.0.0 - [x] Update to IdentityServer4 version 4 ([#633](https://github.com/skoruba/IdentityServer4.Admin/issues/633)) +- [x] Add support for themes ([#725](https://github.com/skoruba/IdentityServer4.Admin/issues/725)) +- [x] Extract UI part into nuget package ([#770](https://github.com/skoruba/IdentityServer4.Admin/issues/770), [#409](https://github.com/skoruba/IdentityServer4.Admin/issues/409), [#55](https://github.com/skoruba/IdentityServer4.Admin/issues/55), [#322](https://github.com/skoruba/IdentityServer4.Admin/issues/322), [#28](https://github.com/skoruba/IdentityServer4.Admin/issues/28), [#133](https://github.com/skoruba/IdentityServer4.Admin/issues/133)) -### 3.0.0: +### 3.0.0 +- [ ] Connect Admin Api to the Admin UI ([#478](https://github.com/skoruba/IdentityServer4.Admin/issues/478)) + +### 4.0.0: - [ ] Create a project template using dotnet CLI - `dotnet new template` - [ ] Second template: The administration of the IdentityServer4 (without Asp.Net Core Identity) ([#79](https://github.com/skoruba/IdentityServer4.Admin/issues/79)) -- [ ] Connect Admin Api to the Admin UI ([#478](https://github.com/skoruba/IdentityServer4.Admin/issues/478)) - [ ] Add windows authentication ([#479](https://github.com/skoruba/IdentityServer4.Admin/issues/479)) @@ -756,7 +756,7 @@ It is possible to define the configuration according the client type - by defaul - Add UI tests ([#97](https://github.com/skoruba/IdentityServer4.Admin/issues/97), [#116](https://github.com/skoruba/IdentityServer4.Admin/issues/116)) - Add more unit and integration tests :blush: - Extend administration for another protocols -- Create separate UI using `Razor Class Library` ([#28](https://github.com/skoruba/IdentityServer4.Admin/issues/28), [#133](https://github.com/skoruba/IdentityServer4.Admin/issues/133)) + ## Licence diff --git a/Skoruba.IdentityServer4.Admin.sln b/Skoruba.IdentityServer4.Admin.sln index 79c9385a0..a4ef392f4 100644 --- a/Skoruba.IdentityServer4.Admin.sln +++ b/Skoruba.IdentityServer4.Admin.sln @@ -51,6 +51,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Skoruba.IdentityServer4.Adm EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Skoruba.IdentityServer4.Shared", "src\Skoruba.IdentityServer4.Shared\Skoruba.IdentityServer4.Shared.csproj", "{61B285F0-EE06-4AEE-AAF3-71492CBD11C5}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Skoruba.IdentityServer4.Admin.UI", "src\Skoruba.IdentityServer4.Admin.UI\Skoruba.IdentityServer4.Admin.UI.csproj", "{6DD24C2C-0FB5-4C37-8B42-5DACA0FDE4EC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Skoruba.IdentityServer4.Admin.EntityFramework.Configuration", "src\Skoruba.IdentityServer4.Admin.EntityFramework.Configuration\Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.csproj", "{45FB23BE-A7F9-4172-8868-B5E387007644}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Skoruba.IdentityServer4.Shared.Configuration", "src\Skoruba.IdentityServer4.Shared.Configuration\Skoruba.IdentityServer4.Shared.Configuration.csproj", "{D49A2D61-AEEB-457C-B3BA-D1322EB2F4EC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -133,6 +139,18 @@ Global {61B285F0-EE06-4AEE-AAF3-71492CBD11C5}.Debug|Any CPU.Build.0 = Debug|Any CPU {61B285F0-EE06-4AEE-AAF3-71492CBD11C5}.Release|Any CPU.ActiveCfg = Release|Any CPU {61B285F0-EE06-4AEE-AAF3-71492CBD11C5}.Release|Any CPU.Build.0 = Release|Any CPU + {6DD24C2C-0FB5-4C37-8B42-5DACA0FDE4EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6DD24C2C-0FB5-4C37-8B42-5DACA0FDE4EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6DD24C2C-0FB5-4C37-8B42-5DACA0FDE4EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6DD24C2C-0FB5-4C37-8B42-5DACA0FDE4EC}.Release|Any CPU.Build.0 = Release|Any CPU + {45FB23BE-A7F9-4172-8868-B5E387007644}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {45FB23BE-A7F9-4172-8868-B5E387007644}.Debug|Any CPU.Build.0 = Debug|Any CPU + {45FB23BE-A7F9-4172-8868-B5E387007644}.Release|Any CPU.ActiveCfg = Release|Any CPU + {45FB23BE-A7F9-4172-8868-B5E387007644}.Release|Any CPU.Build.0 = Release|Any CPU + {D49A2D61-AEEB-457C-B3BA-D1322EB2F4EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D49A2D61-AEEB-457C-B3BA-D1322EB2F4EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D49A2D61-AEEB-457C-B3BA-D1322EB2F4EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D49A2D61-AEEB-457C-B3BA-D1322EB2F4EC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -156,6 +174,9 @@ Global {0A8A0DB7-0509-4DFB-9201-74398511B481} = {2A514C8F-6A53-41CA-AB41-B644E7BC92A7} {4D123ACB-ACBD-4E40-AE6B-1B0F79D703B0} = {0BC0CC4E-A0F1-45E8-B41A-AE0FA76BF3E5} {61B285F0-EE06-4AEE-AAF3-71492CBD11C5} = {EE588CE5-51D0-4E98-A2B3-40EC8E655931} + {6DD24C2C-0FB5-4C37-8B42-5DACA0FDE4EC} = {588205D4-3A30-4DA4-849D-C7422C396DAA} + {45FB23BE-A7F9-4172-8868-B5E387007644} = {2A514C8F-6A53-41CA-AB41-B644E7BC92A7} + {D49A2D61-AEEB-457C-B3BA-D1322EB2F4EC} = {EE588CE5-51D0-4E98-A2B3-40EC8E655931} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B3166EDE-037B-4C68-BEBA-5DE9C5E3DB82} diff --git a/build/add-migrations.ps1 b/build/add-migrations.ps1 index cca076e0a..b9d56693c 100644 --- a/build/add-migrations.ps1 +++ b/build/add-migrations.ps1 @@ -1,4 +1,4 @@ -param([string] $migration = 'DbInit', [string] $migrationProviderName = 'All') +param([string] $migration = 'DbInit', [string] $migrationProviderName = 'All', [string] $targetContext = 'All') $projectName = "Skoruba.IdentityServer4"; $currentPath = Get-Location Set-Location "../src/$projectName.Admin" @@ -12,7 +12,7 @@ $targetContexts = @{ IdentityServerConfigurationDbContext = "Migrations\IdentityServerConfiguration"; IdentityServerPersistedGrantDbContext = "Migrations\IdentityServerGrants"; AdminAuditLogDbContext = "Migrations\AuditLogging"; - IdentityServerDataProtectionDbContext = "Migrations\DataProtection"; + IdentityServerDataProtectionDbContext = "Migrations\DataProtection"; } #Initialize the db providers and it's respective projects @@ -41,10 +41,14 @@ foreach ($provider in $dpProviders.Keys) { $settings | set-content appsettings.json if ((Test-Path $projectPath) -eq $true) { foreach ($context in $targetContexts.Keys) { - $migrationPath = $targetContexts[$context]; + + if ($targetContext -eq 'All' -or $context -eq $targetContext) { - Write-Host "Migrating context " $context - dotnet ef migrations add $migration -c $context -o $migrationPath -p $projectPath + $migrationPath = $targetContexts[$context]; + + Write-Host "Migrating context " $context + dotnet ef migrations add $migration -c $context -o $migrationPath -p $projectPath + } } } diff --git a/build/create-nuget-packages.ps1 b/build/create-nuget-packages.ps1 index 064e6f0ed..afd2b2ce2 100644 --- a/build/create-nuget-packages.ps1 +++ b/build/create-nuget-packages.ps1 @@ -1,10 +1,17 @@ $packagesOutput = ".\packages" +# Business Logic dotnet pack .\..\src\Skoruba.IdentityServer4.Admin.BusinessLogic\Skoruba.IdentityServer4.Admin.BusinessLogic.csproj -c Release -o $packagesOutput dotnet pack .\..\src\Skoruba.IdentityServer4.Admin.BusinessLogic.Identity\Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.csproj -c Release -o $packagesOutput dotnet pack .\..\src\Skoruba.IdentityServer4.Admin.BusinessLogic.Shared\Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.csproj -c Release -o $packagesOutput +dotnet pack .\..\src\Skoruba.IdentityServer4.Shared.Configuration\Skoruba.IdentityServer4.Shared.Configuration.csproj -c Release -o $packagesOutput +# EF dotnet pack .\..\src\Skoruba.IdentityServer4.Admin.EntityFramework\Skoruba.IdentityServer4.Admin.EntityFramework.csproj -c Release -o $packagesOutput dotnet pack .\..\src\Skoruba.IdentityServer4.Admin.EntityFramework.Extensions\Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.csproj -c Release -o $packagesOutput dotnet pack .\..\src\Skoruba.IdentityServer4.Admin.EntityFramework.Identity\Skoruba.IdentityServer4.Admin.EntityFramework.Identity.csproj -c Release -o $packagesOutput -dotnet pack .\..\src\Skoruba.IdentityServer4.Admin.EntityFramework.Shared\Skoruba.IdentityServer4.Admin.EntityFramework.Shared.csproj -c Release -o $packagesOutput \ No newline at end of file +dotnet pack .\..\src\Skoruba.IdentityServer4.Admin.EntityFramework.Shared\Skoruba.IdentityServer4.Admin.EntityFramework.Shared.csproj -c Release -o $packagesOutput +dotnet pack .\..\src\Skoruba.IdentityServer4.Admin.EntityFramework.Configuration\Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.csproj -c Release -o $packagesOutput + +# UI +dotnet pack .\..\src\Skoruba.IdentityServer4.Admin.UI\Skoruba.IdentityServer4.Admin.UI.csproj -c Release -o $packagesOutput \ No newline at end of file diff --git a/build/publish-nuget-packages.ps1 b/build/publish-nuget-packages.ps1 index 3ec37402b..b70bd63c6 100644 --- a/build/publish-nuget-packages.ps1 +++ b/build/publish-nuget-packages.ps1 @@ -7,4 +7,9 @@ dotnet nuget push ./packages/Skoruba.IdentityServer4.Admin.BusinessLogic.Shared. dotnet nuget push ./packages/Skoruba.IdentityServer4.Admin.EntityFramework.$version.nupkg -k $key -s https://api.nuget.org/v3/index.json dotnet nuget push ./packages/Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.$version.nupkg -k $key -s https://api.nuget.org/v3/index.json dotnet nuget push ./packages/Skoruba.IdentityServer4.Admin.EntityFramework.Identity.$version.nupkg -k $key -s https://api.nuget.org/v3/index.json -dotnet nuget push ./packages/Skoruba.IdentityServer4.Admin.EntityFramework.Shared.$version.nupkg -k $key -s https://api.nuget.org/v3/index.json \ No newline at end of file +dotnet nuget push ./packages/Skoruba.IdentityServer4.Admin.EntityFramework.Shared.$version.nupkg -k $key -s https://api.nuget.org/v3/index.json + +dotnet nuget push ./packages/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.$version.nupkg -k $key -s https://api.nuget.org/v3/index.json +dotnet nuget push ./packages/Skoruba.IdentityServer4.Shared.Configuration.$version.nupkg -k $key -s https://api.nuget.org/v3/index.json + +dotnet nuget push ./packages/Skoruba.IdentityServer4.Admin.UI.$version.nupkg -k $key -s https://api.nuget.org/v3/index.json \ No newline at end of file diff --git a/build/rollback-migrations.ps1 b/build/rollback-migrations.ps1 new file mode 100644 index 000000000..500b7b5a3 --- /dev/null +++ b/build/rollback-migrations.ps1 @@ -0,0 +1,59 @@ +param([string] $migration = 'DbInit', [string] $migrationProviderName = 'All', [string] $targetContext = 'All') +$projectName = "Skoruba.IdentityServer4"; +$currentPath = Get-Location +Set-Location "../src/$projectName.Admin" +Copy-Item appsettings.json -Destination appsettings-backup.json +$settings = Get-Content appsettings.json -raw + +#Initialze db context and define the target directory +$targetContexts = @{ + AdminIdentityDbContext = "Migrations\Identity" + AdminLogDbContext = "Migrations\Logging"; + IdentityServerConfigurationDbContext = "Migrations\IdentityServerConfiguration"; + IdentityServerPersistedGrantDbContext = "Migrations\IdentityServerGrants"; + AdminAuditLogDbContext = "Migrations\AuditLogging"; + IdentityServerDataProtectionDbContext = "Migrations\DataProtection"; +} + +#Initialize the db providers and it's respective projects +$dpProviders = @{ + SqlServer = "..\..\src\$projectName.Admin.EntityFramework.SqlServer\$projectName.Admin.EntityFramework.SqlServer.csproj"; + PostgreSQL = "..\..\src\$projectName.Admin.EntityFramework.PostgreSQL\$projectName.Admin.EntityFramework.PostgreSQL.csproj"; + MySql = "..\..\src\$projectName.Admin.EntityFramework.MySql\$projectName.Admin.EntityFramework.MySql.csproj"; +} + +#Fix issue when the tools is not installed and the nuget package does not work see https://github.com/MicrosoftDocs/azure-docs/issues/40048 +Write-Host "Updating donet ef tools" +$env:Path += " % USERPROFILE % \.dotnet\tools"; +dotnet tool update --global dotnet-ef + +Write-Host "Start migrate projects" +foreach ($provider in $dpProviders.Keys) { + + if ($migrationProviderName -eq 'All' -or $migrationProviderName -eq $provider) { + + $projectPath = (Get-Item -Path $dpProviders[$provider] -Verbose).FullName; + Write-Host "Generate migration for db provider:" $provider ", for project path - " $projectPath + + $providerName = '"ProviderType": "' + $provider + '"' + + $settings = $settings -replace '"ProviderType".*', $providerName + $settings | set-content appsettings.json + if ((Test-Path $projectPath) -eq $true) { + foreach ($context in $targetContexts.Keys) { + + if ($targetContext -eq 'All' -or $context -eq $targetContext) { + + Write-Host "Migrating context " $context + dotnet ef database update $migration -c $context -p $projectPath + } + } + } + + } +} + +Remove-Item appsettings.json +Copy-Item appsettings-backup.json -Destination appsettings.json +Remove-Item appsettings-backup.json +Set-Location $currentPath diff --git a/docker-compose.vs.debug.yml b/docker-compose.vs.debug.yml index 444fb888a..bb47f4fc1 100644 --- a/docker-compose.vs.debug.yml +++ b/docker-compose.vs.debug.yml @@ -5,7 +5,7 @@ services: volumes: - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro labels: - com.microsoft.visualstudio.debuggee.arguments: ' --additionalProbingPath /root/.nuget/packages --additionalProbingPath /root/.nuget/fallbackpackages "bin/Debug/netcoreapp3.1/Skoruba.IdentityServer4.Admin.dll" /seed' + com.microsoft.visualstudio.debuggee.arguments: ' --additionalProbingPath /root/.nuget/packages --additionalProbingPath /root/.nuget/fallbackpackages "bin/Debug/net5.0/Skoruba.IdentityServer4.Admin.dll" /seed' skoruba.identityserver4.admin.api: volumes: diff --git a/docker-compose.vs.release.yml b/docker-compose.vs.release.yml index 444fb888a..bb47f4fc1 100644 --- a/docker-compose.vs.release.yml +++ b/docker-compose.vs.release.yml @@ -5,7 +5,7 @@ services: volumes: - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro labels: - com.microsoft.visualstudio.debuggee.arguments: ' --additionalProbingPath /root/.nuget/packages --additionalProbingPath /root/.nuget/fallbackpackages "bin/Debug/netcoreapp3.1/Skoruba.IdentityServer4.Admin.dll" /seed' + com.microsoft.visualstudio.debuggee.arguments: ' --additionalProbingPath /root/.nuget/packages --additionalProbingPath /root/.nuget/fallbackpackages "bin/Debug/net5.0/Skoruba.IdentityServer4.Admin.dll" /seed' skoruba.identityserver4.admin.api: volumes: diff --git a/docker-compose.yml b/docker-compose.yml index abec58d02..2d8991a87 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -93,7 +93,6 @@ services: - 'ConnectionStrings__IdentityDbConnection=Server=db;Database=IdentityServer4Admin;User Id=sa;Password=${DB_PASSWORD:-Password_123};MultipleActiveResultSets=true' - 'ConnectionStrings__DataProtectionDbConnection=Server=db;Database=IdentityServer4Admin;User Id=sa;Password=${DB_PASSWORD:-Password_123};MultipleActiveResultSets=true' - 'AdminConfiguration__IdentityAdminBaseUrl=https://admin.skoruba.local' - - 'AdvancedConfiguration__PublicOrigin=https://sts.skoruba.local' - 'AdvancedConfiguration__IssuerUri=https://sts.skoruba.local' - DockerConfiguration__UpdateCaCertificate=true - ASPNETCORE_ENVIRONMENT=Development diff --git a/docs/Images/App/1.PNG b/docs/Images/App/1.PNG new file mode 100644 index 000000000..7d14506da Binary files /dev/null and b/docs/Images/App/1.PNG differ diff --git a/docs/Images/App/2.PNG b/docs/Images/App/2.PNG new file mode 100644 index 000000000..8cd6aad42 Binary files /dev/null and b/docs/Images/App/2.PNG differ diff --git a/docs/Images/App/3.png b/docs/Images/App/3.png new file mode 100644 index 000000000..9d9c760e3 Binary files /dev/null and b/docs/Images/App/3.png differ diff --git a/docs/Images/App/4.PNG b/docs/Images/App/4.PNG new file mode 100644 index 000000000..8a936bd7a Binary files /dev/null and b/docs/Images/App/4.PNG differ diff --git a/docs/Images/App/Skoruba-Api-Preview.PNG b/docs/Images/App/Skoruba-Api-Preview.PNG deleted file mode 100644 index eaeb88f7c..000000000 Binary files a/docs/Images/App/Skoruba-Api-Preview.PNG and /dev/null differ diff --git a/docs/Images/App/Skoruba-Client-Edit-Preview.PNG b/docs/Images/App/Skoruba-Client-Edit-Preview.PNG deleted file mode 100644 index c3afc53bd..000000000 Binary files a/docs/Images/App/Skoruba-Client-Edit-Preview.PNG and /dev/null differ diff --git a/docs/Images/App/Skoruba-Client-Preview.PNG b/docs/Images/App/Skoruba-Client-Preview.PNG deleted file mode 100644 index f324d5ce2..000000000 Binary files a/docs/Images/App/Skoruba-Client-Preview.PNG and /dev/null differ diff --git a/docs/Images/App/Skoruba-Forms-Preview.PNG b/docs/Images/App/Skoruba-Forms-Preview.PNG deleted file mode 100644 index d843f83f0..000000000 Binary files a/docs/Images/App/Skoruba-Forms-Preview.PNG and /dev/null differ diff --git a/docs/Images/App/Skoruba-Home-Preview.PNG b/docs/Images/App/Skoruba-Home-Preview.PNG deleted file mode 100644 index ad9258f1b..000000000 Binary files a/docs/Images/App/Skoruba-Home-Preview.PNG and /dev/null differ diff --git a/docs/Images/App/Skoruba-STS-Home-Preview.PNG b/docs/Images/App/Skoruba-STS-Home-Preview.PNG deleted file mode 100644 index 484ce5bac..000000000 Binary files a/docs/Images/App/Skoruba-STS-Home-Preview.PNG and /dev/null differ diff --git a/shared/identityserverdata.json b/shared/identityserverdata.json index b2d5c7ad6..04997e008 100644 --- a/shared/identityserverdata.json +++ b/shared/identityserverdata.json @@ -61,19 +61,22 @@ ] } ], + "ApiScopes": [ + { + "Name": "skoruba_identity_admin_api", + "DisplayName": "skoruba_identity_admin_api", + "Required": true, + "UserClaims": [ + "role", + "name" + ] + } + ], "ApiResources": [ { "Name": "skoruba_identity_admin_api", "Scopes": [ - { - "Name": "skoruba_identity_admin_api", - "DisplayName": "skoruba_identity_admin_api", - "Required": true, - "UserClaims": [ - "role", - "name" - ] - } + "skoruba_identity_admin_api" ] } ], diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Configuration/Test/StartupTest.cs b/src/Skoruba.IdentityServer4.Admin.Api/Configuration/Test/StartupTest.cs index 3769378fb..48f89e89c 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Configuration/Test/StartupTest.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Configuration/Test/StartupTest.cs @@ -1,4 +1,4 @@ -using IdentityServer4.AccessTokenValidation; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; @@ -8,7 +8,6 @@ using Skoruba.IdentityServer4.Admin.Api.Middlewares; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.Entities.Identity; -using Skoruba.IdentityServer4.Shared.Configuration.Identity; namespace Skoruba.IdentityServer4.Admin.Api.Configuration.Test { @@ -32,12 +31,12 @@ public override void RegisterAuthentication(IServiceCollection services) services.AddAuthentication(options => { - options.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; - options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; - options.DefaultSignInScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; - options.DefaultForbidScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; - }).AddCookie(IdentityServerAuthenticationDefaults.AuthenticationScheme); + options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme; + }).AddCookie(JwtBearerDefaults.AuthenticationScheme); } public override void RegisterAuthorization(IServiceCollection services) diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Controllers/ApiResourcesController.cs b/src/Skoruba.IdentityServer4.Admin.Api/Controllers/ApiResourcesController.cs index 3cea3bc3c..5b2830dbf 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Controllers/ApiResourcesController.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Controllers/ApiResourcesController.cs @@ -1,250 +1,184 @@ -using System.Threading.Tasks; -using IdentityServer4.AccessTokenValidation; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Skoruba.IdentityServer4.Admin.Api.Configuration.Constants; -using Skoruba.IdentityServer4.Admin.Api.Dtos.ApiResources; -using Skoruba.IdentityServer4.Admin.Api.ExceptionHandling; -using Skoruba.IdentityServer4.Admin.Api.Mappers; -using Skoruba.IdentityServer4.Admin.Api.Resources; -using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; -using Skoruba.IdentityServer4.Admin.BusinessLogic.Services.Interfaces; - -namespace Skoruba.IdentityServer4.Admin.Api.Controllers -{ - [Route("api/[controller]")] - [ApiController] - [TypeFilter(typeof(ControllerExceptionFilterAttribute))] - [Produces("application/json", "application/problem+json")] - [Authorize(Policy = AuthorizationConsts.AdministrationPolicy)] - public class ApiResourcesController : ControllerBase - { - private readonly IApiResourceService _apiResourceService; - private readonly IApiErrorResources _errorResources; - - public ApiResourcesController(IApiResourceService apiResourceService, IApiErrorResources errorResources) - { - _apiResourceService = apiResourceService; - _errorResources = errorResources; - } - - [HttpGet] - public async Task> Get(string searchText, int page = 1, int pageSize = 10) - { - var apiResourcesDto = await _apiResourceService.GetApiResourcesAsync(searchText, page, pageSize); - var apiResourcesApiDto = apiResourcesDto.ToApiResourceApiModel(); - - return Ok(apiResourcesApiDto); - } - - [HttpGet("{id}")] - public async Task> Get(int id) - { - var apiResourceDto = await _apiResourceService.GetApiResourceAsync(id); - var apiResourceApiDto = apiResourceDto.ToApiResourceApiModel(); - - return Ok(apiResourceApiDto); - } - +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Skoruba.IdentityServer4.Admin.Api.Configuration.Constants; +using Skoruba.IdentityServer4.Admin.Api.Dtos.ApiResources; +using Skoruba.IdentityServer4.Admin.Api.ExceptionHandling; +using Skoruba.IdentityServer4.Admin.Api.Mappers; +using Skoruba.IdentityServer4.Admin.Api.Resources; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Services.Interfaces; + +namespace Skoruba.IdentityServer4.Admin.Api.Controllers +{ + [Route("api/[controller]")] + [ApiController] + [TypeFilter(typeof(ControllerExceptionFilterAttribute))] + [Produces("application/json", "application/problem+json")] + [Authorize(Policy = AuthorizationConsts.AdministrationPolicy)] + public class ApiResourcesController : ControllerBase + { + private readonly IApiResourceService _apiResourceService; + private readonly IApiErrorResources _errorResources; + + public ApiResourcesController(IApiResourceService apiResourceService, IApiErrorResources errorResources) + { + _apiResourceService = apiResourceService; + _errorResources = errorResources; + } + + [HttpGet] + public async Task> Get(string searchText, int page = 1, int pageSize = 10) + { + var apiResourcesDto = await _apiResourceService.GetApiResourcesAsync(searchText, page, pageSize); + var apiResourcesApiDto = apiResourcesDto.ToApiResourceApiModel(); + + return Ok(apiResourcesApiDto); + } + + [HttpGet("{id}")] + public async Task> Get(int id) + { + var apiResourceDto = await _apiResourceService.GetApiResourceAsync(id); + var apiResourceApiDto = apiResourceDto.ToApiResourceApiModel(); + + return Ok(apiResourceApiDto); + } + [HttpPost] - [ProducesResponseType(201)] - [ProducesResponseType(400)] - public async Task Post([FromBody]ApiResourceApiDto apiResourceApi) - { - var apiResourceDto = apiResourceApi.ToApiResourceApiModel(); - - if (!apiResourceDto.Id.Equals(default)) - { - return BadRequest(_errorResources.CannotSetId()); - } - - var apiResourceId = await _apiResourceService.AddApiResourceAsync(apiResourceDto); - apiResourceApi.Id = apiResourceId; - - return CreatedAtAction(nameof(Get), new { id = apiResourceId }, apiResourceApi); - } - - [HttpPut] - public async Task Put([FromBody]ApiResourceApiDto apiResourceApi) - { - var apiResourceDto = apiResourceApi.ToApiResourceApiModel(); - - await _apiResourceService.GetApiResourceAsync(apiResourceDto.Id); - await _apiResourceService.UpdateApiResourceAsync(apiResourceDto); - - return Ok(); - } - - [HttpDelete("{id}")] - public async Task Delete(int id) - { - var apiResourceDto = new ApiResourceDto { Id = id }; - - await _apiResourceService.GetApiResourceAsync(apiResourceDto.Id); - await _apiResourceService.DeleteApiResourceAsync(apiResourceDto); - - return Ok(); - } - - [HttpGet("{id}/Scopes")] - public async Task> GetScopes(int id, int page = 1, int pageSize = 10) - { - var apiScopesDto = await _apiResourceService.GetApiScopesAsync(id, page, pageSize); - var apiScopesApiDto = apiScopesDto.ToApiResourceApiModel(); - - return Ok(apiScopesApiDto); - } - - [HttpGet("{id}/Scopes/{scopeId}")] - public async Task> GetScope(int id, int scopeId) - { - var apiScopesDto = await _apiResourceService.GetApiScopeAsync(id, scopeId); - var apiScopeApiDto = apiScopesDto.ToApiResourceApiModel(); - - return Ok(apiScopeApiDto); - } - - [HttpPost("{id}/Scopes")] - [ProducesResponseType(201)] - [ProducesResponseType(400)] - public async Task PostScope(int id, [FromBody]ApiScopeApiDto apiScopeApi) - { - var apiScope = apiScopeApi.ToApiResourceApiModel(); - apiScope.ApiResourceId = id; - - if (!apiScope.ApiScopeId.Equals(default)) - { - return BadRequest(_errorResources.CannotSetId()); - } - - await _apiResourceService.GetApiResourceAsync(apiScope.ApiResourceId); - var scopeId = await _apiResourceService.AddApiScopeAsync(apiScope); - apiScope.ApiScopeId = scopeId; - - return CreatedAtAction(nameof(GetScope), new { id, scopeId }, apiScope); - } - - [HttpPut("{id}/Scopes")] - public async Task PutScope(int id, [FromBody]ApiScopeApiDto apiScopeApi) - { - var apiScope = apiScopeApi.ToApiResourceApiModel(); - apiScope.ApiResourceId = id; - - await _apiResourceService.GetApiResourceAsync(apiScope.ApiResourceId); - await _apiResourceService.GetApiScopeAsync(apiScope.ApiResourceId, apiScope.ApiScopeId); - - await _apiResourceService.UpdateApiScopeAsync(apiScope); - - return Ok(); - } - - [HttpDelete("{id}/Scopes/{apiScopeId}")] - public async Task DeleteScope(int id, int apiScopeId) - { - var apiScope = new ApiScopesDto { ApiResourceId = id, ApiScopeId = apiScopeId }; - - await _apiResourceService.GetApiResourceAsync(apiScope.ApiResourceId); - await _apiResourceService.GetApiScopeAsync(apiScope.ApiResourceId, apiScope.ApiScopeId); - - await _apiResourceService.DeleteApiScopeAsync(apiScope); - - return Ok(); - } - - [HttpGet("{id}/Secrets")] - public async Task> GetSecrets(int id, int page = 1, int pageSize = 10) - { - var apiSecretsDto = await _apiResourceService.GetApiSecretsAsync(id, page, pageSize); - var apiSecretsApiDto = apiSecretsDto.ToApiResourceApiModel(); - - return Ok(apiSecretsApiDto); - } - - [HttpGet("Secrets/{secretId}")] - public async Task> GetSecret(int secretId) - { - var apiSecretsDto = await _apiResourceService.GetApiSecretAsync(secretId); - var apiSecretApiDto = apiSecretsDto.ToApiResourceApiModel(); - - return Ok(apiSecretApiDto); - } - + [ProducesResponseType(201)] + [ProducesResponseType(400)] + public async Task Post([FromBody]ApiResourceApiDto apiResourceApi) + { + var apiResourceDto = apiResourceApi.ToApiResourceApiModel(); + + if (!apiResourceDto.Id.Equals(default)) + { + return BadRequest(_errorResources.CannotSetId()); + } + + var apiResourceId = await _apiResourceService.AddApiResourceAsync(apiResourceDto); + apiResourceApi.Id = apiResourceId; + + return CreatedAtAction(nameof(Get), new { id = apiResourceId }, apiResourceApi); + } + + [HttpPut] + public async Task Put([FromBody]ApiResourceApiDto apiResourceApi) + { + var apiResourceDto = apiResourceApi.ToApiResourceApiModel(); + + await _apiResourceService.GetApiResourceAsync(apiResourceDto.Id); + await _apiResourceService.UpdateApiResourceAsync(apiResourceDto); + + return Ok(); + } + + [HttpDelete("{id}")] + public async Task Delete(int id) + { + var apiResourceDto = new ApiResourceDto { Id = id }; + + await _apiResourceService.GetApiResourceAsync(apiResourceDto.Id); + await _apiResourceService.DeleteApiResourceAsync(apiResourceDto); + + return Ok(); + } + + [HttpGet("{id}/Secrets")] + public async Task> GetSecrets(int id, int page = 1, int pageSize = 10) + { + var apiSecretsDto = await _apiResourceService.GetApiSecretsAsync(id, page, pageSize); + var apiSecretsApiDto = apiSecretsDto.ToApiResourceApiModel(); + + return Ok(apiSecretsApiDto); + } + + [HttpGet("Secrets/{secretId}")] + public async Task> GetSecret(int secretId) + { + var apiSecretsDto = await _apiResourceService.GetApiSecretAsync(secretId); + var apiSecretApiDto = apiSecretsDto.ToApiResourceApiModel(); + + return Ok(apiSecretApiDto); + } + [HttpPost("{id}/Secrets")] - [ProducesResponseType(201)] - [ProducesResponseType(400)] - public async Task PostSecret(int id, [FromBody]ApiSecretApiDto clientSecretApi) - { - var secretsDto = clientSecretApi.ToApiResourceApiModel(); - secretsDto.ApiResourceId = id; - - if (!secretsDto.ApiSecretId.Equals(default)) - { - return BadRequest(_errorResources.CannotSetId()); - } - + [ProducesResponseType(201)] + [ProducesResponseType(400)] + public async Task PostSecret(int id, [FromBody]ApiSecretApiDto clientSecretApi) + { + var secretsDto = clientSecretApi.ToApiResourceApiModel(); + secretsDto.ApiResourceId = id; + + if (!secretsDto.ApiSecretId.Equals(default)) + { + return BadRequest(_errorResources.CannotSetId()); + } + var secretId = await _apiResourceService.AddApiSecretAsync(secretsDto); clientSecretApi.Id = secretId; - return CreatedAtAction(nameof(GetSecret), new { secretId }, clientSecretApi); - } - - [HttpDelete("Secrets/{secretId}")] - public async Task DeleteSecret(int secretId) - { - var apiSecret = new ApiSecretsDto { ApiSecretId = secretId }; - - await _apiResourceService.GetApiSecretAsync(apiSecret.ApiSecretId); - await _apiResourceService.DeleteApiSecretAsync(apiSecret); - - return Ok(); - } - - [HttpGet("{id}/Properties")] - public async Task> GetProperties(int id, int page = 1, int pageSize = 10) - { - var apiResourcePropertiesDto = await _apiResourceService.GetApiResourcePropertiesAsync(id, page, pageSize); - var apiResourcePropertiesApiDto = apiResourcePropertiesDto.ToApiResourceApiModel(); - - return Ok(apiResourcePropertiesApiDto); - } - - [HttpGet("Properties/{propertyId}")] - public async Task> GetProperty(int propertyId) - { - var apiResourcePropertiesDto = await _apiResourceService.GetApiResourcePropertyAsync(propertyId); - var apiResourcePropertyApiDto = apiResourcePropertiesDto.ToApiResourceApiModel(); - - return Ok(apiResourcePropertyApiDto); - } - + return CreatedAtAction(nameof(GetSecret), new { secretId }, clientSecretApi); + } + + [HttpDelete("Secrets/{secretId}")] + public async Task DeleteSecret(int secretId) + { + var apiSecret = new ApiSecretsDto { ApiSecretId = secretId }; + + await _apiResourceService.GetApiSecretAsync(apiSecret.ApiSecretId); + await _apiResourceService.DeleteApiSecretAsync(apiSecret); + + return Ok(); + } + + [HttpGet("{id}/Properties")] + public async Task> GetProperties(int id, int page = 1, int pageSize = 10) + { + var apiResourcePropertiesDto = await _apiResourceService.GetApiResourcePropertiesAsync(id, page, pageSize); + var apiResourcePropertiesApiDto = apiResourcePropertiesDto.ToApiResourceApiModel(); + + return Ok(apiResourcePropertiesApiDto); + } + + [HttpGet("Properties/{propertyId}")] + public async Task> GetProperty(int propertyId) + { + var apiResourcePropertiesDto = await _apiResourceService.GetApiResourcePropertyAsync(propertyId); + var apiResourcePropertyApiDto = apiResourcePropertiesDto.ToApiResourceApiModel(); + + return Ok(apiResourcePropertyApiDto); + } + [HttpPost("{id}/Properties")] - [ProducesResponseType(201)] - [ProducesResponseType(400)] - public async Task PostProperty(int id, [FromBody]ApiResourcePropertyApiDto apiPropertyApi) - { - var apiResourcePropertiesDto = apiPropertyApi.ToApiResourceApiModel(); - apiResourcePropertiesDto.ApiResourceId = id; - - if (!apiResourcePropertiesDto.ApiResourcePropertyId.Equals(default)) - { - return BadRequest(_errorResources.CannotSetId()); - } - + [ProducesResponseType(201)] + [ProducesResponseType(400)] + public async Task PostProperty(int id, [FromBody]ApiResourcePropertyApiDto apiPropertyApi) + { + var apiResourcePropertiesDto = apiPropertyApi.ToApiResourceApiModel(); + apiResourcePropertiesDto.ApiResourceId = id; + + if (!apiResourcePropertiesDto.ApiResourcePropertyId.Equals(default)) + { + return BadRequest(_errorResources.CannotSetId()); + } + var propertyId = await _apiResourceService.AddApiResourcePropertyAsync(apiResourcePropertiesDto); apiPropertyApi.Id = propertyId; - return CreatedAtAction(nameof(GetProperty), new { propertyId }, apiPropertyApi); - } - - [HttpDelete("Properties/{propertyId}")] - public async Task DeleteProperty(int propertyId) - { - var apiResourceProperty = new ApiResourcePropertiesDto { ApiResourcePropertyId = propertyId }; - - await _apiResourceService.GetApiResourcePropertyAsync(apiResourceProperty.ApiResourcePropertyId); - await _apiResourceService.DeleteApiResourcePropertyAsync(apiResourceProperty); - - return Ok(); - } - } + return CreatedAtAction(nameof(GetProperty), new { propertyId }, apiPropertyApi); + } + + [HttpDelete("Properties/{propertyId}")] + public async Task DeleteProperty(int propertyId) + { + var apiResourceProperty = new ApiResourcePropertiesDto { ApiResourcePropertyId = propertyId }; + + await _apiResourceService.GetApiResourcePropertyAsync(apiResourceProperty.ApiResourcePropertyId); + await _apiResourceService.DeleteApiResourcePropertyAsync(apiResourceProperty); + + return Ok(); + } + } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Controllers/ApiScopesController.cs b/src/Skoruba.IdentityServer4.Admin.Api/Controllers/ApiScopesController.cs new file mode 100644 index 000000000..1093fe33a --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.Api/Controllers/ApiScopesController.cs @@ -0,0 +1,138 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Skoruba.IdentityServer4.Admin.Api.Configuration.Constants; +using Skoruba.IdentityServer4.Admin.Api.Dtos.ApiScopes; +using Skoruba.IdentityServer4.Admin.Api.ExceptionHandling; +using Skoruba.IdentityServer4.Admin.Api.Mappers; +using Skoruba.IdentityServer4.Admin.Api.Resources; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Services.Interfaces; + +namespace Skoruba.IdentityServer4.Admin.Api.Controllers +{ + [Route("api/[controller]")] + [ApiController] + [TypeFilter(typeof(ControllerExceptionFilterAttribute))] + [Produces("application/json", "application/problem+json")] + [Authorize(Policy = AuthorizationConsts.AdministrationPolicy)] + public class ApiScopesController : ControllerBase + { + private readonly IApiErrorResources _errorResources; + private readonly IApiScopeService _apiScopeService; + + public ApiScopesController(IApiErrorResources errorResources, IApiScopeService apiScopeService) + { + _errorResources = errorResources; + _apiScopeService = apiScopeService; + } + + [HttpGet] + public async Task> GetScopes(string search, int page = 1, int pageSize = 10) + { + var apiScopesDto = await _apiScopeService.GetApiScopesAsync(search, page, pageSize); + var apiScopesApiDto = apiScopesDto.ToApiScopeApiModel(); + + return Ok(apiScopesApiDto); + } + + [HttpGet("{id}")] + public async Task> GetScope(int id) + { + var apiScopesDto = await _apiScopeService.GetApiScopeAsync(id); + var apiScopeApiDto = apiScopesDto.ToApiScopeApiModel(); + + return Ok(apiScopeApiDto); + } + + [HttpGet("{id}/Properties")] + public async Task> GetScopeProperties(int id, int page = 1, int pageSize = 10) + { + var apiScopePropertiesDto = await _apiScopeService.GetApiScopePropertiesAsync(id, page, pageSize); + var apiScopePropertiesApiDto = apiScopePropertiesDto.ToApiScopeApiModel(); + + return Ok(apiScopePropertiesApiDto); + } + + [HttpPost] + [ProducesResponseType(201)] + [ProducesResponseType(400)] + public async Task PostScope([FromBody]ApiScopeApiDto apiScopeApi) + { + var apiScope = apiScopeApi.ToApiScopeApiModel(); + + if (!apiScope.Id.Equals(default)) + { + return BadRequest(_errorResources.CannotSetId()); + } + + var id = await _apiScopeService.AddApiScopeAsync(apiScope); + apiScope.Id = id; + + return CreatedAtAction(nameof(GetScope), new {scopeId = id}, apiScope); + } + + [HttpPost("{id}/Properties")] + [ProducesResponseType(201)] + [ProducesResponseType(400)] + public async Task PostProperty(int id, [FromBody]ApiScopePropertyApiDto apiScopePropertyApi) + { + var apiResourcePropertiesDto = apiScopePropertyApi.ToApiScopeApiModel(); + apiResourcePropertiesDto.ApiScopeId = id; + + if (!apiResourcePropertiesDto.ApiScopePropertyId.Equals(default)) + { + return BadRequest(_errorResources.CannotSetId()); + } + + var propertyId = await _apiScopeService.AddApiScopePropertyAsync(apiResourcePropertiesDto); + apiScopePropertyApi.Id = propertyId; + + return CreatedAtAction(nameof(GetProperty), new { propertyId }, apiScopePropertyApi); + } + + [HttpGet("Properties/{propertyId}")] + public async Task> GetProperty(int propertyId) + { + var apiScopePropertyAsync = await _apiScopeService.GetApiScopePropertyAsync(propertyId); + var resourcePropertyApiDto = apiScopePropertyAsync.ToApiScopeApiModel(); + + return Ok(resourcePropertyApiDto); + } + + [HttpDelete("Properties/{propertyId}")] + public async Task DeleteProperty(int propertyId) + { + var apiScopePropertiesDto = new ApiScopePropertiesDto { ApiScopePropertyId = propertyId }; + + await _apiScopeService.GetApiScopePropertyAsync(apiScopePropertiesDto.ApiScopePropertyId); + await _apiScopeService.DeleteApiScopePropertyAsync(apiScopePropertiesDto); + + return Ok(); + } + + [HttpPut] + public async Task PutScope([FromBody]ApiScopeApiDto apiScopeApi) + { + var apiScope = apiScopeApi.ToApiScopeApiModel(); + + await _apiScopeService.GetApiScopeAsync(apiScope.Id); + + await _apiScopeService.UpdateApiScopeAsync(apiScope); + + return Ok(); + } + + [HttpDelete("{id}")] + public async Task DeleteScope(int id) + { + var apiScope = new ApiScopeDto { Id = id }; + + await _apiScopeService.GetApiScopeAsync(apiScope.Id); + + await _apiScopeService.DeleteApiScopeAsync(apiScope); + + return Ok(); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Controllers/ClientsController.cs b/src/Skoruba.IdentityServer4.Admin.Api/Controllers/ClientsController.cs index fd5db733b..b39580852 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Controllers/ClientsController.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Controllers/ClientsController.cs @@ -1,248 +1,246 @@ -using System.Runtime.InteropServices.ComTypes; -using System.Threading.Tasks; -using IdentityServer4.AccessTokenValidation; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Skoruba.IdentityServer4.Admin.Api.Configuration.Constants; -using Skoruba.IdentityServer4.Admin.Api.Dtos.Clients; -using Skoruba.IdentityServer4.Admin.Api.ExceptionHandling; -using Skoruba.IdentityServer4.Admin.Api.Mappers; -using Skoruba.IdentityServer4.Admin.Api.Resources; -using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; -using Skoruba.IdentityServer4.Admin.BusinessLogic.Services.Interfaces; - -namespace Skoruba.IdentityServer4.Admin.Api.Controllers -{ - [Route("api/[controller]")] - [ApiController] - [TypeFilter(typeof(ControllerExceptionFilterAttribute))] - [Produces("application/json", "application/problem+json")] - [Authorize(Policy = AuthorizationConsts.AdministrationPolicy)] - public class ClientsController : ControllerBase - { - private readonly IClientService _clientService; - private readonly IApiErrorResources _errorResources; - - public ClientsController(IClientService clientService, IApiErrorResources errorResources) - { - _clientService = clientService; - _errorResources = errorResources; - } - - [HttpGet] - public async Task> Get(string searchText, int page = 1, int pageSize = 10) - { - var clientsDto = await _clientService.GetClientsAsync(searchText, page, pageSize); - var clientsApiDto = clientsDto.ToClientApiModel(); - - return Ok(clientsApiDto); - } - - [HttpGet("{id}")] - public async Task> Get(int id) - { - var clientDto = await _clientService.GetClientAsync(id); - var clientApiDto = clientDto.ToClientApiModel(); - - return Ok(clientApiDto); - } - +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Skoruba.IdentityServer4.Admin.Api.Configuration.Constants; +using Skoruba.IdentityServer4.Admin.Api.Dtos.Clients; +using Skoruba.IdentityServer4.Admin.Api.ExceptionHandling; +using Skoruba.IdentityServer4.Admin.Api.Mappers; +using Skoruba.IdentityServer4.Admin.Api.Resources; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Services.Interfaces; + +namespace Skoruba.IdentityServer4.Admin.Api.Controllers +{ + [Route("api/[controller]")] + [ApiController] + [TypeFilter(typeof(ControllerExceptionFilterAttribute))] + [Produces("application/json", "application/problem+json")] + [Authorize(Policy = AuthorizationConsts.AdministrationPolicy)] + public class ClientsController : ControllerBase + { + private readonly IClientService _clientService; + private readonly IApiErrorResources _errorResources; + + public ClientsController(IClientService clientService, IApiErrorResources errorResources) + { + _clientService = clientService; + _errorResources = errorResources; + } + + [HttpGet] + public async Task> Get(string searchText, int page = 1, int pageSize = 10) + { + var clientsDto = await _clientService.GetClientsAsync(searchText, page, pageSize); + var clientsApiDto = clientsDto.ToClientApiModel(); + + return Ok(clientsApiDto); + } + + [HttpGet("{id}")] + public async Task> Get(int id) + { + var clientDto = await _clientService.GetClientAsync(id); + var clientApiDto = clientDto.ToClientApiModel(); + + return Ok(clientApiDto); + } + [HttpPost] - [ProducesResponseType(201)] - [ProducesResponseType(400)] - public async Task Post([FromBody]ClientApiDto client) - { - var clientDto = client.ToClientApiModel(); - - if (!clientDto.Id.Equals(default)) - { - return BadRequest(_errorResources.CannotSetId()); - } - - var id = await _clientService.AddClientAsync(clientDto); - client.Id = id; - - return CreatedAtAction(nameof(Get), new { id }, client); - } - - [HttpPut] - public async Task Put([FromBody]ClientApiDto client) - { - var clientDto = client.ToClientApiModel(); - - await _clientService.GetClientAsync(clientDto.Id); - await _clientService.UpdateClientAsync(clientDto); - - return Ok(); - } - - [HttpDelete("{id}")] - public async Task Delete(int id) - { - var clientDto = new ClientDto { Id = id }; - - await _clientService.GetClientAsync(clientDto.Id); - await _clientService.RemoveClientAsync(clientDto); - - return Ok(); - } - + [ProducesResponseType(201)] + [ProducesResponseType(400)] + public async Task Post([FromBody]ClientApiDto client) + { + var clientDto = client.ToClientApiModel(); + + if (!clientDto.Id.Equals(default)) + { + return BadRequest(_errorResources.CannotSetId()); + } + + var id = await _clientService.AddClientAsync(clientDto); + client.Id = id; + + return CreatedAtAction(nameof(Get), new { id }, client); + } + + [HttpPut] + public async Task Put([FromBody]ClientApiDto client) + { + var clientDto = client.ToClientApiModel(); + + await _clientService.GetClientAsync(clientDto.Id); + await _clientService.UpdateClientAsync(clientDto); + + return Ok(); + } + + [HttpDelete("{id}")] + public async Task Delete(int id) + { + var clientDto = new ClientDto { Id = id }; + + await _clientService.GetClientAsync(clientDto.Id); + await _clientService.RemoveClientAsync(clientDto); + + return Ok(); + } + [HttpPost("Clone")] - [ProducesResponseType(201)] - [ProducesResponseType(400)] - public async Task PostClientClone([FromBody]ClientCloneApiDto client) - { - var clientCloneDto = client.ToClientApiModel(); - - var originalClient = await _clientService.GetClientAsync(clientCloneDto.Id); - var id = await _clientService.CloneClientAsync(clientCloneDto); - originalClient.Id = id; - - return CreatedAtAction(nameof(Get), new { id }, originalClient); - } - - [HttpGet("{id}/Secrets")] - public async Task> GetSecrets(int id, int page = 1, int pageSize = 10) - { - var clientSecretsDto = await _clientService.GetClientSecretsAsync(id, page, pageSize); - var clientSecretsApiDto = clientSecretsDto.ToClientApiModel(); - - return Ok(clientSecretsApiDto); - } - - [HttpGet("Secrets/{secretId}")] - public async Task> GetSecret(int secretId) - { - var clientSecretsDto = await _clientService.GetClientSecretAsync(secretId); - var clientSecretDto = clientSecretsDto.ToClientApiModel(); - - return Ok(clientSecretDto); - } - + [ProducesResponseType(201)] + [ProducesResponseType(400)] + public async Task PostClientClone([FromBody]ClientCloneApiDto client) + { + var clientCloneDto = client.ToClientApiModel(); + + var originalClient = await _clientService.GetClientAsync(clientCloneDto.Id); + var id = await _clientService.CloneClientAsync(clientCloneDto); + originalClient.Id = id; + + return CreatedAtAction(nameof(Get), new { id }, originalClient); + } + + [HttpGet("{id}/Secrets")] + public async Task> GetSecrets(int id, int page = 1, int pageSize = 10) + { + var clientSecretsDto = await _clientService.GetClientSecretsAsync(id, page, pageSize); + var clientSecretsApiDto = clientSecretsDto.ToClientApiModel(); + + return Ok(clientSecretsApiDto); + } + + [HttpGet("Secrets/{secretId}")] + public async Task> GetSecret(int secretId) + { + var clientSecretsDto = await _clientService.GetClientSecretAsync(secretId); + var clientSecretDto = clientSecretsDto.ToClientApiModel(); + + return Ok(clientSecretDto); + } + [HttpPost("{id}/Secrets")] - [ProducesResponseType(201)] - [ProducesResponseType(400)] - public async Task PostSecret(int id, [FromBody]ClientSecretApiDto clientSecretApi) - { - var secretsDto = clientSecretApi.ToClientApiModel(); - secretsDto.ClientId = id; - - if (!secretsDto.ClientSecretId.Equals(default)) - { - return BadRequest(_errorResources.CannotSetId()); - } - - var secretId = await _clientService.AddClientSecretAsync(secretsDto); - clientSecretApi.Id = secretId; - - return CreatedAtAction(nameof(GetSecret), new { secretId }, clientSecretApi); - } - - [HttpDelete("Secrets/{secretId}")] - public async Task DeleteSecret(int secretId) - { - var clientSecret = new ClientSecretsDto { ClientSecretId = secretId }; - - await _clientService.GetClientSecretAsync(clientSecret.ClientSecretId); - await _clientService.DeleteClientSecretAsync(clientSecret); - - return Ok(); - } - - [HttpGet("{id}/Properties")] - public async Task> GetProperties(int id, int page = 1, int pageSize = 10) - { - var clientPropertiesDto = await _clientService.GetClientPropertiesAsync(id, page, pageSize); - var clientPropertiesApiDto = clientPropertiesDto.ToClientApiModel(); - - return Ok(clientPropertiesApiDto); - } - - [HttpGet("Properties/{propertyId}")] - public async Task> GetProperty(int propertyId) - { - var clientPropertiesDto = await _clientService.GetClientPropertyAsync(propertyId); - var clientPropertyApiDto = clientPropertiesDto.ToClientApiModel(); - - return Ok(clientPropertyApiDto); - } - + [ProducesResponseType(201)] + [ProducesResponseType(400)] + public async Task PostSecret(int id, [FromBody]ClientSecretApiDto clientSecretApi) + { + var secretsDto = clientSecretApi.ToClientApiModel(); + secretsDto.ClientId = id; + + if (!secretsDto.ClientSecretId.Equals(default)) + { + return BadRequest(_errorResources.CannotSetId()); + } + + var secretId = await _clientService.AddClientSecretAsync(secretsDto); + clientSecretApi.Id = secretId; + + return CreatedAtAction(nameof(GetSecret), new { secretId }, clientSecretApi); + } + + [HttpDelete("Secrets/{secretId}")] + public async Task DeleteSecret(int secretId) + { + var clientSecret = new ClientSecretsDto { ClientSecretId = secretId }; + + await _clientService.GetClientSecretAsync(clientSecret.ClientSecretId); + await _clientService.DeleteClientSecretAsync(clientSecret); + + return Ok(); + } + + [HttpGet("{id}/Properties")] + public async Task> GetProperties(int id, int page = 1, int pageSize = 10) + { + var clientPropertiesDto = await _clientService.GetClientPropertiesAsync(id, page, pageSize); + var clientPropertiesApiDto = clientPropertiesDto.ToClientApiModel(); + + return Ok(clientPropertiesApiDto); + } + + [HttpGet("Properties/{propertyId}")] + public async Task> GetProperty(int propertyId) + { + var clientPropertiesDto = await _clientService.GetClientPropertyAsync(propertyId); + var clientPropertyApiDto = clientPropertiesDto.ToClientApiModel(); + + return Ok(clientPropertyApiDto); + } + [HttpPost("{id}/Properties")] - [ProducesResponseType(201)] - [ProducesResponseType(400)] - public async Task PostProperty(int id, [FromBody]ClientPropertyApiDto clientPropertyApi) - { - var clientPropertiesDto = clientPropertyApi.ToClientApiModel(); - clientPropertiesDto.ClientId = id; - - if (!clientPropertiesDto.ClientPropertyId.Equals(default)) - { - return BadRequest(_errorResources.CannotSetId()); - } - - var propertyId = await _clientService.AddClientPropertyAsync(clientPropertiesDto); - clientPropertyApi.Id = propertyId; - + [ProducesResponseType(201)] + [ProducesResponseType(400)] + public async Task PostProperty(int id, [FromBody]ClientPropertyApiDto clientPropertyApi) + { + var clientPropertiesDto = clientPropertyApi.ToClientApiModel(); + clientPropertiesDto.ClientId = id; + + if (!clientPropertiesDto.ClientPropertyId.Equals(default)) + { + return BadRequest(_errorResources.CannotSetId()); + } + + var propertyId = await _clientService.AddClientPropertyAsync(clientPropertiesDto); + clientPropertyApi.Id = propertyId; + return CreatedAtAction(nameof(GetProperty), new { propertyId }, clientPropertyApi); - } - - [HttpDelete("Properties/{propertyId}")] - public async Task DeleteProperty(int propertyId) - { - var clientProperty = new ClientPropertiesDto { ClientPropertyId = propertyId }; - - await _clientService.GetClientPropertyAsync(clientProperty.ClientPropertyId); - await _clientService.DeleteClientPropertyAsync(clientProperty); - - return Ok(); - } - - [HttpGet("{id}/Claims")] - public async Task> GetClaims(int id, int page = 1, int pageSize = 10) - { - var clientClaimsDto = await _clientService.GetClientClaimsAsync(id, page, pageSize); - var clientClaimsApiDto = clientClaimsDto.ToClientApiModel(); - - return Ok(clientClaimsApiDto); - } - - [HttpGet("Claims/{claimId}")] - public async Task> GetClaim(int claimId) - { - var clientClaimsDto = await _clientService.GetClientClaimAsync(claimId); - var clientClaimApiDto = clientClaimsDto.ToClientApiModel(); - - return Ok(clientClaimApiDto); - } - + } + + [HttpDelete("Properties/{propertyId}")] + public async Task DeleteProperty(int propertyId) + { + var clientProperty = new ClientPropertiesDto { ClientPropertyId = propertyId }; + + await _clientService.GetClientPropertyAsync(clientProperty.ClientPropertyId); + await _clientService.DeleteClientPropertyAsync(clientProperty); + + return Ok(); + } + + [HttpGet("{id}/Claims")] + public async Task> GetClaims(int id, int page = 1, int pageSize = 10) + { + var clientClaimsDto = await _clientService.GetClientClaimsAsync(id, page, pageSize); + var clientClaimsApiDto = clientClaimsDto.ToClientApiModel(); + + return Ok(clientClaimsApiDto); + } + + [HttpGet("Claims/{claimId}")] + public async Task> GetClaim(int claimId) + { + var clientClaimsDto = await _clientService.GetClientClaimAsync(claimId); + var clientClaimApiDto = clientClaimsDto.ToClientApiModel(); + + return Ok(clientClaimApiDto); + } + [HttpPost("{id}/Claims")] - [ProducesResponseType(201)] - [ProducesResponseType(400)] - public async Task PostClaim(int id, [FromBody]ClientClaimApiDto clientClaimApiDto) - { - var clientClaimsDto = clientClaimApiDto.ToClientApiModel(); - clientClaimsDto.ClientId = id; - - if (!clientClaimsDto.ClientClaimId.Equals(default)) - { - return BadRequest(_errorResources.CannotSetId()); - } - - var claimId = await _clientService.AddClientClaimAsync(clientClaimsDto); - clientClaimApiDto.Id = claimId; - + [ProducesResponseType(201)] + [ProducesResponseType(400)] + public async Task PostClaim(int id, [FromBody]ClientClaimApiDto clientClaimApiDto) + { + var clientClaimsDto = clientClaimApiDto.ToClientApiModel(); + clientClaimsDto.ClientId = id; + + if (!clientClaimsDto.ClientClaimId.Equals(default)) + { + return BadRequest(_errorResources.CannotSetId()); + } + + var claimId = await _clientService.AddClientClaimAsync(clientClaimsDto); + clientClaimApiDto.Id = claimId; + return CreatedAtAction(nameof(GetClaim), new { claimId }, clientClaimApiDto); - } - - [HttpDelete("Claims/{claimId}")] - public async Task DeleteClaim(int claimId) - { - var clientClaimsDto = new ClientClaimsDto { ClientClaimId = claimId }; - - await _clientService.GetClientClaimAsync(claimId); - await _clientService.DeleteClientClaimAsync(clientClaimsDto); - - return Ok(); - } - } + } + + [HttpDelete("Claims/{claimId}")] + public async Task DeleteClaim(int claimId) + { + var clientClaimsDto = new ClientClaimsDto { ClientClaimId = claimId }; + + await _clientService.GetClientClaimAsync(claimId); + await _clientService.DeleteClientClaimAsync(clientClaimsDto); + + return Ok(); + } + } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Controllers/IdentityResourcesController.cs b/src/Skoruba.IdentityServer4.Admin.Api/Controllers/IdentityResourcesController.cs index b9fb3fdc5..b08c829fd 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Controllers/IdentityResourcesController.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Controllers/IdentityResourcesController.cs @@ -1,137 +1,136 @@ -using System.Threading.Tasks; -using IdentityServer4.AccessTokenValidation; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Skoruba.IdentityServer4.Admin.Api.Configuration.Constants; -using Skoruba.IdentityServer4.Admin.Api.Dtos.IdentityResources; -using Skoruba.IdentityServer4.Admin.Api.ExceptionHandling; -using Skoruba.IdentityServer4.Admin.Api.Mappers; -using Skoruba.IdentityServer4.Admin.Api.Resources; -using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; -using Skoruba.IdentityServer4.Admin.BusinessLogic.Services.Interfaces; - -namespace Skoruba.IdentityServer4.Admin.Api.Controllers -{ - [Route("api/[controller]")] - [ApiController] - [TypeFilter(typeof(ControllerExceptionFilterAttribute))] - [Produces("application/json", "application/problem+json")] - [Authorize(Policy = AuthorizationConsts.AdministrationPolicy)] - public class IdentityResourcesController : ControllerBase - { - private readonly IIdentityResourceService _identityResourceService; - private readonly IApiErrorResources _errorResources; - - public IdentityResourcesController(IIdentityResourceService identityResourceService, IApiErrorResources errorResources) - { - _identityResourceService = identityResourceService; - _errorResources = errorResources; - } - - [HttpGet] - public async Task> Get(string searchText, int page = 1, int pageSize = 10) - { - var identityResourcesDto = await _identityResourceService.GetIdentityResourcesAsync(searchText, page, pageSize); - var identityResourcesApiDto = identityResourcesDto.ToIdentityResourceApiModel(); - - return Ok(identityResourcesApiDto); - } - - [HttpGet("{id}")] - public async Task> Get(int id) - { - var identityResourceDto = await _identityResourceService.GetIdentityResourceAsync(id); - var identityResourceApiModel = identityResourceDto.ToIdentityResourceApiModel(); - - return Ok(identityResourceApiModel); - } - +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Skoruba.IdentityServer4.Admin.Api.Configuration.Constants; +using Skoruba.IdentityServer4.Admin.Api.Dtos.IdentityResources; +using Skoruba.IdentityServer4.Admin.Api.ExceptionHandling; +using Skoruba.IdentityServer4.Admin.Api.Mappers; +using Skoruba.IdentityServer4.Admin.Api.Resources; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Services.Interfaces; + +namespace Skoruba.IdentityServer4.Admin.Api.Controllers +{ + [Route("api/[controller]")] + [ApiController] + [TypeFilter(typeof(ControllerExceptionFilterAttribute))] + [Produces("application/json", "application/problem+json")] + [Authorize(Policy = AuthorizationConsts.AdministrationPolicy)] + public class IdentityResourcesController : ControllerBase + { + private readonly IIdentityResourceService _identityResourceService; + private readonly IApiErrorResources _errorResources; + + public IdentityResourcesController(IIdentityResourceService identityResourceService, IApiErrorResources errorResources) + { + _identityResourceService = identityResourceService; + _errorResources = errorResources; + } + + [HttpGet] + public async Task> Get(string searchText, int page = 1, int pageSize = 10) + { + var identityResourcesDto = await _identityResourceService.GetIdentityResourcesAsync(searchText, page, pageSize); + var identityResourcesApiDto = identityResourcesDto.ToIdentityResourceApiModel(); + + return Ok(identityResourcesApiDto); + } + + [HttpGet("{id}")] + public async Task> Get(int id) + { + var identityResourceDto = await _identityResourceService.GetIdentityResourceAsync(id); + var identityResourceApiModel = identityResourceDto.ToIdentityResourceApiModel(); + + return Ok(identityResourceApiModel); + } + [HttpPost] - [ProducesResponseType(201)] - [ProducesResponseType(400)] - public async Task Post([FromBody]IdentityResourceApiDto identityResourceApi) - { - var identityResourceDto = identityResourceApi.ToIdentityResourceApiModel(); - - if (!identityResourceDto.Id.Equals(default)) - { - return BadRequest(_errorResources.CannotSetId()); - } - - var id = await _identityResourceService.AddIdentityResourceAsync(identityResourceDto); - identityResourceApi.Id = id; - - return CreatedAtAction(nameof(Get), new { id }, identityResourceApi); - } - - [HttpPut] - public async Task Put([FromBody]IdentityResourceApiDto identityResourceApi) - { - var identityResource = identityResourceApi.ToIdentityResourceApiModel(); - - await _identityResourceService.GetIdentityResourceAsync(identityResource.Id); - await _identityResourceService.UpdateIdentityResourceAsync(identityResource); - - return Ok(); - } - - [HttpDelete("{id}")] - public async Task Delete(int id) - { - var identityResource = new IdentityResourceDto { Id = id }; - - await _identityResourceService.GetIdentityResourceAsync(identityResource.Id); - await _identityResourceService.DeleteIdentityResourceAsync(identityResource); - - return Ok(); - } - - [HttpGet("{id}/Properties")] - public async Task> GetProperties(int id, int page = 1, int pageSize = 10) - { - var identityResourcePropertiesDto = await _identityResourceService.GetIdentityResourcePropertiesAsync(id, page, pageSize); - var identityResourcePropertiesApiDto = identityResourcePropertiesDto.ToIdentityResourceApiModel(); - - return Ok(identityResourcePropertiesApiDto); - } - - [HttpGet("Properties/{propertyId}")] - public async Task> GetProperty(int propertyId) - { - var identityResourcePropertiesDto = await _identityResourceService.GetIdentityResourcePropertyAsync(propertyId); - var identityResourcePropertyApiDto = identityResourcePropertiesDto.ToIdentityResourceApiModel(); - - return Ok(identityResourcePropertyApiDto); - } - + [ProducesResponseType(201)] + [ProducesResponseType(400)] + public async Task Post([FromBody]IdentityResourceApiDto identityResourceApi) + { + var identityResourceDto = identityResourceApi.ToIdentityResourceApiModel(); + + if (!identityResourceDto.Id.Equals(default)) + { + return BadRequest(_errorResources.CannotSetId()); + } + + var id = await _identityResourceService.AddIdentityResourceAsync(identityResourceDto); + identityResourceApi.Id = id; + + return CreatedAtAction(nameof(Get), new { id }, identityResourceApi); + } + + [HttpPut] + public async Task Put([FromBody]IdentityResourceApiDto identityResourceApi) + { + var identityResource = identityResourceApi.ToIdentityResourceApiModel(); + + await _identityResourceService.GetIdentityResourceAsync(identityResource.Id); + await _identityResourceService.UpdateIdentityResourceAsync(identityResource); + + return Ok(); + } + + [HttpDelete("{id}")] + public async Task Delete(int id) + { + var identityResource = new IdentityResourceDto { Id = id }; + + await _identityResourceService.GetIdentityResourceAsync(identityResource.Id); + await _identityResourceService.DeleteIdentityResourceAsync(identityResource); + + return Ok(); + } + + [HttpGet("{id}/Properties")] + public async Task> GetProperties(int id, int page = 1, int pageSize = 10) + { + var identityResourcePropertiesDto = await _identityResourceService.GetIdentityResourcePropertiesAsync(id, page, pageSize); + var identityResourcePropertiesApiDto = identityResourcePropertiesDto.ToIdentityResourceApiModel(); + + return Ok(identityResourcePropertiesApiDto); + } + + [HttpGet("Properties/{propertyId}")] + public async Task> GetProperty(int propertyId) + { + var identityResourcePropertiesDto = await _identityResourceService.GetIdentityResourcePropertyAsync(propertyId); + var identityResourcePropertyApiDto = identityResourcePropertiesDto.ToIdentityResourceApiModel(); + + return Ok(identityResourcePropertyApiDto); + } + [HttpPost("{id}/Properties")] - [ProducesResponseType(201)] - [ProducesResponseType(400)] - public async Task PostProperty(int id, [FromBody]IdentityResourcePropertyApiDto identityResourcePropertyApi) - { - var identityResourcePropertiesDto = identityResourcePropertyApi.ToIdentityResourceApiModel(); - identityResourcePropertiesDto.IdentityResourceId = id; - - if (!identityResourcePropertiesDto.IdentityResourcePropertyId.Equals(default)) - { - return BadRequest(_errorResources.CannotSetId()); - } - - var propertyId = await _identityResourceService.AddIdentityResourcePropertyAsync(identityResourcePropertiesDto); - identityResourcePropertyApi.Id = propertyId; - + [ProducesResponseType(201)] + [ProducesResponseType(400)] + public async Task PostProperty(int id, [FromBody]IdentityResourcePropertyApiDto identityResourcePropertyApi) + { + var identityResourcePropertiesDto = identityResourcePropertyApi.ToIdentityResourceApiModel(); + identityResourcePropertiesDto.IdentityResourceId = id; + + if (!identityResourcePropertiesDto.IdentityResourcePropertyId.Equals(default)) + { + return BadRequest(_errorResources.CannotSetId()); + } + + var propertyId = await _identityResourceService.AddIdentityResourcePropertyAsync(identityResourcePropertiesDto); + identityResourcePropertyApi.Id = propertyId; + return CreatedAtAction(nameof(GetProperty), new { propertyId }, identityResourcePropertyApi); - } - - [HttpDelete("Properties/{propertyId}")] - public async Task DeleteProperty(int propertyId) - { - var identityResourceProperty = new IdentityResourcePropertiesDto { IdentityResourcePropertyId = propertyId }; - - await _identityResourceService.GetIdentityResourcePropertyAsync(identityResourceProperty.IdentityResourcePropertyId); - await _identityResourceService.DeleteIdentityResourcePropertyAsync(identityResourceProperty); - - return Ok(); - } - } + } + + [HttpDelete("Properties/{propertyId}")] + public async Task DeleteProperty(int propertyId) + { + var identityResourceProperty = new IdentityResourcePropertiesDto { IdentityResourcePropertyId = propertyId }; + + await _identityResourceService.GetIdentityResourcePropertyAsync(identityResourceProperty.IdentityResourcePropertyId); + await _identityResourceService.DeleteIdentityResourcePropertyAsync(identityResourceProperty); + + return Ok(); + } + } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Controllers/RolesController.cs b/src/Skoruba.IdentityServer4.Admin.Api/Controllers/RolesController.cs index 8e7341b9e..828dbd583 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Controllers/RolesController.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Controllers/RolesController.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Threading.Tasks; using AutoMapper; -using IdentityServer4.AccessTokenValidation; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Controllers/UsersController.cs b/src/Skoruba.IdentityServer4.Admin.Api/Controllers/UsersController.cs index d03b6d83d..4bfc4796e 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Controllers/UsersController.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Controllers/UsersController.cs @@ -3,8 +3,6 @@ using System.Threading.Tasks; using AutoMapper; using IdentityModel; -using IdentityServer4.AccessTokenValidation; -using IdentityServer4.Extensions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; @@ -198,11 +196,7 @@ public async Task PutUserClaims([FromBody]UserClaimApiDto c { var userClaimDto = _mapper.Map(claim); - if (!userClaimDto.ClaimId.Equals(default)) - { - return BadRequest(_errorResources.CannotSetId()); - } - + await _identityService.GetUserClaimAsync(userClaimDto.UserId.ToString(), userClaimDto.ClaimId); await _identityService.UpdateUserClaimsAsync(userClaimDto); return Ok(); diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Dockerfile b/src/Skoruba.IdentityServer4.Admin.Api/Dockerfile index 7bebebbd7..d672e29de 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Dockerfile +++ b/src/Skoruba.IdentityServer4.Admin.Api/Dockerfile @@ -1,8 +1,9 @@ -FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base +FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base WORKDIR /app EXPOSE 80 +EXPOSE 443 -FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build +FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build WORKDIR /src COPY ["src/Skoruba.IdentityServer4.Admin.Api/Skoruba.IdentityServer4.Admin.Api.csproj", "src/Skoruba.IdentityServer4.Admin.Api/"] COPY ["src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Skoruba.IdentityServer4.Admin.EntityFramework.MySql.csproj", "src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/"] @@ -10,12 +11,14 @@ COPY ["src/Skoruba.IdentityServer4.Admin.EntityFramework.Identity/Skoruba.Identi COPY ["src/Skoruba.IdentityServer4.Admin.EntityFramework/Skoruba.IdentityServer4.Admin.EntityFramework.csproj", "src/Skoruba.IdentityServer4.Admin.EntityFramework/"] COPY ["src/Skoruba.IdentityServer4.Admin.EntityFramework.Extensions/Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.csproj", "src/Skoruba.IdentityServer4.Admin.EntityFramework.Extensions/"] COPY ["src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Skoruba.IdentityServer4.Admin.EntityFramework.Shared.csproj", "src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/"] +COPY ["src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.csproj", "src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/"] COPY ["src/Skoruba.IdentityServer4.Admin.BusinessLogic/Skoruba.IdentityServer4.Admin.BusinessLogic.csproj", "src/Skoruba.IdentityServer4.Admin.BusinessLogic/"] COPY ["src/Skoruba.IdentityServer4.Admin.BusinessLogic.Shared/Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.csproj", "src/Skoruba.IdentityServer4.Admin.BusinessLogic.Shared/"] COPY ["src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL.csproj", "src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/"] +COPY ["src/Skoruba.IdentityServer4.Shared.Configuration/Skoruba.IdentityServer4.Shared.Configuration.csproj", "src/Skoruba.IdentityServer4.Shared.Configuration/"] COPY ["src/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.csproj", "src/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity/"] -COPY ["src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.csproj", "src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/"] COPY ["src/Skoruba.IdentityServer4.Shared/Skoruba.IdentityServer4.Shared.csproj", "src/Skoruba.IdentityServer4.Shared/"] +COPY ["src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.csproj", "src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/"] RUN dotnet restore "src/Skoruba.IdentityServer4.Admin.Api/Skoruba.IdentityServer4.Admin.Api.csproj" COPY . . WORKDIR "/src/src/Skoruba.IdentityServer4.Admin.Api" diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiResources/ApiResourceApiDto.cs b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiResources/ApiResourceApiDto.cs index 2b778f150..da9abd3e9 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiResources/ApiResourceApiDto.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiResources/ApiResourceApiDto.cs @@ -8,6 +8,8 @@ public class ApiResourceApiDto public ApiResourceApiDto() { UserClaims = new List(); + Scopes = new List(); + AllowedAccessTokenSigningAlgorithms = new List(); } public int Id { get; set; } @@ -21,6 +23,12 @@ public ApiResourceApiDto() public bool Enabled { get; set; } = true; + public bool ShowInDiscoveryDocument { get; set; } + public List UserClaims { get; set; } + + public List AllowedAccessTokenSigningAlgorithms { get; set; } + + public List Scopes { get; set; } } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiResources/ApiScopeApiDto.cs b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiResources/ApiScopeApiDto.cs deleted file mode 100644 index b53bb72a6..000000000 --- a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiResources/ApiScopeApiDto.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; - -namespace Skoruba.IdentityServer4.Admin.Api.Dtos.ApiResources -{ - public class ApiScopeApiDto - { - public ApiScopeApiDto() - { - UserClaims = new List(); - } - - public bool ShowInDiscoveryDocument { get; set; } = true; - - public int Id { get; set; } - - [Required] - public string Name { get; set; } - - public string DisplayName { get; set; } - - public string Description { get; set; } - - public bool Required { get; set; } - - public bool Emphasize { get; set; } - - public List UserClaims { get; set; } - } -} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiResources/ApiScopesApiDto.cs b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiResources/ApiScopesApiDto.cs deleted file mode 100644 index 51056753f..000000000 --- a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiResources/ApiScopesApiDto.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; - -namespace Skoruba.IdentityServer4.Admin.Api.Dtos.ApiResources -{ - public class ApiScopesApiDto - { - public ApiScopesApiDto() - { - Scopes = new List(); - } - - public int PageSize { get; set; } - - public int TotalCount { get; set; } - - public List Scopes { get; set; } - } -} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiScopes/ApiScopeApiDto.cs b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiScopes/ApiScopeApiDto.cs new file mode 100644 index 000000000..f2e5a341f --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiScopes/ApiScopeApiDto.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Skoruba.IdentityServer4.Admin.Api.Dtos.ApiScopes +{ + public class ApiScopeApiDto + { + public ApiScopeApiDto() + { + UserClaims = new List(); + } + + public bool ShowInDiscoveryDocument { get; set; } = true; + + public int Id { get; set; } + + [Required] + public string Name { get; set; } + + public string DisplayName { get; set; } + + public string Description { get; set; } + + public bool Required { get; set; } + + public bool Emphasize { get; set; } + + public bool Enabled { get; set; } = true; + + public List UserClaims { get; set; } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiScopes/ApiScopePropertiesApiDto.cs b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiScopes/ApiScopePropertiesApiDto.cs new file mode 100644 index 000000000..d80db30af --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiScopes/ApiScopePropertiesApiDto.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace Skoruba.IdentityServer4.Admin.Api.Dtos.ApiScopes +{ + public class ApiScopePropertiesApiDto + { + public ApiScopePropertiesApiDto() + { + ApiScopeProperties = new List(); + } + + public List ApiScopeProperties { get; set; } = new List(); + + public int TotalCount { get; set; } + + public int PageSize { get; set; } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiScopes/ApiScopePropertyApiDto.cs b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiScopes/ApiScopePropertyApiDto.cs new file mode 100644 index 000000000..f42636571 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiScopes/ApiScopePropertyApiDto.cs @@ -0,0 +1,9 @@ +namespace Skoruba.IdentityServer4.Admin.Api.Dtos.ApiScopes +{ + public class ApiScopePropertyApiDto + { + public int Id { get; set; } + public string Key { get; set; } + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiScopes/ApiScopesApiDto.cs b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiScopes/ApiScopesApiDto.cs new file mode 100644 index 000000000..9a759ce05 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/ApiScopes/ApiScopesApiDto.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace Skoruba.IdentityServer4.Admin.Api.Dtos.ApiScopes +{ + public class ApiScopesApiDto + { + public ApiScopesApiDto() + { + Scopes = new List(); + } + + public int PageSize { get; set; } + + public int TotalCount { get; set; } + + public List Scopes { get; set; } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/Clients/ClientApiDto.cs b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/Clients/ClientApiDto.cs index a10f11ef4..34d56c39a 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/Clients/ClientApiDto.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/Clients/ClientApiDto.cs @@ -94,5 +94,9 @@ public ClientApiDto() public int? UserSsoLifetime { get; set; } public string UserCodeType { get; set; } public int DeviceCodeLifetime { get; set; } = 300; + + public bool RequireRequestObject { get; set; } + + public List AllowedIdentityTokenSigningAlgorithms { get; set; } } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/Clients/ClientSecretApiDto.cs b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/Clients/ClientSecretApiDto.cs index bc3e9046c..f7706ca47 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/Clients/ClientSecretApiDto.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/Clients/ClientSecretApiDto.cs @@ -18,20 +18,7 @@ public class ClientSecretApiDto public string HashType { get; set; } - public HashType HashTypeEnum - { - get - { - HashType result; - - if (Enum.TryParse(HashType, true, out result)) - { - return result; - } - - return Skoruba.IdentityServer4.Admin.EntityFramework.Helpers.HashType.Sha256; - } - } + public HashType HashTypeEnum => Enum.TryParse(HashType, true, out HashType result) ? result : Skoruba.IdentityServer4.Admin.EntityFramework.Helpers.HashType.Sha256; public DateTime? Expiration { get; set; } } diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/PersistedGrants/PersistedGrantApiDto.cs b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/PersistedGrants/PersistedGrantApiDto.cs index 8678ec955..45e9b743c 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Dtos/PersistedGrants/PersistedGrantApiDto.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Dtos/PersistedGrants/PersistedGrantApiDto.cs @@ -12,5 +12,8 @@ public class PersistedGrantApiDto public DateTime CreationTime { get; set; } public DateTime? Expiration { get; set; } public string Data { get; set; } + public DateTime? ConsumedTime { get; set; } + public string SessionId { get; set; } + public string Description { get; set; } } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Helpers/StartupHelpers.cs b/src/Skoruba.IdentityServer4.Admin.Api/Helpers/StartupHelpers.cs index 0ed50c3e6..4a0083357 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Helpers/StartupHelpers.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Helpers/StartupHelpers.cs @@ -1,7 +1,7 @@ using System; using IdentityModel; -using IdentityServer4.AccessTokenValidation; using IdentityServer4.EntityFramework.Options; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; using Microsoft.AspNetCore.HttpOverrides; @@ -21,13 +21,12 @@ using Skoruba.IdentityServer4.Admin.Api.Configuration.Constants; using Skoruba.IdentityServer4.Admin.Api.Helpers.Localization; using Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity; +using Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration; +using Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.MySql; +using Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.PostgreSQL; +using Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.SqlServer; using Skoruba.IdentityServer4.Admin.EntityFramework.Helpers; using Skoruba.IdentityServer4.Admin.EntityFramework.Interfaces; -using Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Extensions; -using Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL.Extensions; -using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.Configuration; -using Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Extensions; -using Skoruba.IdentityServer4.Shared.Configuration.Identity; namespace Skoruba.IdentityServer4.Admin.Api.Helpers { @@ -136,33 +135,29 @@ public static IServiceCollection AddAdminApiCors(this IServiceCollection service /// /// public static void AddDbContexts(this IServiceCollection services, IConfiguration configuration) + TLogDbContext, TAuditLoggingDbContext, TDataProtectionDbContext, TAuditLog>(this IServiceCollection services, IConfiguration configuration) where TIdentityDbContext : DbContext where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext where TLogDbContext : DbContext, IAdminLogDbContext - where TAuditLoggingDbContext : DbContext, IAuditLoggingDbContext + where TAuditLoggingDbContext : DbContext, IAuditLoggingDbContext where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext + where TAuditLog : AuditLog { var databaseProvider = configuration.GetSection(nameof(DatabaseProviderConfiguration)).Get(); - - var identityConnectionString = configuration.GetConnectionString(ConfigurationConsts.IdentityDbConnectionStringKey); - var configurationConnectionString = configuration.GetConnectionString(ConfigurationConsts.ConfigurationDbConnectionStringKey); - var persistedGrantsConnectionString = configuration.GetConnectionString(ConfigurationConsts.PersistedGrantDbConnectionStringKey); - var errorLoggingConnectionString = configuration.GetConnectionString(ConfigurationConsts.AdminLogDbConnectionStringKey); - var auditLoggingConnectionString = configuration.GetConnectionString(ConfigurationConsts.AdminAuditLogDbConnectionStringKey); - var dataProtectionConnectionString = configuration.GetConnectionString(ConfigurationConsts.DataProtectionDbConnectionStringKey); + var databaseMigrations = configuration.GetSection(nameof(DatabaseMigrationsConfiguration)).Get() ?? new DatabaseMigrationsConfiguration(); + var connectionStrings = configuration.GetSection("ConnectionStrings").Get(); switch (databaseProvider.ProviderType) { case DatabaseProviderType.SqlServer: - services.RegisterSqlServerDbContexts(identityConnectionString, configurationConnectionString, persistedGrantsConnectionString, errorLoggingConnectionString, auditLoggingConnectionString, dataProtectionConnectionString); + services.RegisterSqlServerDbContexts(connectionStrings, databaseMigrations); break; case DatabaseProviderType.PostgreSQL: - services.RegisterNpgSqlDbContexts(identityConnectionString, configurationConnectionString, persistedGrantsConnectionString, errorLoggingConnectionString, auditLoggingConnectionString, dataProtectionConnectionString); + services.RegisterNpgSqlDbContexts(connectionStrings, databaseMigrations); break; case DatabaseProviderType.MySql: - services.RegisterMySqlDbContexts(identityConnectionString, configurationConnectionString, persistedGrantsConnectionString, errorLoggingConnectionString, auditLoggingConnectionString, dataProtectionConnectionString); + services.RegisterMySqlDbContexts(connectionStrings, databaseMigrations); break; default: throw new ArgumentOutOfRangeException(nameof(databaseProvider.ProviderType), $@"The value needs to be one of {string.Join(", ", Enum.GetNames(typeof(DatabaseProviderType)))}."); @@ -191,18 +186,18 @@ public static void AddApiAuthentication(this I .AddDefaultTokenProviders(); services.AddAuthentication(options => - { - options.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; - options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; - options.DefaultSignInScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; - options.DefaultForbidScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; - }) - .AddIdentityServerAuthentication(options => + { + options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => { options.Authority = adminApiConfiguration.IdentityServerBaseUrl; - options.ApiName = adminApiConfiguration.OidcApiName; options.RequireHttpsMetadata = adminApiConfiguration.RequireHttpsMetadata; + options.Audience = adminApiConfiguration.OidcApiName; }); } @@ -255,9 +250,9 @@ public static void AddAuthorizationPolicies(this IServiceCollection services) options.AddPolicy(AuthorizationConsts.AdministrationPolicy, policy => policy.RequireAssertion(context => context.User.HasClaim(c => - (c.Type == JwtClaimTypes.Role && c.Value == adminApiConfiguration.AdministrationRole) || - (c.Type == $"client_{JwtClaimTypes.Role}" && c.Value == adminApiConfiguration.AdministrationRole) - ) + ((c.Type == JwtClaimTypes.Role && c.Value == adminApiConfiguration.AdministrationRole) || + (c.Type == $"client_{JwtClaimTypes.Role}" && c.Value == adminApiConfiguration.AdministrationRole)) + ) && context.User.HasClaim(c => c.Type == JwtClaimTypes.Scope && c.Value == adminApiConfiguration.OidcApiName) )); }); } diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Mappers/ApiResourceApiMapperProfile.cs b/src/Skoruba.IdentityServer4.Admin.Api/Mappers/ApiResourceApiMapperProfile.cs index 69f1ad939..7444be73f 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Mappers/ApiResourceApiMapperProfile.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Mappers/ApiResourceApiMapperProfile.cs @@ -15,17 +15,6 @@ public ApiResourceApiMapperProfile() CreateMap(MemberList.Destination) .ReverseMap(); - // Api Scopes - CreateMap(MemberList.Destination) - .ReverseMap(); - - CreateMap(MemberList.Destination) - .ReverseMap(); - - CreateMap(MemberList.Destination) - .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.ApiScopeId)) - .ReverseMap(); - // Api Secrets CreateMap(MemberList.Destination) .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.ApiSecretId)) diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Mappers/ApiScopeApiMapperProfile.cs b/src/Skoruba.IdentityServer4.Admin.Api/Mappers/ApiScopeApiMapperProfile.cs new file mode 100644 index 000000000..f373acf7e --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.Api/Mappers/ApiScopeApiMapperProfile.cs @@ -0,0 +1,30 @@ +using AutoMapper; +using Skoruba.IdentityServer4.Admin.Api.Dtos.ApiScopes; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; + +namespace Skoruba.IdentityServer4.Admin.Api.Mappers +{ + public class ApiScopeApiMapperProfile : Profile + { + public ApiScopeApiMapperProfile() + { + // Api Scopes + CreateMap(MemberList.Destination) + .ReverseMap(); + + CreateMap(MemberList.Destination) + .ReverseMap(); + + // Api Scope Properties + CreateMap(MemberList.Destination) + .ReverseMap(); + + CreateMap(MemberList.Destination) + .ReverseMap(); + + CreateMap(MemberList.Destination) + .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.ApiScopePropertyId)) + .ReverseMap(); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Mappers/ApiScopeApiMappers.cs b/src/Skoruba.IdentityServer4.Admin.Api/Mappers/ApiScopeApiMappers.cs new file mode 100644 index 000000000..47c7cbab0 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.Api/Mappers/ApiScopeApiMappers.cs @@ -0,0 +1,20 @@ +using AutoMapper; + +namespace Skoruba.IdentityServer4.Admin.Api.Mappers +{ + public static class ApiScopeApiMappers + { + static ApiScopeApiMappers() + { + Mapper = new MapperConfiguration(cfg => cfg.AddProfile()) + .CreateMapper(); + } + + internal static IMapper Mapper { get; } + + public static T ToApiScopeApiModel(this object source) + { + return Mapper.Map(source); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Middlewares/AuthenticatedTestRequestMiddleware.cs b/src/Skoruba.IdentityServer4.Admin.Api/Middlewares/AuthenticatedTestRequestMiddleware.cs index 4f3e3b4f0..25b3f7236 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Middlewares/AuthenticatedTestRequestMiddleware.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Middlewares/AuthenticatedTestRequestMiddleware.cs @@ -3,7 +3,7 @@ using System.Security.Claims; using System.Threading.Tasks; using IdentityModel; -using IdentityServer4.AccessTokenValidation; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Http; namespace Skoruba.IdentityServer4.Admin.Api.Middlewares @@ -23,7 +23,7 @@ public async Task Invoke(HttpContext context) { var token = context.Request.Headers[TestAuthorizationHeader].Single(); var jwt = new JwtSecurityToken(token); - var claimsIdentity = new ClaimsIdentity(jwt.Claims, IdentityServerAuthenticationDefaults.AuthenticationScheme, JwtClaimTypes.Name, JwtClaimTypes.Role); + var claimsIdentity = new ClaimsIdentity(jwt.Claims, JwtBearerDefaults.AuthenticationScheme, JwtClaimTypes.Name, JwtClaimTypes.Role); context.User = new ClaimsPrincipal(claimsIdentity); } diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Program.cs b/src/Skoruba.IdentityServer4.Admin.Api/Program.cs index bd431d3c1..02db2e76b 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Program.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Program.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Serilog; -using Skoruba.IdentityServer4.Shared.Helpers; +using Skoruba.IdentityServer4.Shared.Configuration.Helpers; namespace Skoruba.IdentityServer4.Admin.Api { diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Properties/launchSettings.json b/src/Skoruba.IdentityServer4.Admin.Api/Properties/launchSettings.json index b1c7dd47a..250bea8a6 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Properties/launchSettings.json +++ b/src/Skoruba.IdentityServer4.Admin.Api/Properties/launchSettings.json @@ -1,30 +1,30 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "https://localhost:44302", - "sslPort": 44302 - } + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "https://localhost:44302", + "sslPort": 44302 + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } }, - "$schema": "http://json.schemastore.org/launchsettings.json", - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "swagger", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Skoruba.IdentityServer4.Admin.Api": { - "commandName": "Project", - "launchBrowser": true, - "launchUrl": "swagger", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:44302" - } + "Skoruba.IdentityServer4.Admin.Api": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:44302" } -} + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Resources/ApiErrorResource.nl.resx b/src/Skoruba.IdentityServer4.Admin.Api/Resources/ApiErrorResource.nl.resx new file mode 100644 index 000000000..fbe178e7e --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.Api/Resources/ApiErrorResource.nl.resx @@ -0,0 +1,14 @@ + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Skoruba.IdentityServer4.Admin.Api.csproj b/src/Skoruba.IdentityServer4.Admin.Api/Skoruba.IdentityServer4.Admin.Api.csproj index faadd0986..e135c4914 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Skoruba.IdentityServer4.Admin.Api.csproj +++ b/src/Skoruba.IdentityServer4.Admin.Api/Skoruba.IdentityServer4.Admin.Api.csproj @@ -1,8 +1,8 @@  - netcoreapp3.1 - 1.0.0 + net5.0 + 2.0.0 Jan Škoruba InProcess 1cc472a2-4e4b-48ce-846b-5219f71fc643 @@ -12,38 +12,38 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + - - - - + + + + + - + - - + @@ -54,6 +54,7 @@ + @@ -75,3 +76,11 @@ + + + + + + + + diff --git a/src/Skoruba.IdentityServer4.Admin.Api/Startup.cs b/src/Skoruba.IdentityServer4.Admin.Api/Startup.cs index 63b95040b..e4b2feda4 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/Startup.cs +++ b/src/Skoruba.IdentityServer4.Admin.Api/Startup.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; using HealthChecks.UI.Client; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -19,9 +18,9 @@ using Skoruba.IdentityServer4.Admin.Api.Resources; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.Entities.Identity; +using Skoruba.IdentityServer4.Shared.Configuration.Helpers; using Skoruba.IdentityServer4.Shared.Dtos; using Skoruba.IdentityServer4.Shared.Dtos.Identity; -using Skoruba.IdentityServer4.Shared.Helpers; namespace Skoruba.IdentityServer4.Admin.Api { @@ -29,6 +28,7 @@ public class Startup { public Startup(IWebHostEnvironment env, IConfiguration configuration) { + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); HostingEnvironment = env; Configuration = configuration; } @@ -134,7 +134,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, AdminApi app.UseAuthorization(); app.UseEndpoints(endpoints => { - endpoints.MapDefaultControllerRoute(); + endpoints.MapControllers(); + endpoints.MapHealthChecks("/health", new HealthCheckOptions { ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse @@ -144,7 +145,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, AdminApi public virtual void RegisterDbContexts(IServiceCollection services) { - services.AddDbContexts(Configuration); + services.AddDbContexts(Configuration); } public virtual void RegisterAuthentication(IServiceCollection services) diff --git a/src/Skoruba.IdentityServer4.Admin.Api/appsettings.json b/src/Skoruba.IdentityServer4.Admin.Api/appsettings.json index 06a004bb1..50d8c8ccc 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/appsettings.json +++ b/src/Skoruba.IdentityServer4.Admin.Api/appsettings.json @@ -56,6 +56,7 @@ "AzureKeyVaultEndpoint": "", "ClientId": "", "ClientSecret": "", + "TenantId": "", "UseClientCredentials": true, "DataProtectionKeyIdentifier": "", "ReadConfigurationFromKeyVault": false diff --git a/src/Skoruba.IdentityServer4.Admin.Api/serilog.json b/src/Skoruba.IdentityServer4.Admin.Api/serilog.json index 9cb47c7c7..acc5d925f 100644 --- a/src/Skoruba.IdentityServer4.Admin.Api/serilog.json +++ b/src/Skoruba.IdentityServer4.Admin.Api/serilog.json @@ -13,7 +13,7 @@ { "Name": "File", "Args": { - "path": "Log\\skoruba_admin.txt", + "path": "Log/skoruba_admin.txt", "rollingInterval": "Day" } }, diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity/Dtos/Grant/PersistedGrantDto.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity/Dtos/Grant/PersistedGrantDto.cs index 59ab8668a..3f2293c37 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity/Dtos/Grant/PersistedGrantDto.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity/Dtos/Grant/PersistedGrantDto.cs @@ -2,15 +2,18 @@ namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Grant { - public class PersistedGrantDto - { - public string Key { get; set; } - public string Type { get; set; } - public string SubjectId { get; set; } - public string SubjectName { get; set; } - public string ClientId { get; set; } - public DateTime CreationTime { get; set; } - public DateTime? Expiration { get; set; } - public string Data { get; set; } - } + public class PersistedGrantDto + { + public string Key { get; set; } + public string Type { get; set; } + public string SubjectId { get; set; } + public string SubjectName { get; set; } + public string ClientId { get; set; } + public DateTime CreationTime { get; set; } + public DateTime? Expiration { get; set; } + public string Data { get; set; } + public DateTime? ConsumedTime { get; set; } + public string SessionId { get; set; } + public string Description { get; set; } + } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.csproj b/src/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.csproj index 03879551b..251e3fb53 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.csproj +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity/Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.csproj @@ -1,8 +1,8 @@  - netcoreapp3.1 - 1.0.0 + net5.0 + 2.0.0 Jan Škoruba Business Logic layer for the administration of the Asp.Net Core Identity and IdentityServer4 IdentityServer4 Admin OpenIDConnect OAuth2 Identity @@ -12,8 +12,8 @@ - - + + @@ -33,3 +33,11 @@ + + + + + + + + diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic.Shared/Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.csproj b/src/Skoruba.IdentityServer4.Admin.BusinessLogic.Shared/Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.csproj index 679154900..211ed45d0 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic.Shared/Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.csproj +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic.Shared/Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.csproj @@ -1,8 +1,8 @@  - netcoreapp3.1 - 1.0.0 + net5.0 + 2.0.0 Jan Škoruba IdentityServer4 Admin OpenIDConnect OAuth2 Identity Shared Business Logic layer for the administration of the IdentityServer4 and Asp.Net Core Identity @@ -16,3 +16,11 @@ + + + + + + + + diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiResourceDto.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiResourceDto.cs index 7fe17e0ce..5cb18cb18 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiResourceDto.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiResourceDto.cs @@ -8,6 +8,8 @@ public class ApiResourceDto public ApiResourceDto() { UserClaims = new List(); + Scopes = new List(); + AllowedAccessTokenSigningAlgorithms = new List(); } public int Id { get; set; } @@ -24,5 +26,15 @@ public ApiResourceDto() public List UserClaims { get; set; } public string UserClaimsItems { get; set; } + + public bool ShowInDiscoveryDocument { get; set; } + + public List AllowedAccessTokenSigningAlgorithms { get; set; } + + public string AllowedAccessTokenSigningAlgorithmsItems { get; set; } + + public List Scopes { get; set; } + + public string ScopesItems { get; set; } } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopeDto.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopeDto.cs index 905fc5c02..490460109 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopeDto.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopeDto.cs @@ -26,5 +26,11 @@ public ApiScopeDto() public bool Emphasize { get; set; } public List UserClaims { get; set; } + + public string UserClaimsItems { get; set; } + + public bool Enabled { get; set; } = true; + + public List ApiScopeProperties { get; set; } } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopePropertiesDto.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopePropertiesDto.cs new file mode 100644 index 000000000..32072ea66 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopePropertiesDto.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration +{ + public class ApiScopePropertiesDto + { + public int ApiScopePropertyId { get; set; } + + public int ApiScopeId { get; set; } + + public string ApiScopeName { get; set; } + + [Required] + public string Key { get; set; } + + [Required] + public string Value { get; set; } + + public List ApiScopeProperties { get; set; } = new List(); + + public int TotalCount { get; set; } + + public int PageSize { get; set; } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopePropertyDto.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopePropertyDto.cs new file mode 100644 index 000000000..673f55fe0 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopePropertyDto.cs @@ -0,0 +1,9 @@ +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration +{ + public class ApiScopePropertyDto + { + public int Id { get; set; } + public string Key { get; set; } + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopesDto.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopesDto.cs index cbfa15c58..7216f4217 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopesDto.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiScopesDto.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration { @@ -8,36 +7,12 @@ public class ApiScopesDto public ApiScopesDto() { Scopes = new List(); - UserClaims = new List(); } - - public int ApiResourceId { get; set; } - - public string ResourceName { get; set; } - - public bool ShowInDiscoveryDocument { get; set; } = true; - - public int ApiScopeId { get; set; } - - [Required] - public string Name { get; set; } - - public string DisplayName { get; set; } - - public string Description { get; set; } - - public bool Required { get; set; } - - public bool Emphasize { get; set; } - + public int PageSize { get; set; } public int TotalCount { get; set; } public List Scopes { get; set; } - - public List UserClaims { get; set; } - - public string UserClaimsItems { get; set; } } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiSecretsDto.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiSecretsDto.cs index c79ec20a6..c43a62f46 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiSecretsDto.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ApiSecretsDto.cs @@ -31,22 +31,9 @@ public ApiSecretsDto() public string HashType { get; set; } - public HashType HashTypeEnum - { - get - { - HashType result; - - if (Enum.TryParse(HashType, true, out result)) - { - return result; - } - - return EntityFramework.Helpers.HashType.Sha256; - } - } - - public List HashTypes { get; set; } + public HashType HashTypeEnum => Enum.TryParse(HashType, true, out HashType result) ? result : EntityFramework.Helpers.HashType.Sha256; + + public List HashTypes { get; set; } public DateTime? Expiration { get; set; } diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ClientDto.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ClientDto.cs index d11d5a61c..55c75283d 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ClientDto.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ClientDto.cs @@ -112,5 +112,11 @@ public ClientDto() public int DeviceCodeLifetime { get; set; } = 300; public bool NonEditable { get; set; } + + public bool RequireRequestObject { get; set; } + + public List AllowedIdentityTokenSigningAlgorithms { get; set; } + + public string AllowedIdentityTokenSigningAlgorithmsItems { get; set; } } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ClientSecretsDto.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ClientSecretsDto.cs index bf78b6f5a..cde11176f 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ClientSecretsDto.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Configuration/ClientSecretsDto.cs @@ -31,22 +31,9 @@ public ClientSecretsDto() public string HashType { get; set; } - public HashType HashTypeEnum - { - get - { - HashType result; - - if (Enum.TryParse(HashType, true, out result)) - { - return result; - } - - return EntityFramework.Helpers.HashType.Sha256; - } - } - - public List HashTypes { get; set; } + public HashType HashTypeEnum => Enum.TryParse(HashType, true, out HashType result) ? result : EntityFramework.Helpers.HashType.Sha256; + + public List HashTypes { get; set; } public DateTime? Expiration { get; set; } diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Grant/PersistedGrantDto.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Grant/PersistedGrantDto.cs index c1cc47f1c..91d3ded55 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Grant/PersistedGrantDto.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Dtos/Grant/PersistedGrantDto.cs @@ -12,5 +12,8 @@ public class PersistedGrantDto public DateTime CreationTime { get; set; } public DateTime? Expiration { get; set; } public string Data { get; set; } + public DateTime? ConsumedTime { get; set; } + public string SessionId { get; set; } + public string Description { get; set; } } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopeAddedEvent.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopeAddedEvent.cs deleted file mode 100644 index 1376c4566..000000000 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopeAddedEvent.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Skoruba.AuditLogging.Events; -using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; - -namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiResource -{ - public class ApiScopeAddedEvent : AuditEvent - { - public ApiScopesDto ApiScope { get; set; } - - public ApiScopeAddedEvent(ApiScopesDto apiScope) - { - ApiScope = apiScope; - } - } -} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopeDeletedEvent.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopeDeletedEvent.cs deleted file mode 100644 index db8407d0d..000000000 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopeDeletedEvent.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Skoruba.AuditLogging.Events; -using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; - -namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiResource -{ - public class ApiScopeDeletedEvent : AuditEvent - { - public ApiScopesDto ApiScope { get; set; } - - public ApiScopeDeletedEvent(ApiScopesDto apiScope) - { - ApiScope = apiScope; - } - } -} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopeRequestedEvent.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopeRequestedEvent.cs deleted file mode 100644 index 5886f3e17..000000000 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopeRequestedEvent.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Skoruba.AuditLogging.Events; -using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; - -namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiResource -{ - public class ApiScopeRequestedEvent : AuditEvent - { - public ApiScopesDto ApiScopes { get; set; } - - public ApiScopeRequestedEvent(ApiScopesDto apiScopes) - { - ApiScopes = apiScopes; - } - } -} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopeUpdatedEvent.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopeUpdatedEvent.cs deleted file mode 100644 index 6580a6d34..000000000 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopeUpdatedEvent.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Skoruba.AuditLogging.Events; -using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; - -namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiResource -{ - public class ApiScopeUpdatedEvent : AuditEvent - { - public ApiScopesDto OriginalApiScope { get; set; } - public ApiScopesDto ApiScope { get; set; } - - public ApiScopeUpdatedEvent(ApiScopesDto originalApiScope, ApiScopesDto apiScope) - { - OriginalApiScope = originalApiScope; - ApiScope = apiScope; - } - } -} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopeAddedEvent.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopeAddedEvent.cs new file mode 100644 index 000000000..a4127b9ec --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopeAddedEvent.cs @@ -0,0 +1,15 @@ +using Skoruba.AuditLogging.Events; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiScope +{ + public class ApiScopeAddedEvent : AuditEvent + { + public ApiScopeDto ApiScope { get; set; } + + public ApiScopeAddedEvent(ApiScopeDto apiScope) + { + ApiScope = apiScope; + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopeDeletedEvent.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopeDeletedEvent.cs new file mode 100644 index 000000000..11ac421f4 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopeDeletedEvent.cs @@ -0,0 +1,15 @@ +using Skoruba.AuditLogging.Events; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiScope +{ + public class ApiScopeDeletedEvent : AuditEvent + { + public ApiScopeDto ApiScope { get; set; } + + public ApiScopeDeletedEvent(ApiScopeDto apiScope) + { + ApiScope = apiScope; + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopePropertiesRequestedEvent.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopePropertiesRequestedEvent.cs new file mode 100644 index 000000000..fc113d7cf --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopePropertiesRequestedEvent.cs @@ -0,0 +1,17 @@ +using Skoruba.AuditLogging.Events; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiScope +{ + public class ApiScopePropertiesRequestedEvent : AuditEvent + { + public ApiScopePropertiesRequestedEvent(int apiScopeId, ApiScopePropertiesDto apiScopeProperties) + { + ApiScopeId = apiScopeId; + ApiResourceProperties = apiScopeProperties; + } + + public int ApiScopeId { get; set; } + public ApiScopePropertiesDto ApiResourceProperties { get; } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopePropertyAddedEvent.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopePropertyAddedEvent.cs new file mode 100644 index 000000000..f6b3e4cfb --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopePropertyAddedEvent.cs @@ -0,0 +1,15 @@ +using Skoruba.AuditLogging.Events; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiScope +{ + public class ApiScopePropertyAddedEvent : AuditEvent + { + public ApiScopePropertyAddedEvent(ApiScopePropertiesDto apiScopeProperty) + { + ApiScopeProperty = apiScopeProperty; + } + + public ApiScopePropertiesDto ApiScopeProperty { get; set; } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopePropertyDeletedEvent.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopePropertyDeletedEvent.cs new file mode 100644 index 000000000..50654abcd --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopePropertyDeletedEvent.cs @@ -0,0 +1,15 @@ +using Skoruba.AuditLogging.Events; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiScope +{ + public class ApiScopePropertyDeletedEvent : AuditEvent + { + public ApiScopePropertyDeletedEvent(ApiScopePropertiesDto apiScopeProperty) + { + ApiScopeProperty = apiScopeProperty; + } + + public ApiScopePropertiesDto ApiScopeProperty { get; set; } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopePropertyRequestedEvent.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopePropertyRequestedEvent.cs new file mode 100644 index 000000000..df30c587c --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopePropertyRequestedEvent.cs @@ -0,0 +1,18 @@ +using Skoruba.AuditLogging.Events; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiScope +{ + public class ApiScopePropertyRequestedEvent : AuditEvent + { + public ApiScopePropertyRequestedEvent(int apiScopePropertyId, ApiScopePropertiesDto apiScopeProperty) + { + ApiScopePropertyId = apiScopePropertyId; + ApiScopeProperty = apiScopeProperty; + } + + public int ApiScopePropertyId { get; set; } + + public ApiScopePropertiesDto ApiScopeProperty { get; set; } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopeRequestedEvent.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopeRequestedEvent.cs new file mode 100644 index 000000000..a83f97f40 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopeRequestedEvent.cs @@ -0,0 +1,15 @@ +using Skoruba.AuditLogging.Events; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiScope +{ + public class ApiScopeRequestedEvent : AuditEvent + { + public ApiScopeDto ApiScopes { get; set; } + + public ApiScopeRequestedEvent(ApiScopeDto apiScopes) + { + ApiScopes = apiScopes; + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopeUpdatedEvent.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopeUpdatedEvent.cs new file mode 100644 index 000000000..8e451662f --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopeUpdatedEvent.cs @@ -0,0 +1,17 @@ +using Skoruba.AuditLogging.Events; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiScope +{ + public class ApiScopeUpdatedEvent : AuditEvent + { + public ApiScopeDto OriginalApiScope { get; set; } + public ApiScopeDto ApiScope { get; set; } + + public ApiScopeUpdatedEvent(ApiScopeDto originalApiScope, ApiScopeDto apiScope) + { + OriginalApiScope = originalApiScope; + ApiScope = apiScope; + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopesRequestedEvent.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopesRequestedEvent.cs similarity index 97% rename from src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopesRequestedEvent.cs rename to src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopesRequestedEvent.cs index f5eaace1b..b69944b11 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiResource/ApiScopesRequestedEvent.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Events/ApiScope/ApiScopesRequestedEvent.cs @@ -1,7 +1,7 @@ using Skoruba.AuditLogging.Events; using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; -namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiResource +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiScope { public class ApiScopesRequestedEvent : AuditEvent { diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Extensions/AdminServicesExtensions.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Extensions/AdminServicesExtensions.cs index 55e49cfe7..a5ffa2496 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Extensions/AdminServicesExtensions.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Extensions/AdminServicesExtensions.cs @@ -27,18 +27,21 @@ public static IServiceCollection AddAdminServices>(); services.AddTransient>(); services.AddTransient>(); + services.AddTransient>(); services.AddTransient>(); services.AddTransient>(); //Services services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); //Resources services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiResourceMapperProfile.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiResourceMapperProfile.cs index 40269e396..dbe5f0d2c 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiResourceMapperProfile.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiResourceMapperProfile.cs @@ -7,6 +7,7 @@ using AutoMapper; using IdentityServer4.EntityFramework.Entities; using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Mappers.Converters; using Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.Common; namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Mappers @@ -17,22 +18,18 @@ public ApiResourceMapperProfile() { // entity to model CreateMap(MemberList.Destination) - .ForMember(x => x.UserClaims, opts => opts.MapFrom(src => src.UserClaims.Select(x => x.Type))); - - CreateMap(MemberList.Destination) - .ForMember(x => x.UserClaims, opt => opt.MapFrom(src => src.UserClaims.Select(x => x.Type))) - .ForMember(x => x.ApiResourceId, opt => opt.MapFrom(src => src.ApiResource.Id)) - .ForMember(x => x.ApiScopeId, opt => opt.MapFrom(src => src.Id)); - - CreateMap(MemberList.Destination) - .ForMember(x => x.UserClaims, opt => opt.MapFrom(src => src.UserClaims.Select(x => x.Type))); - - CreateMap(MemberList.Destination) + .ForMember(x => x.UserClaims, opts => opts.MapFrom(src => src.UserClaims.Select(x => x.Type))) + .ForMember(x => x.Scopes, opts => opts.MapFrom(src => src.Scopes.Select(x => x.Scope))) + .ForMember(x => x.AllowedAccessTokenSigningAlgorithms, + opts => opts.ConvertUsing(AllowedSigningAlgorithmsConverter.Converter, + x => x.AllowedAccessTokenSigningAlgorithms)); + + CreateMap(MemberList.Destination) .ForMember(dest => dest.Type, opt => opt.Condition(srs => srs != null)) .ForMember(x => x.ApiSecretId, opt => opt.MapFrom(x => x.Id)) .ForMember(x => x.ApiResourceId, opt => opt.MapFrom(x => x.ApiResource.Id)); - CreateMap(MemberList.Destination) + CreateMap(MemberList.Destination) .ForMember(dest => dest.Type, opt => opt.Condition(srs => srs != null)); CreateMap(MemberList.Destination) @@ -47,10 +44,7 @@ public ApiResourceMapperProfile() CreateMap, ApiResourcesDto>(MemberList.Destination) .ForMember(x => x.ApiResources, opt => opt.MapFrom(src => src.Data)); - CreateMap, ApiScopesDto>(MemberList.Destination) - .ForMember(x => x.Scopes, opt => opt.MapFrom(src => src.Data)); - - CreateMap, ApiSecretsDto>(MemberList.Destination) + CreateMap, ApiSecretsDto>(MemberList.Destination) .ForMember(x => x.ApiSecrets, opt => opt.MapFrom(src => src.Data)); CreateMap, ApiResourcePropertiesDto>(MemberList.Destination) @@ -58,19 +52,16 @@ public ApiResourceMapperProfile() // model to entity CreateMap(MemberList.Source) - .ForMember(x => x.UserClaims, opts => opts.MapFrom(src => src.UserClaims.Select(x => new ApiResourceClaim { Type = x }))); + .ForMember(x => x.UserClaims, opts => opts.MapFrom(src => src.UserClaims.Select(x => new ApiResourceClaim { Type = x }))) + .ForMember(x => x.Scopes, opts => opts.MapFrom(src => src.Scopes.Select(x => new ApiResourceScope { Scope = x}))) + .ForMember(x => x.AllowedAccessTokenSigningAlgorithms, + opts => opts.ConvertUsing(AllowedSigningAlgorithmsConverter.Converter, + x => x.AllowedAccessTokenSigningAlgorithms)); - CreateMap(MemberList.Source) + CreateMap(MemberList.Source) .ForMember(x => x.ApiResource, opts => opts.MapFrom(src => new ApiResource() { Id = src.ApiResourceId })) .ForMember(x => x.Id, opt => opt.MapFrom(src => src.ApiSecretId)); - CreateMap(MemberList.Source) - .ForMember(x => x.UserClaims, opts => opts.MapFrom(src => src.UserClaims.Select(x => new ApiScopeClaim { Type = x }))) - .ForMember(x => x.Id, opt => opt.MapFrom(src => src.ApiScopeId)); - - CreateMap(MemberList.Source) - .ForMember(x => x.UserClaims, opts => opts.MapFrom(src => src.UserClaims.Select(x => new ApiScopeClaim { Type = x }))); - CreateMap(MemberList.Source) .ForMember(x => x.ApiResource, dto => dto.MapFrom(src => new ApiResource() { Id = src.ApiResourceId })) .ForMember(x => x.Id, opt => opt.MapFrom(src => src.ApiResourcePropertyId)); diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiResourceMappers.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiResourceMappers.cs index e5d5295cd..b49def1af 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiResourceMappers.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiResourceMappers.cs @@ -35,22 +35,12 @@ public static ApiResourcePropertiesDto ToModel(this ApiResourceProperty apiResou return Mapper.Map(apiResourceProperty); } - public static ApiSecretsDto ToModel(this PagedList secrets) + public static ApiSecretsDto ToModel(this PagedList secrets) { return secrets == null ? null : Mapper.Map(secrets); } - public static ApiScopesDto ToModel(this PagedList scopes) - { - return scopes == null ? null : Mapper.Map(scopes); - } - - public static ApiScopesDto ToModel(this ApiScope resource) - { - return resource == null ? null : Mapper.Map(resource); - } - - public static ApiSecretsDto ToModel(this ApiSecret resource) + public static ApiSecretsDto ToModel(this ApiResourceSecret resource) { return resource == null ? null : Mapper.Map(resource); } @@ -60,14 +50,9 @@ public static ApiResource ToEntity(this ApiResourceDto resource) return resource == null ? null : Mapper.Map(resource); } - public static ApiSecret ToEntity(this ApiSecretsDto resource) - { - return resource == null ? null : Mapper.Map(resource); - } - - public static ApiScope ToEntity(this ApiScopesDto resource) + public static ApiResourceSecret ToEntity(this ApiSecretsDto resource) { - return resource == null ? null : Mapper.Map(resource); + return resource == null ? null : Mapper.Map(resource); } public static ApiResourceProperty ToEntity(this ApiResourcePropertiesDto apiResourceProperties) diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiScopeMapperProfile.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiScopeMapperProfile.cs new file mode 100644 index 000000000..aac2b982a --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiScopeMapperProfile.cs @@ -0,0 +1,47 @@ +// Based on the IdentityServer4.EntityFramework - authors - Brock Allen & Dominick Baier. +// https://github.com/IdentityServer/IdentityServer4.EntityFramework + +// Modified by Jan Škoruba + +using System.Linq; +using AutoMapper; +using IdentityServer4.EntityFramework.Entities; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; +using Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.Common; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Mappers +{ + public class ApiScopeMapperProfile : Profile + { + public ApiScopeMapperProfile() + { + // entity to model + CreateMap(MemberList.Destination) + .ForMember(x => x.UserClaims, opt => opt.MapFrom(src => src.UserClaims.Select(x => x.Type))); + + CreateMap(MemberList.Destination) + .ReverseMap(); + + CreateMap(MemberList.Destination) + .ForMember(dest => dest.Key, opt => opt.Condition(srs => srs != null)) + .ForMember(x => x.ApiScopePropertyId, opt => opt.MapFrom(x => x.Id)) + .ForMember(x => x.ApiScopeId, opt => opt.MapFrom(x => x.Scope.Id)); + + // PagedLists + CreateMap, ApiScopesDto>(MemberList.Destination) + .ForMember(x => x.Scopes, opt => opt.MapFrom(src => src.Data)); + + CreateMap, ApiScopePropertiesDto>(MemberList.Destination) + .ForMember(x => x.ApiScopeProperties, opt => opt.MapFrom(src => src.Data)); + + // model to entity + CreateMap(MemberList.Source) + .ForMember(x => x.UserClaims, opts => opts.MapFrom(src => src.UserClaims.Select(x => new ApiScopeClaim { Type = x }))); + + CreateMap(MemberList.Source) + .ForMember(x => x.Scope, dto => dto.MapFrom(src => new ApiScope { Id = src.ApiScopeId })) + .ForMember(x => x.ScopeId, dto => dto.MapFrom(src => src.ApiScopeId)) + .ForMember(x => x.Id, opt => opt.MapFrom(src => src.ApiScopePropertyId)); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiScopeMappers.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiScopeMappers.cs new file mode 100644 index 000000000..0bcf58023 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ApiScopeMappers.cs @@ -0,0 +1,48 @@ +using AutoMapper; +using IdentityServer4.EntityFramework.Entities; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; +using Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.Common; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Mappers +{ + public static class ApiScopeMappers + { + static ApiScopeMappers() + { + Mapper = new MapperConfiguration(cfg => cfg.AddProfile()) + .CreateMapper(); + } + + internal static IMapper Mapper { get; } + + public static ApiScopesDto ToModel(this PagedList scopes) + { + return scopes == null ? null : Mapper.Map(scopes); + } + + public static ApiScopeDto ToModel(this ApiScope resource) + { + return resource == null ? null : Mapper.Map(resource); + } + + public static ApiScope ToEntity(this ApiScopeDto resource) + { + return resource == null ? null : Mapper.Map(resource); + } + + public static ApiScopeProperty ToEntity(this ApiScopePropertiesDto resource) + { + return resource == null ? null : Mapper.Map(resource); + } + + public static ApiScopePropertiesDto ToModel(this PagedList scope) + { + return scope == null ? null : Mapper.Map(scope); + } + + public static ApiScopePropertiesDto ToModel(this ApiScopeProperty scope) + { + return scope == null ? null : Mapper.Map(scope); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ClientMapperProfile.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ClientMapperProfile.cs index b283fe522..be9e50069 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ClientMapperProfile.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/ClientMapperProfile.cs @@ -6,6 +6,7 @@ using AutoMapper; using IdentityServer4.EntityFramework.Entities; using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Mappers.Converters; using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common; using Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.Common; @@ -18,7 +19,9 @@ public ClientMapperProfile() // entity to model CreateMap(MemberList.Destination) .ForMember(dest => dest.ProtocolType, opt => opt.Condition(srs => srs != null)) - .ReverseMap(); + .ForMember(x => x.AllowedIdentityTokenSigningAlgorithms, opts => opts.ConvertUsing(AllowedSigningAlgorithmsConverter.Converter, x => x.AllowedIdentityTokenSigningAlgorithms)) + .ReverseMap() + .ForMember(x => x.AllowedIdentityTokenSigningAlgorithms, opts => opts.ConvertUsing(AllowedSigningAlgorithmsConverter.Converter, x => x.AllowedIdentityTokenSigningAlgorithms)); CreateMap(MemberList.Destination) .ReverseMap(); diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/Converters/AllowedSigningAlgorithmsConverter.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/Converters/AllowedSigningAlgorithmsConverter.cs new file mode 100644 index 000000000..732a545ed --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/Converters/AllowedSigningAlgorithmsConverter.cs @@ -0,0 +1,42 @@ +// Copyright (c) Brock Allen & Dominick Baier. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +// Modified by Jan Škoruba - original file: https://github.com/IdentityServer/IdentityServer4/blob/main/src/EntityFramework.Storage/src/Mappers/AllowedSigningAlgorithmsConverter.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using AutoMapper; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Mappers.Converters +{ + public class AllowedSigningAlgorithmsConverter : + IValueConverter, string>, + IValueConverter> + { + public static AllowedSigningAlgorithmsConverter Converter = new AllowedSigningAlgorithmsConverter(); + + public string Convert(List sourceMember, ResolutionContext context) + { + if (sourceMember == null || !sourceMember.Any()) + { + return null; + } + return sourceMember.Aggregate((x, y) => $"{x},{y}"); + } + + public List Convert(string sourceMember, ResolutionContext context) + { + var list = new List(); + if (!String.IsNullOrWhiteSpace(sourceMember)) + { + sourceMember = sourceMember.Trim(); + foreach (var item in sourceMember.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Distinct()) + { + list.Add(item); + } + } + return list; + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/IdentityResourceMapperProfile.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/IdentityResourceMapperProfile.cs index 9be6dafc8..4afe97aef 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/IdentityResourceMapperProfile.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Mappers/IdentityResourceMapperProfile.cs @@ -36,7 +36,7 @@ public IdentityResourceMapperProfile() // model to entity CreateMap(MemberList.Source) - .ForMember(x => x.UserClaims, opts => opts.MapFrom(src => src.UserClaims.Select(x => new IdentityClaim { Type = x }))); + .ForMember(x => x.UserClaims, opts => opts.MapFrom(src => src.UserClaims.Select(x => new IdentityResourceClaim { Type = x }))); CreateMap(MemberList.Source) .ForMember(x => x.IdentityResource, dto => dto.MapFrom(src => new IdentityResource() { Id = src.IdentityResourceId })) diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResource.Designer.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResource.Designer.cs index e7c0c8baf..bc97e8ebc 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResource.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResource.Designer.cs @@ -19,7 +19,7 @@ namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Resources { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class ApiResourceServiceResource { @@ -114,33 +114,6 @@ internal static string ApiResourcePropertyExistsValue { } } - /// - /// Looks up a localized string similar to Api Scope with id {0} doesn't exist. - /// - internal static string ApiScopeDoesNotExist { - get { - return ResourceManager.GetString("ApiScopeDoesNotExist", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Api Scope already exists. - /// - internal static string ApiScopeExistsKey { - get { - return ResourceManager.GetString("ApiScopeExistsKey", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Api Scope ({0}) already exists. - /// - internal static string ApiScopeExistsValue { - get { - return ResourceManager.GetString("ApiScopeExistsValue", resourceCulture); - } - } - /// /// Looks up a localized string similar to Api Secret with id {0} doesn't exist. /// diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResource.nl.resx b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResource.nl.resx new file mode 100644 index 000000000..fbe178e7e --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResource.nl.resx @@ -0,0 +1,14 @@ + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResource.resx b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResource.resx index fe4ff1e4a..6ae0a4ee8 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResource.resx +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResource.resx @@ -135,15 +135,6 @@ Api Resource Property with key ({0}) already exists - - Api Scope with id {0} doesn't exist - - - Api Scope already exists - - - Api Scope ({0}) already exists - Api Secret with id {0} doesn't exist diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResources.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResources.cs index e298474da..c62db7ba5 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResources.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiResourceServiceResources.cs @@ -31,33 +31,6 @@ public virtual ResourceMessage ApiResourceExistsKey() }; } - public virtual ResourceMessage ApiScopeDoesNotExist() - { - return new ResourceMessage() - { - Code = nameof(ApiScopeDoesNotExist), - Description = ApiResourceServiceResource.ApiScopeDoesNotExist - }; - } - - public virtual ResourceMessage ApiScopeExistsValue() - { - return new ResourceMessage() - { - Code = nameof(ApiScopeExistsValue), - Description = ApiResourceServiceResource.ApiScopeExistsValue - }; - } - - public virtual ResourceMessage ApiScopeExistsKey() - { - return new ResourceMessage() - { - Code = nameof(ApiScopeExistsKey), - Description = ApiResourceServiceResource.ApiScopeExistsKey - }; - } - public virtual ResourceMessage ApiSecretDoesNotExist() { return new ResourceMessage() diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiScopeServiceResource.Designer.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiScopeServiceResource.Designer.cs new file mode 100644 index 000000000..881151a92 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiScopeServiceResource.Designer.cs @@ -0,0 +1,117 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Resources { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class ApiScopeServiceResource { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal ApiScopeServiceResource() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Skoruba.IdentityServer4.Admin.BusinessLogic.Resources.ApiScopeServiceResource", typeof(ApiScopeServiceResource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Api Scope with id {0} doesn't exist. + /// + public static string ApiScopeDoesNotExist { + get { + return ResourceManager.GetString("ApiScopeDoesNotExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Api Scope already exists. + /// + public static string ApiScopeExistsKey { + get { + return ResourceManager.GetString("ApiScopeExistsKey", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Api Scope ({0}) already exists. + /// + public static string ApiScopeExistsValue { + get { + return ResourceManager.GetString("ApiScopeExistsValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Api Scope Property with id {0} doesn't exist. + /// + public static string ApiScopePropertyDoesNotExist { + get { + return ResourceManager.GetString("ApiScopePropertyDoesNotExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Api Scope Property already exists. + /// + public static string ApiScopePropertyExistsKey { + get { + return ResourceManager.GetString("ApiScopePropertyExistsKey", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Api Scope Property ({0}) already exists. + /// + public static string ApiScopePropertyExistsValue { + get { + return ResourceManager.GetString("ApiScopePropertyExistsValue", resourceCulture); + } + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiScopeServiceResource.resx b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiScopeServiceResource.resx new file mode 100644 index 000000000..afe458470 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiScopeServiceResource.resx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Api Scope with id {0} doesn't exist + + + Api Scope already exists + + + Api Scope ({0}) already exists + + + Api Scope Property with id {0} doesn't exist + + + Api Scope Property already exists + + + Api Scope Property ({0}) already exists + + \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiScopeServiceResources.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiScopeServiceResources.cs new file mode 100644 index 000000000..1356b610f --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/ApiScopeServiceResources.cs @@ -0,0 +1,61 @@ +using Skoruba.IdentityServer4.Admin.BusinessLogic.Helpers; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Resources +{ + public class ApiScopeServiceResources : IApiScopeServiceResources + { + public virtual ResourceMessage ApiScopeDoesNotExist() + { + return new ResourceMessage() + { + Code = nameof(ApiScopeDoesNotExist), + Description = ApiScopeServiceResource.ApiScopeDoesNotExist + }; + } + + public virtual ResourceMessage ApiScopeExistsValue() + { + return new ResourceMessage() + { + Code = nameof(ApiScopeExistsValue), + Description = ApiScopeServiceResource.ApiScopeExistsValue + }; + } + + public virtual ResourceMessage ApiScopeExistsKey() + { + return new ResourceMessage() + { + Code = nameof(ApiScopeExistsKey), + Description = ApiScopeServiceResource.ApiScopeExistsKey + }; + } + + public ResourceMessage ApiScopePropertyExistsValue() + { + return new ResourceMessage() + { + Code = nameof(ApiScopePropertyExistsValue), + Description = ApiScopeServiceResource.ApiScopePropertyExistsValue + }; + } + + public ResourceMessage ApiScopePropertyDoesNotExist() + { + return new ResourceMessage() + { + Code = nameof(ApiScopePropertyDoesNotExist), + Description = ApiScopeServiceResource.ApiScopePropertyDoesNotExist + }; + } + + public ResourceMessage ApiScopePropertyExistsKey() + { + return new ResourceMessage() + { + Code = nameof(ApiScopePropertyExistsKey), + Description = ApiScopeServiceResource.ApiScopePropertyExistsKey + }; + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/IApiResourceServiceResources.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/IApiResourceServiceResources.cs index 36adde013..6e2db856c 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/IApiResourceServiceResources.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/IApiResourceServiceResources.cs @@ -7,9 +7,6 @@ public interface IApiResourceServiceResources ResourceMessage ApiResourceDoesNotExist(); ResourceMessage ApiResourceExistsValue(); ResourceMessage ApiResourceExistsKey(); - ResourceMessage ApiScopeDoesNotExist(); - ResourceMessage ApiScopeExistsValue(); - ResourceMessage ApiScopeExistsKey(); ResourceMessage ApiSecretDoesNotExist(); ResourceMessage ApiResourcePropertyDoesNotExist(); ResourceMessage ApiResourcePropertyExistsKey(); diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/IApiScopeServiceResources.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/IApiScopeServiceResources.cs new file mode 100644 index 000000000..d75e0358d --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Resources/IApiScopeServiceResources.cs @@ -0,0 +1,14 @@ +using Skoruba.IdentityServer4.Admin.BusinessLogic.Helpers; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Resources +{ + public interface IApiScopeServiceResources + { + ResourceMessage ApiScopeDoesNotExist(); + ResourceMessage ApiScopeExistsValue(); + ResourceMessage ApiScopeExistsKey(); + ResourceMessage ApiScopePropertyExistsValue(); + ResourceMessage ApiScopePropertyDoesNotExist(); + ResourceMessage ApiScopePropertyExistsKey(); + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/ApiResourceService.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/ApiResourceService.cs index cc5d51ab6..ba264f1f7 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/ApiResourceService.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/ApiResourceService.cs @@ -195,73 +195,6 @@ public virtual async Task CanInsertApiResourceAsync(ApiResourceDto apiReso return await ApiResourceRepository.CanInsertApiResourceAsync(resource); } - public virtual async Task GetApiScopesAsync(int apiResourceId, int page = 1, int pageSize = 10) - { - var apiResource = await ApiResourceRepository.GetApiResourceAsync(apiResourceId); - if (apiResource == null) throw new UserFriendlyErrorPageException(string.Format(ApiResourceServiceResources.ApiResourceDoesNotExist().Description, apiResourceId), ApiResourceServiceResources.ApiResourceDoesNotExist().Description); - - var pagedList = await ApiResourceRepository.GetApiScopesAsync(apiResourceId, page, pageSize); - - var apiScopesDto = pagedList.ToModel(); - apiScopesDto.ApiResourceId = apiResourceId; - apiScopesDto.ResourceName = await GetApiResourceNameAsync(apiResourceId); - - await AuditEventLogger.LogEventAsync(new ApiScopesRequestedEvent(apiScopesDto)); - - return apiScopesDto; - } - - public virtual async Task GetApiScopeAsync(int apiResourceId, int apiScopeId) - { - var apiResource = await ApiResourceRepository.GetApiResourceAsync(apiResourceId); - if (apiResource == null) throw new UserFriendlyErrorPageException(string.Format(ApiResourceServiceResources.ApiResourceDoesNotExist().Description, apiResourceId), ApiResourceServiceResources.ApiResourceDoesNotExist().Description); - - var apiScope = await ApiResourceRepository.GetApiScopeAsync(apiResourceId, apiScopeId); - if (apiScope == null) throw new UserFriendlyErrorPageException(string.Format(ApiResourceServiceResources.ApiScopeDoesNotExist().Description, apiScopeId), ApiResourceServiceResources.ApiScopeDoesNotExist().Description); - - var apiScopesDto = apiScope.ToModel(); - apiScopesDto.ResourceName = await GetApiResourceNameAsync(apiResourceId); - - await AuditEventLogger.LogEventAsync(new ApiScopeRequestedEvent(apiScopesDto)); - - return apiScopesDto; - } - - public virtual async Task AddApiScopeAsync(ApiScopesDto apiScope) - { - var canInsert = await CanInsertApiScopeAsync(apiScope); - if (!canInsert) - { - await BuildApiScopesViewModelAsync(apiScope); - throw new UserFriendlyViewException(string.Format(ApiResourceServiceResources.ApiScopeExistsValue().Description, apiScope.Name), ApiResourceServiceResources.ApiScopeExistsKey().Description, apiScope); - } - - var scope = apiScope.ToEntity(); - - var added = await ApiResourceRepository.AddApiScopeAsync(apiScope.ApiResourceId, scope); - - await AuditEventLogger.LogEventAsync(new ApiScopeAddedEvent(apiScope)); - - return added; - } - - public virtual ApiScopesDto BuildApiScopeViewModel(ApiScopesDto apiScope) - { - ComboBoxHelpers.PopulateValuesToList(apiScope.UserClaimsItems, apiScope.UserClaims); - - return apiScope; - } - - private async Task BuildApiScopesViewModelAsync(ApiScopesDto apiScope) - { - if (apiScope.ApiScopeId == 0) - { - var apiScopesDto = await GetApiScopesAsync(apiScope.ApiResourceId); - apiScope.Scopes.AddRange(apiScopesDto.Scopes); - apiScope.TotalCount = apiScopesDto.TotalCount; - } - } - private async Task BuildApiResourcePropertiesViewModelAsync(ApiResourcePropertiesDto apiResourceProperties) { var apiResourcePropertiesDto = await GetApiResourcePropertiesAsync(apiResourceProperties.ApiResourceId); @@ -269,37 +202,6 @@ private async Task BuildApiResourcePropertiesViewModelAsync(ApiResourcePropertie apiResourceProperties.TotalCount = apiResourcePropertiesDto.TotalCount; } - public virtual async Task UpdateApiScopeAsync(ApiScopesDto apiScope) - { - var canInsert = await CanInsertApiScopeAsync(apiScope); - if (!canInsert) - { - await BuildApiScopesViewModelAsync(apiScope); - throw new UserFriendlyViewException(string.Format(ApiResourceServiceResources.ApiScopeExistsValue().Description, apiScope.Name), ApiResourceServiceResources.ApiScopeExistsKey().Description, apiScope); - } - - var scope = apiScope.ToEntity(); - - var originalApiScope = await GetApiScopeAsync(apiScope.ApiResourceId, apiScope.ApiScopeId); - - var updated = await ApiResourceRepository.UpdateApiScopeAsync(apiScope.ApiResourceId, scope); - - await AuditEventLogger.LogEventAsync(new ApiScopeUpdatedEvent(originalApiScope, apiScope)); - - return updated; - } - - public virtual async Task DeleteApiScopeAsync(ApiScopesDto apiScope) - { - var scope = apiScope.ToEntity(); - - var deleted = await ApiResourceRepository.DeleteApiScopeAsync(scope); - - await AuditEventLogger.LogEventAsync(new ApiScopeDeletedEvent(apiScope)); - - return deleted; - } - public virtual async Task GetApiSecretsAsync(int apiResourceId, int page = 1, int pageSize = 10) { var apiResource = await ApiResourceRepository.GetApiResourceAsync(apiResourceId); @@ -311,6 +213,9 @@ public virtual async Task GetApiSecretsAsync(int apiResourceId, i apiSecretsDto.ApiResourceId = apiResourceId; apiSecretsDto.ApiResourceName = await ApiResourceRepository.GetApiResourceNameAsync(apiResourceId); + // remove secret value from dto + apiSecretsDto.ApiSecrets.ForEach(x => x.Value = null); + await AuditEventLogger.LogEventAsync(new ApiSecretsRequestedEvent(apiSecretsDto.ApiResourceId, apiSecretsDto.ApiSecrets.Select(x => (x.Id, x.Type, x.Expiration)).ToList())); return apiSecretsDto; @@ -335,6 +240,9 @@ public virtual async Task GetApiSecretAsync(int apiSecretId) if (apiSecret == null) throw new UserFriendlyErrorPageException(string.Format(ApiResourceServiceResources.ApiSecretDoesNotExist().Description, apiSecretId), ApiResourceServiceResources.ApiSecretDoesNotExist().Description); var apiSecretsDto = apiSecret.ToModel(); + // remove secret value for dto + apiSecretsDto.Value = null; + await AuditEventLogger.LogEventAsync(new ApiSecretRequestedEvent(apiSecretsDto.ApiResourceId, apiSecretsDto.ApiSecretId, apiSecretsDto.Type, apiSecretsDto.Expiration)); return apiSecretsDto; @@ -351,13 +259,6 @@ public virtual async Task DeleteApiSecretAsync(ApiSecretsDto apiSecret) return deleted; } - public virtual async Task CanInsertApiScopeAsync(ApiScopesDto apiScopes) - { - var apiScope = apiScopes.ToEntity(); - - return await ApiResourceRepository.CanInsertApiScopeAsync(apiScope); - } - public virtual async Task GetApiResourceNameAsync(int apiResourceId) { return await ApiResourceRepository.GetApiResourceNameAsync(apiResourceId); diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/ApiScopeService.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/ApiScopeService.cs new file mode 100644 index 000000000..8655d7a47 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/ApiScopeService.cs @@ -0,0 +1,196 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using IdentityServer4.EntityFramework.Entities; +using Skoruba.AuditLogging.Services; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Events.ApiScope; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Helpers; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Mappers; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Resources; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Services.Interfaces; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.ExceptionHandling; +using Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.Common; +using Skoruba.IdentityServer4.Admin.EntityFramework.Repositories.Interfaces; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Services +{ + public class ApiScopeService : IApiScopeService + { + protected readonly IApiScopeRepository ApiScopeRepository; + protected readonly IApiScopeServiceResources ApiScopeServiceResources; + protected readonly IAuditEventLogger AuditEventLogger; + + public ApiScopeService(IApiScopeServiceResources apiScopeServiceResources, IApiScopeRepository apiScopeRepository, IAuditEventLogger auditEventLogger) + { + ApiScopeRepository = apiScopeRepository; + AuditEventLogger = auditEventLogger; + ApiScopeServiceResources = apiScopeServiceResources; + + } + + public virtual async Task GetApiScopesAsync(string search, int page = 1, int pageSize = 10) + { + var pagedList = await ApiScopeRepository.GetApiScopesAsync(search, page, pageSize); + + var apiScopesDto = pagedList.ToModel(); + + await AuditEventLogger.LogEventAsync(new ApiScopesRequestedEvent(apiScopesDto)); + + return apiScopesDto; + } + + public virtual async Task> GetApiScopesNameAsync(string scope, int limit = 0) + { + var scopes = await ApiScopeRepository.GetApiScopesNameAsync(scope, limit); + + return scopes; + } + + public virtual async Task GetApiScopePropertiesAsync(int apiScopeId, int page = 1, int pageSize = 10) + { + var apiScope = await ApiScopeRepository.GetApiScopeAsync(apiScopeId); + if (apiScope == null) + throw new UserFriendlyErrorPageException(string.Format(ApiScopeServiceResources.ApiScopeDoesNotExist().Description, apiScopeId), ApiScopeServiceResources.ApiScopeDoesNotExist().Description); + + PagedList pagedList = await ApiScopeRepository.GetApiScopePropertiesAsync(apiScopeId, page, pageSize); + var apiScopePropertiesDto = pagedList.ToModel(); + apiScopePropertiesDto.ApiScopeId = apiScopeId; + apiScopePropertiesDto.ApiScopeName = await ApiScopeRepository.GetApiScopeNameAsync(apiScopeId); + + await AuditEventLogger.LogEventAsync(new ApiScopePropertiesRequestedEvent(apiScopeId, apiScopePropertiesDto)); + + return apiScopePropertiesDto; + } + + public virtual async Task GetApiScopeAsync(int apiScopeId) + { + var apiScope = await ApiScopeRepository.GetApiScopeAsync(apiScopeId); + if (apiScope == null) throw new UserFriendlyErrorPageException(string.Format(ApiScopeServiceResources.ApiScopeDoesNotExist().Description, apiScopeId), ApiScopeServiceResources.ApiScopeDoesNotExist().Description); + + var apiScopeDto = apiScope.ToModel(); + + await AuditEventLogger.LogEventAsync(new ApiScopeRequestedEvent(apiScopeDto)); + + return apiScopeDto; + } + + public virtual async Task AddApiScopeAsync(ApiScopeDto apiScope) + { + var canInsert = await CanInsertApiScopeAsync(apiScope); + if (!canInsert) + { + throw new UserFriendlyViewException(string.Format(ApiScopeServiceResources.ApiScopeExistsValue().Description, apiScope.Name), ApiScopeServiceResources.ApiScopeExistsKey().Description, apiScope); + } + + var scope = apiScope.ToEntity(); + + var added = await ApiScopeRepository.AddApiScopeAsync(scope); + + await AuditEventLogger.LogEventAsync(new ApiScopeAddedEvent(apiScope)); + + return added; + } + + public virtual ApiScopeDto BuildApiScopeViewModel(ApiScopeDto apiScope) + { + ComboBoxHelpers.PopulateValuesToList(apiScope.UserClaimsItems, apiScope.UserClaims); + + return apiScope; + } + + public virtual async Task UpdateApiScopeAsync(ApiScopeDto apiScope) + { + var canInsert = await CanInsertApiScopeAsync(apiScope); + if (!canInsert) + { + throw new UserFriendlyViewException(string.Format(ApiScopeServiceResources.ApiScopeExistsValue().Description, apiScope.Name), ApiScopeServiceResources.ApiScopeExistsKey().Description, apiScope); + } + + var scope = apiScope.ToEntity(); + + var originalApiScope = await GetApiScopeAsync(apiScope.Id); + + var updated = await ApiScopeRepository.UpdateApiScopeAsync(scope); + + await AuditEventLogger.LogEventAsync(new ApiScopeUpdatedEvent(originalApiScope, apiScope)); + + return updated; + } + + public virtual async Task DeleteApiScopeAsync(ApiScopeDto apiScope) + { + var scope = apiScope.ToEntity(); + + var deleted = await ApiScopeRepository.DeleteApiScopeAsync(scope); + + await AuditEventLogger.LogEventAsync(new ApiScopeDeletedEvent(apiScope)); + + return deleted; + } + + public virtual async Task CanInsertApiScopeAsync(ApiScopeDto apiScopeDto) + { + var apiScope = apiScopeDto.ToEntity(); + + return await ApiScopeRepository.CanInsertApiScopeAsync(apiScope); + } + + public virtual async Task GetApiScopePropertyAsync(int apiScopePropertyId) + { + var apiScopeProperty = await ApiScopeRepository.GetApiScopePropertyAsync(apiScopePropertyId); + if (apiScopeProperty == null) throw new UserFriendlyErrorPageException(string.Format(ApiScopeServiceResources.ApiScopePropertyDoesNotExist().Description, apiScopePropertyId)); + + var apiScopePropertiesDto = apiScopeProperty.ToModel(); + apiScopePropertiesDto.ApiScopeId = apiScopeProperty.ScopeId; + apiScopePropertiesDto.ApiScopeName = await ApiScopeRepository.GetApiScopeNameAsync(apiScopeProperty.ScopeId); + + await AuditEventLogger.LogEventAsync(new ApiScopePropertyRequestedEvent(apiScopePropertyId, apiScopePropertiesDto)); + + return apiScopePropertiesDto; + } + + private async Task BuildApiScopePropertiesViewModelAsync(ApiScopePropertiesDto apiScopeProperties) + { + var apiResourcePropertiesDto = await GetApiScopePropertiesAsync(apiScopeProperties.ApiScopeId); + apiScopeProperties.ApiScopeProperties.AddRange(apiResourcePropertiesDto.ApiScopeProperties); + apiScopeProperties.TotalCount = apiResourcePropertiesDto.TotalCount; + } + + public virtual async Task AddApiScopePropertyAsync(ApiScopePropertiesDto apiScopeProperties) + { + var canInsert = await CanInsertApiScopePropertyAsync(apiScopeProperties); + if (!canInsert) + { + await BuildApiScopePropertiesViewModelAsync(apiScopeProperties); + throw new UserFriendlyViewException(string.Format(ApiScopeServiceResources.ApiScopePropertyExistsValue().Description, apiScopeProperties.Key), ApiScopeServiceResources.ApiScopePropertyExistsKey().Description, apiScopeProperties); + } + + var apiScopeProperty = apiScopeProperties.ToEntity(); + + var saved = await ApiScopeRepository.AddApiScopePropertyAsync(apiScopeProperties.ApiScopeId, apiScopeProperty); + + await AuditEventLogger.LogEventAsync(new ApiScopePropertyAddedEvent(apiScopeProperties)); + + return saved; + } + + public virtual async Task DeleteApiScopePropertyAsync(ApiScopePropertiesDto apiScopeProperty) + { + var propertyEntity = apiScopeProperty.ToEntity(); + + var deleted = await ApiScopeRepository.DeleteApiScopePropertyAsync(propertyEntity); + + await AuditEventLogger.LogEventAsync(new ApiScopePropertyDeletedEvent(apiScopeProperty)); + + return deleted; + } + + public virtual async Task CanInsertApiScopePropertyAsync(ApiScopePropertiesDto apiResourceProperty) + { + var resource = apiResourceProperty.ToEntity(); + + return await ApiScopeRepository.CanInsertApiScopePropertyAsync(resource); + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/ClientService.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/ClientService.cs index 5d40295d8..fbae49651 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/ClientService.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/ClientService.cs @@ -88,6 +88,7 @@ private void PopulateClientRelations(ClientDto client) ComboBoxHelpers.PopulateValuesToList(client.RedirectUrisItems, client.RedirectUris); ComboBoxHelpers.PopulateValuesToList(client.AllowedCorsOriginsItems, client.AllowedCorsOrigins); ComboBoxHelpers.PopulateValuesToList(client.AllowedGrantTypesItems, client.AllowedGrantTypes); + ComboBoxHelpers.PopulateValuesToList(client.AllowedIdentityTokenSigningAlgorithmsItems, client.AllowedIdentityTokenSigningAlgorithms); } public virtual ClientCloneDto BuildClientCloneViewModel(int id, ClientDto clientDto) @@ -273,6 +274,13 @@ public virtual List GetAccessTokenTypes() return accessTokenTypes; } + public virtual List GetSigningAlgorithms(string algorithm, int limit = 0) + { + var signingAlgorithms = ClientRepository.GetSigningAlgorithms(algorithm, limit); + + return signingAlgorithms; + } + public virtual List GetTokenExpirations() { var tokenExpirations = ClientRepository.GetTokenExpirations().ToModel(); @@ -348,6 +356,9 @@ public virtual async Task GetClientSecretsAsync(int clientId, clientSecretsDto.ClientId = clientId; clientSecretsDto.ClientName = ViewHelpers.GetClientName(clientInfo.ClientId, clientInfo.ClientName); + // remove secret value from dto + clientSecretsDto.ClientSecrets.ForEach(x => x.Value = null); + await AuditEventLogger.LogEventAsync(new ClientSecretsRequestedEvent(clientSecretsDto.ClientId, clientSecretsDto.ClientSecrets.Select(x => (x.Id, x.Type, x.Expiration)).ToList())); return clientSecretsDto; @@ -365,6 +376,9 @@ public virtual async Task GetClientSecretAsync(int clientSecre clientSecretsDto.ClientId = clientSecret.Client.Id; clientSecretsDto.ClientName = ViewHelpers.GetClientName(clientInfo.ClientId, clientInfo.ClientName); + // remove secret value for dto + clientSecretsDto.Value = null; + await AuditEventLogger.LogEventAsync(new ClientSecretRequestedEvent(clientSecretsDto.ClientId, clientSecretsDto.ClientSecretId, clientSecretsDto.Type, clientSecretsDto.Expiration)); return clientSecretsDto; diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/Interfaces/IApiResourceService.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/Interfaces/IApiResourceService.cs index d38677247..cf7a304b5 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/Interfaces/IApiResourceService.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/Interfaces/IApiResourceService.cs @@ -7,8 +7,6 @@ public interface IApiResourceService { ApiSecretsDto BuildApiSecretsViewModel(ApiSecretsDto apiSecrets); - ApiScopesDto BuildApiScopeViewModel(ApiScopesDto apiScope); - Task GetApiResourcesAsync(string search, int page = 1, int pageSize = 10); Task GetApiResourcePropertiesAsync(int apiResourceId, int page = 1, int pageSize = 10); @@ -30,17 +28,7 @@ public interface IApiResourceService Task DeleteApiResourceAsync(ApiResourceDto apiResource); Task CanInsertApiResourceAsync(ApiResourceDto apiResource); - - Task GetApiScopesAsync(int apiResourceId, int page = 1, int pageSize = 10); - - Task GetApiScopeAsync(int apiResourceId, int apiScopeId); - - Task AddApiScopeAsync(ApiScopesDto apiScope); - - Task UpdateApiScopeAsync(ApiScopesDto apiScope); - - Task DeleteApiScopeAsync(ApiScopesDto apiScope); - + Task GetApiSecretsAsync(int apiResourceId, int page = 1, int pageSize = 10); Task AddApiSecretAsync(ApiSecretsDto apiSecret); @@ -49,8 +37,6 @@ public interface IApiResourceService Task DeleteApiSecretAsync(ApiSecretsDto apiSecret); - Task CanInsertApiScopeAsync(ApiScopesDto apiScopes); - Task GetApiResourceNameAsync(int apiResourceId); } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/Interfaces/IApiScopeService.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/Interfaces/IApiScopeService.cs new file mode 100644 index 000000000..d667e5601 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/Interfaces/IApiScopeService.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; + +namespace Skoruba.IdentityServer4.Admin.BusinessLogic.Services.Interfaces +{ + public interface IApiScopeService + { + ApiScopeDto BuildApiScopeViewModel(ApiScopeDto apiScope); + + Task GetApiScopesAsync(string search, int page = 1, int pageSize = 10); + + Task> GetApiScopesNameAsync(string scope, int limit = 0); + + Task GetApiScopeAsync(int apiScopeId); + + Task AddApiScopeAsync(ApiScopeDto apiScope); + + Task UpdateApiScopeAsync(ApiScopeDto apiScope); + + Task DeleteApiScopeAsync(ApiScopeDto apiScope); + + Task CanInsertApiScopeAsync(ApiScopeDto apiScopes); + + Task GetApiScopePropertiesAsync(int apiScopeId, int page = 1, int pageSize = 10); + + Task AddApiScopePropertyAsync(ApiScopePropertiesDto apiScopeProperties); + + Task DeleteApiScopePropertyAsync(ApiScopePropertiesDto apiScopeProperty); + + Task GetApiScopePropertyAsync(int apiScopePropertyId); + + Task CanInsertApiScopePropertyAsync(ApiScopePropertiesDto apiResourceProperty); + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/Interfaces/IClientService.cs b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/Interfaces/IClientService.cs index 97778ef4f..5accdf139 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/Interfaces/IClientService.cs +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Services/Interfaces/IClientService.cs @@ -67,6 +67,8 @@ public interface IClientService Task DeleteClientPropertyAsync(ClientPropertiesDto clientProperty); + List GetSigningAlgorithms(string algorithm, int limit = 0); + List GetProtocolTypes(); } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Skoruba.IdentityServer4.Admin.BusinessLogic.csproj b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Skoruba.IdentityServer4.Admin.BusinessLogic.csproj index 2b2a6c430..f8b29c865 100644 --- a/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Skoruba.IdentityServer4.Admin.BusinessLogic.csproj +++ b/src/Skoruba.IdentityServer4.Admin.BusinessLogic/Skoruba.IdentityServer4.Admin.BusinessLogic.csproj @@ -1,8 +1,8 @@  - netcoreapp3.1 - 1.0.0 + net5.0 + 2.0.0 Jan Škoruba Business Logic layer for the administration of the IdentityServer4 IdentityServer4 Admin OpenIDConnect OAuth2 Identity @@ -12,7 +12,7 @@ - + @@ -21,11 +21,21 @@ + + ApiResourceServiceResource.resx + True + True + True True ApiResourceServiceResource.resx + + True + True + ApiScopeServiceResource.resx + True True @@ -38,6 +48,10 @@ ResXFileCodeGenerator ApiResourceServiceResource.Designer.cs + + PublicResXFileCodeGenerator + ApiScopeServiceResource.Designer.cs + ResXFileCodeGenerator IdentityResourceServiceResource.Designer.cs @@ -49,3 +63,11 @@ + + + + + + + + diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/ConnectionStringsConfiguration.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/ConnectionStringsConfiguration.cs new file mode 100644 index 000000000..f65ef5dd4 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/ConnectionStringsConfiguration.cs @@ -0,0 +1,27 @@ +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration +{ + public class ConnectionStringsConfiguration + { + public string ConfigurationDbConnection { get; set; } + + public string PersistedGrantDbConnection { get; set; } + + public string AdminLogDbConnection { get; set; } + + public string IdentityDbConnection { get; set; } + + public string AdminAuditLogDbConnection { get; set; } + + public string DataProtectionDbConnection { get; set; } + + public void SetConnections(string commonConnectionString) + { + AdminAuditLogDbConnection = commonConnectionString; + AdminLogDbConnection = commonConnectionString; + ConfigurationDbConnection = commonConnectionString; + DataProtectionDbConnection = commonConnectionString; + IdentityDbConnection = commonConnectionString; + PersistedGrantDbConnection = commonConnectionString; + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/DatabaseMigrationsConfiguration.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/DatabaseMigrationsConfiguration.cs new file mode 100644 index 000000000..44fb945e9 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/DatabaseMigrationsConfiguration.cs @@ -0,0 +1,29 @@ +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration +{ + public class DatabaseMigrationsConfiguration + { + public bool ApplyDatabaseMigrations { get; set; } = false; + + public string ConfigurationDbMigrationsAssembly { get; set; } + + public string PersistedGrantDbMigrationsAssembly { get; set; } + + public string AdminLogDbMigrationsAssembly { get; set; } + + public string IdentityDbMigrationsAssembly { get; set; } + + public string AdminAuditLogDbMigrationsAssembly { get; set; } + + public string DataProtectionDbMigrationsAssembly { get; set; } + + public void SetMigrationsAssemblies(string commonMigrationsAssembly) + { + AdminAuditLogDbMigrationsAssembly = commonMigrationsAssembly; + AdminLogDbMigrationsAssembly = commonMigrationsAssembly; + ConfigurationDbMigrationsAssembly = commonMigrationsAssembly; + DataProtectionDbMigrationsAssembly = commonMigrationsAssembly; + IdentityDbMigrationsAssembly = commonMigrationsAssembly; + PersistedGrantDbMigrationsAssembly = commonMigrationsAssembly; + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/DatabaseProviderConfiguration.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/DatabaseProviderConfiguration.cs new file mode 100644 index 000000000..fb400e8dc --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/DatabaseProviderConfiguration.cs @@ -0,0 +1,7 @@ +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration +{ + public class DatabaseProviderConfiguration + { + public DatabaseProviderType ProviderType { get; set; } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/DatabaseProviderType.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/DatabaseProviderType.cs new file mode 100644 index 000000000..a01aaddf1 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/DatabaseProviderType.cs @@ -0,0 +1,9 @@ +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration +{ + public enum DatabaseProviderType + { + SqlServer, + PostgreSQL, + MySql + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/Identity/Claim.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/Identity/Claim.cs new file mode 100644 index 000000000..2934e9c8e --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/Identity/Claim.cs @@ -0,0 +1,8 @@ +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration.Identity +{ + public class Claim + { + public string Type { get; set; } + public string Value { get; set; } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/Identity/Role.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/Identity/Role.cs new file mode 100644 index 000000000..30073ebd3 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/Identity/Role.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration.Identity +{ + public class Role + { + public string Name { get; set; } + public List Claims { get; set; } = new List(); + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/Identity/User.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/Identity/User.cs new file mode 100644 index 000000000..ba3b7ba3b --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/Identity/User.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration.Identity +{ + public class User + { + public string Username { get; set; } + public string Email { get; set; } + public string Password { get; set; } + public List Claims { get; set; } = new List(); + public List Roles { get; set; } = new List(); + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/IdentityData.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/IdentityData.cs new file mode 100644 index 000000000..c1942d8e5 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/IdentityData.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration.Identity; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration +{ + public class IdentityData + { + public List Roles { get; set; } + public List Users { get; set; } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/IdentityServer/Client.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/IdentityServer/Client.cs new file mode 100644 index 000000000..77223f2bd --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/IdentityServer/Client.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration.Identity; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration.IdentityServer +{ + public class Client : global::IdentityServer4.Models.Client + { + public List ClientClaims { get; set; } = new List(); + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/IdentityServerData.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/IdentityServerData.cs new file mode 100644 index 000000000..7cf4122b1 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/IdentityServerData.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using IdentityServer4.Models; +using Client = Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration.IdentityServer.Client; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration +{ + public class IdentityServerData + { + public List Clients { get; set; } = new List(); + public List IdentityResources { get; set; } = new List(); + public List ApiResources { get; set; } = new List(); + public List ApiScopes { get; set; } = new List(); + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/SeedConfiguration.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/SeedConfiguration.cs new file mode 100644 index 000000000..b62cc18f2 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Configuration/SeedConfiguration.cs @@ -0,0 +1,7 @@ +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration +{ + public class SeedConfiguration + { + public bool ApplySeed { get; set; } = false; + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/MySql/DatabaseExtensions.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/MySql/DatabaseExtensions.cs new file mode 100644 index 000000000..9bdcc9513 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/MySql/DatabaseExtensions.cs @@ -0,0 +1,107 @@ +using System.Reflection; +using IdentityServer4.EntityFramework.Storage; +using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Skoruba.AuditLogging.EntityFramework.DbContexts; +using Skoruba.AuditLogging.EntityFramework.Entities; +using Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration; +using Skoruba.IdentityServer4.Admin.EntityFramework.Interfaces; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.MySql +{ + public static class DatabaseExtensions + { + /// + /// Register DbContexts for IdentityServer ConfigurationStore and PersistedGrants, Identity and Logging + /// Configure the connection strings in AppSettings.json + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void RegisterMySqlDbContexts(this IServiceCollection services, + ConnectionStringsConfiguration connectionStrings, + DatabaseMigrationsConfiguration databaseMigrations) + where TIdentityDbContext : DbContext + where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext + where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext + where TLogDbContext : DbContext, IAdminLogDbContext + where TAuditLoggingDbContext : DbContext, IAuditLoggingDbContext + where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext + where TAuditLog : AuditLog + { + var migrationsAssembly = typeof(DatabaseExtensions).GetTypeInfo().Assembly.GetName().Name; + + // Config DB for identity + services.AddDbContext(options => + options.UseMySql(connectionStrings.IdentityDbConnection, ServerVersion.AutoDetect(connectionStrings.IdentityDbConnection), sql => sql.MigrationsAssembly(databaseMigrations.IdentityDbMigrationsAssembly ?? migrationsAssembly))); + + // Config DB from existing connection + services.AddConfigurationDbContext(options => + options.ConfigureDbContext = b => + b.UseMySql(connectionStrings.ConfigurationDbConnection, ServerVersion.AutoDetect(connectionStrings.ConfigurationDbConnection), sql => sql.MigrationsAssembly(databaseMigrations.ConfigurationDbMigrationsAssembly ?? migrationsAssembly))); + + // Operational DB from existing connection + services.AddOperationalDbContext(options => options.ConfigureDbContext = b => + b.UseMySql(connectionStrings.PersistedGrantDbConnection, ServerVersion.AutoDetect(connectionStrings.PersistedGrantDbConnection), sql => sql.MigrationsAssembly(databaseMigrations.PersistedGrantDbMigrationsAssembly ?? migrationsAssembly))); + + // Log DB from existing connection + services.AddDbContext(options => options.UseMySql(connectionStrings.AdminLogDbConnection, ServerVersion.AutoDetect(connectionStrings.AdminLogDbConnection), + optionsSql => optionsSql.MigrationsAssembly(databaseMigrations.AdminLogDbMigrationsAssembly ?? migrationsAssembly))); + + // Audit logging connection + services.AddDbContext(options => options.UseMySql(connectionStrings.AdminAuditLogDbConnection, ServerVersion.AutoDetect(connectionStrings.AdminAuditLogDbConnection), + optionsSql => optionsSql.MigrationsAssembly(databaseMigrations.AdminAuditLogDbMigrationsAssembly ?? migrationsAssembly))); + + // DataProtectionKey DB from existing connection + if(!string.IsNullOrEmpty(connectionStrings.DataProtectionDbConnection)) + services.AddDbContext(options => options.UseMySql(connectionStrings.DataProtectionDbConnection, ServerVersion.AutoDetect(connectionStrings.DataProtectionDbConnection), + optionsSql => optionsSql.MigrationsAssembly(databaseMigrations.DataProtectionDbMigrationsAssembly ?? migrationsAssembly))); + } + + /// + /// Register DbContexts for IdentityServer ConfigurationStore and PersistedGrants and Identity + /// Configure the connection strings in AppSettings.json + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void RegisterMySqlDbContexts(this IServiceCollection services, + string identityConnectionString, string configurationConnectionString, + string persistedGrantConnectionString, string dataProtectionConnectionString) + where TIdentityDbContext : DbContext + where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext + where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext + where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext + { + var migrationsAssembly = typeof(DatabaseExtensions).GetTypeInfo().Assembly.GetName().Name; + + // Config DB for identity + services.AddDbContext(options => options.UseMySql(identityConnectionString, ServerVersion.AutoDetect(identityConnectionString), sql => sql.MigrationsAssembly(migrationsAssembly))); + + // Config DB from existing connection + services.AddConfigurationDbContext(options => options.ConfigureDbContext = b => b.UseMySql(configurationConnectionString, ServerVersion.AutoDetect(configurationConnectionString), sql => sql.MigrationsAssembly(migrationsAssembly))); + + // Operational DB from existing connection + services.AddOperationalDbContext(options => options.ConfigureDbContext = b => b.UseMySql(persistedGrantConnectionString, ServerVersion.AutoDetect(persistedGrantConnectionString), sql => sql.MigrationsAssembly(migrationsAssembly))); + + // DataProtectionKey DB from existing connection + services.AddDbContext(options => options.UseMySql(dataProtectionConnectionString, ServerVersion.AutoDetect(dataProtectionConnectionString), optionsSql => optionsSql.MigrationsAssembly(migrationsAssembly))); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/PostgreSQL/DatabaseExtensions.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/PostgreSQL/DatabaseExtensions.cs new file mode 100644 index 000000000..fcc322433 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/PostgreSQL/DatabaseExtensions.cs @@ -0,0 +1,104 @@ +using System.Reflection; +using IdentityServer4.EntityFramework.Storage; +using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Skoruba.AuditLogging.EntityFramework.DbContexts; +using Skoruba.AuditLogging.EntityFramework.Entities; +using Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration; +using Skoruba.IdentityServer4.Admin.EntityFramework.Interfaces; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.PostgreSQL +{ + public static class DatabaseExtensions + { + /// + /// Register DbContexts for IdentityServer ConfigurationStore and PersistedGrants, Identity and Logging + /// Configure the connection strings in AppSettings.json + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void RegisterNpgSqlDbContexts(this IServiceCollection services, + ConnectionStringsConfiguration connectionStrings, + DatabaseMigrationsConfiguration databaseMigrations) + where TIdentityDbContext : DbContext + where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext + where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext + where TLogDbContext : DbContext, IAdminLogDbContext + where TAuditLoggingDbContext : DbContext, IAuditLoggingDbContext + where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext + where TAuditLog : AuditLog + { + var migrationsAssembly = typeof(DatabaseExtensions).GetTypeInfo().Assembly.GetName().Name; + + // Config DB for identity + services.AddDbContext(options => + options.UseNpgsql(connectionStrings.IdentityDbConnection, sql => sql.MigrationsAssembly(databaseMigrations.IdentityDbMigrationsAssembly ?? migrationsAssembly))); + + // Config DB from existing connection + services.AddConfigurationDbContext(options => + options.ConfigureDbContext = b => + b.UseNpgsql(connectionStrings.ConfigurationDbConnection, sql => sql.MigrationsAssembly(databaseMigrations.ConfigurationDbMigrationsAssembly ?? migrationsAssembly))); + + // Operational DB from existing connection + services.AddOperationalDbContext(options => options.ConfigureDbContext = b => + b.UseNpgsql(connectionStrings.PersistedGrantDbConnection, sql => sql.MigrationsAssembly(databaseMigrations.PersistedGrantDbMigrationsAssembly ?? migrationsAssembly))); + + // Log DB from existing connection + services.AddDbContext(options => options.UseNpgsql(connectionStrings.AdminLogDbConnection, + optionsSql => optionsSql.MigrationsAssembly(databaseMigrations.AdminLogDbMigrationsAssembly ?? migrationsAssembly))); + + // Audit logging connection + services.AddDbContext(options => options.UseNpgsql(connectionStrings.AdminAuditLogDbConnection, + optionsSql => optionsSql.MigrationsAssembly(databaseMigrations.AdminAuditLogDbMigrationsAssembly ?? migrationsAssembly))); + + // DataProtectionKey DB from existing connection + if (!string.IsNullOrEmpty(connectionStrings.DataProtectionDbConnection)) + services.AddDbContext(options => options.UseNpgsql(connectionStrings.DataProtectionDbConnection, sql => sql.MigrationsAssembly(databaseMigrations.DataProtectionDbMigrationsAssembly ?? migrationsAssembly))); + } + + /// + /// Register DbContexts for IdentityServer ConfigurationStore and PersistedGrants and Identity + /// Configure the connection strings in AppSettings.json + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void RegisterNpgSqlDbContexts(this IServiceCollection services, + string identityConnectionString, string configurationConnectionString, + string persistedGrantConnectionString, string dataProtectionConnectionString) + where TIdentityDbContext : DbContext + where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext + where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext + where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext + { + var migrationsAssembly = typeof(DatabaseExtensions).GetTypeInfo().Assembly.GetName().Name; + + // Config DB for identity + services.AddDbContext(options => options.UseNpgsql(identityConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); + + // Config DB from existing connection + services.AddConfigurationDbContext(options => options.ConfigureDbContext = b => b.UseNpgsql(configurationConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); + + // Operational DB from existing connection + services.AddOperationalDbContext(options => options.ConfigureDbContext = b => b.UseNpgsql(persistedGrantConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); + + // DataProtectionKey DB from existing connection + services.AddDbContext(options => options.UseNpgsql(dataProtectionConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.csproj b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.csproj new file mode 100644 index 000000000..fa44330b4 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.csproj @@ -0,0 +1,33 @@ + + + + net5.0 + 2.0.0 + Jan Škoruba + IdentityServer4 Admin OpenIDConnect OAuth2 Identity + Entity Framework configuration for the administration of the IdentityServer4 and Asp.Net Core Identity + https://github.com/skoruba/IdentityServer4.Admin/blob/master/LICENSE.md + https://github.com/skoruba/IdentityServer4.Admin + https://raw.githubusercontent.com/skoruba/IdentityServer4.Admin/master/docs/Images/Skoruba.IdentityServer4.Admin-Logo-Nuget.png + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/SqlServer/DatabaseExtensions.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/SqlServer/DatabaseExtensions.cs new file mode 100644 index 000000000..dc6e4cacd --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Configuration/SqlServer/DatabaseExtensions.cs @@ -0,0 +1,102 @@ +using System.Reflection; +using IdentityServer4.EntityFramework.Storage; +using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Skoruba.AuditLogging.EntityFramework.DbContexts; +using Skoruba.AuditLogging.EntityFramework.Entities; +using Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration; +using Skoruba.IdentityServer4.Admin.EntityFramework.Interfaces; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.SqlServer +{ + public static class DatabaseExtensions + { + /// + /// Register DbContexts for IdentityServer ConfigurationStore and PersistedGrants, Identity and Logging + /// Configure the connection strings in AppSettings.json + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void RegisterSqlServerDbContexts(this IServiceCollection services, + ConnectionStringsConfiguration connectionStrings, + DatabaseMigrationsConfiguration databaseMigrations) + where TIdentityDbContext : DbContext + where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext + where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext + where TLogDbContext : DbContext, IAdminLogDbContext + where TAuditLoggingDbContext : DbContext, IAuditLoggingDbContext + where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext + where TAuditLog : AuditLog + { + var migrationsAssembly = typeof(DatabaseExtensions).GetTypeInfo().Assembly.GetName().Name; + + // Config DB for identity + services.AddDbContext(options => options.UseSqlServer(connectionStrings.IdentityDbConnection, sql => sql.MigrationsAssembly(databaseMigrations.IdentityDbMigrationsAssembly ?? migrationsAssembly))); + + // Config DB from existing connection + services.AddConfigurationDbContext(options => options.ConfigureDbContext = b => b.UseSqlServer(connectionStrings.ConfigurationDbConnection, sql => sql.MigrationsAssembly(databaseMigrations.ConfigurationDbMigrationsAssembly ?? migrationsAssembly))); + + // Operational DB from existing connection + services.AddOperationalDbContext(options => options.ConfigureDbContext = b => b.UseSqlServer(connectionStrings.PersistedGrantDbConnection, sql => sql.MigrationsAssembly(databaseMigrations.PersistedGrantDbMigrationsAssembly ?? migrationsAssembly))); + + // Log DB from existing connection + services.AddDbContext(options => options.UseSqlServer(connectionStrings.AdminLogDbConnection, + optionsSql => optionsSql.MigrationsAssembly(databaseMigrations.AdminLogDbMigrationsAssembly ?? migrationsAssembly))); + + // Audit logging connection + services.AddDbContext(options => options.UseSqlServer(connectionStrings.AdminAuditLogDbConnection, + optionsSql => optionsSql.MigrationsAssembly(databaseMigrations.AdminAuditLogDbMigrationsAssembly ?? migrationsAssembly))); + + // DataProtectionKey DB from existing connection + if (!string.IsNullOrEmpty(connectionStrings.DataProtectionDbConnection)) + services.AddDbContext(options => options.UseSqlServer(connectionStrings.DataProtectionDbConnection, + optionsSql => optionsSql.MigrationsAssembly(databaseMigrations.DataProtectionDbMigrationsAssembly ?? migrationsAssembly))); + } + + /// + /// Register DbContexts for IdentityServer ConfigurationStore and PersistedGrants and Identity + /// Configure the connection strings in AppSettings.json + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void RegisterSqlServerDbContexts(this IServiceCollection services, + string identityConnectionString, string configurationConnectionString, + string persistedGrantConnectionString, string dataProtectionConnectionString) + where TIdentityDbContext : DbContext + where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext + where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext + where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext + { + var migrationsAssembly = typeof(DatabaseExtensions).GetTypeInfo().Assembly.GetName().Name; + + // Config DB for identity + services.AddDbContext(options => options.UseSqlServer(identityConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); + + // Config DB from existing connection + services.AddConfigurationDbContext(options => options.ConfigureDbContext = b => b.UseSqlServer(configurationConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); + + // Operational DB from existing connection + services.AddOperationalDbContext(options => options.ConfigureDbContext = b => b.UseSqlServer(persistedGrantConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); + + // DataProtectionKey DB from existing connection + services.AddDbContext(options => options.UseSqlServer(dataProtectionConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Extensions/Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.csproj b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Extensions/Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.csproj index 2365d8c50..2bce27003 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Extensions/Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.csproj +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Extensions/Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.csproj @@ -1,8 +1,8 @@  - netcoreapp3.1 - 1.0.0 + net5.0 + 2.0.0 Jan Škoruba IdentityServer4 Admin OpenIDConnect OAuth2 Identity EntityFramework extensions for the administration of the IdentityServer4 and Asp.Net Core Identity @@ -16,3 +16,11 @@ + + + + + + + + diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Identity/Skoruba.IdentityServer4.Admin.EntityFramework.Identity.csproj b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Identity/Skoruba.IdentityServer4.Admin.EntityFramework.Identity.csproj index 33ea01380..7a4e997e5 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Identity/Skoruba.IdentityServer4.Admin.EntityFramework.Identity.csproj +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Identity/Skoruba.IdentityServer4.Admin.EntityFramework.Identity.csproj @@ -1,8 +1,8 @@  - netcoreapp3.1 - 1.0.0 + net5.0 + 2.0.0 Jan Škoruba Entity Framework layer for the administration of the Asp.Net Core Identity and IdentityServer4 IdentityServer4 Admin OpenIDConnect OAuth2 Identity @@ -12,8 +12,8 @@ - - + + @@ -25,3 +25,11 @@ + + + + + + + + diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Extensions/DatabaseExtensions.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Extensions/DatabaseExtensions.cs deleted file mode 100644 index 1b44f96e8..000000000 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Extensions/DatabaseExtensions.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System.Reflection; -using IdentityServer4.EntityFramework.Storage; -using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Skoruba.AuditLogging.EntityFramework.DbContexts; -using Skoruba.AuditLogging.EntityFramework.Entities; -using Skoruba.IdentityServer4.Admin.EntityFramework.Interfaces; - -namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Extensions -{ - public static class DatabaseExtensions - { - /// - /// Register DbContexts for IdentityServer ConfigurationStore and PersistedGrants, Identity and Logging - /// Configure the connection strings in AppSettings.json - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static void RegisterMySqlDbContexts(this IServiceCollection services, - string identityConnectionString, string configurationConnectionString, - string persistedGrantConnectionString, string errorLoggingConnectionString, - string auditLoggingConnectionString, string dataProtectionConnectionString = null) - where TIdentityDbContext : DbContext - where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext - where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext - where TLogDbContext : DbContext, IAdminLogDbContext - where TAuditLoggingDbContext : DbContext, IAuditLoggingDbContext - where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext - { - var migrationsAssembly = typeof(DatabaseExtensions).GetTypeInfo().Assembly.GetName().Name; - - // Config DB for identity - services.AddDbContext(options => - options.UseMySql(identityConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Config DB from existing connection - services.AddConfigurationDbContext(options => - options.ConfigureDbContext = b => - b.UseMySql(configurationConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Operational DB from existing connection - services.AddOperationalDbContext(options => options.ConfigureDbContext = b => - b.UseMySql(persistedGrantConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Log DB from existing connection - services.AddDbContext(options => options.UseMySql(errorLoggingConnectionString, - optionsSql => optionsSql.MigrationsAssembly(migrationsAssembly))); - - // Audit logging connection - services.AddDbContext(options => options.UseMySql(auditLoggingConnectionString, - optionsSql => optionsSql.MigrationsAssembly(migrationsAssembly))); - - // DataProtectionKey DB from existing connection - if(!string.IsNullOrEmpty(dataProtectionConnectionString)) - services.AddDbContext(options => options.UseMySql(dataProtectionConnectionString, - optionsSql => optionsSql.MigrationsAssembly(migrationsAssembly))); - } - - /// - /// Register DbContexts for IdentityServer ConfigurationStore and PersistedGrants and Identity - /// Configure the connection strings in AppSettings.json - /// - /// - /// - /// - /// - /// - /// - /// - public static void RegisterMySqlDbContexts(this IServiceCollection services, - string identityConnectionString, string configurationConnectionString, - string persistedGrantConnectionString, string dataProtectionConnectionString) - where TIdentityDbContext : DbContext - where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext - where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext - where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext - { - var migrationsAssembly = typeof(DatabaseExtensions).GetTypeInfo().Assembly.GetName().Name; - - // Config DB for identity - services.AddDbContext(options => options.UseMySql(identityConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Config DB from existing connection - services.AddConfigurationDbContext(options => options.ConfigureDbContext = b => b.UseMySql(configurationConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Operational DB from existing connection - services.AddOperationalDbContext(options => options.ConfigureDbContext = b => b.UseMySql(persistedGrantConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // DataProtectionKey DB from existing connection - services.AddDbContext(options => options.UseMySql(dataProtectionConnectionString, - optionsSql => optionsSql.MigrationsAssembly(migrationsAssembly))); - - } - } -} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Helpers/MigrationAssembly.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Helpers/MigrationAssembly.cs new file mode 100644 index 000000000..b43ac5ec7 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Helpers/MigrationAssembly.cs @@ -0,0 +1,7 @@ +namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Helpers +{ + public class MigrationAssembly + { + + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/AuditLogging/20191120085753_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/AuditLogging/20191120085753_DbInit.Designer.cs index b3f4e156a..3f7da6d8a 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/AuditLogging/20191120085753_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/AuditLogging/20191120085753_DbInit.Designer.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.AuditLogging diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/AuditLogging/20200419131142_ChangeAuditLogToLong.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/AuditLogging/20200419131142_ChangeAuditLogToLong.Designer.cs index b208fbe81..2971e269e 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/AuditLogging/20200419131142_ChangeAuditLogToLong.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/AuditLogging/20200419131142_ChangeAuditLogToLong.Designer.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.AuditLogging diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/AuditLogging/AdminAuditLogDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/AuditLogging/AdminAuditLogDbContextModelSnapshot.cs index eca03d5db..ebf162076 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/AuditLogging/AdminAuditLogDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/AuditLogging/AdminAuditLogDbContextModelSnapshot.cs @@ -1,8 +1,8 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.AuditLogging diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/DataProtection/20200419131430_AddDataProtection.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/DataProtection/20200419131430_AddDataProtection.Designer.cs index 2e3d51e55..7afd82e08 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/DataProtection/20200419131430_AddDataProtection.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/DataProtection/20200419131430_AddDataProtection.Designer.cs @@ -1,8 +1,8 @@ // + using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.DataProtection diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/DataProtection/IdentityServerDataProtectionDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/DataProtection/IdentityServerDataProtectionDbContextModelSnapshot.cs index 4ca021ec1..0573905ca 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/DataProtection/IdentityServerDataProtectionDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/DataProtection/IdentityServerDataProtectionDbContextModelSnapshot.cs @@ -1,7 +1,7 @@ // + using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.DataProtection diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Identity/20191120085611_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Identity/20191120085611_DbInit.Designer.cs index 24aab9ec4..59efbd13e 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Identity/20191120085611_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Identity/20191120085611_DbInit.Designer.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.Identity diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Identity/AdminIdentityDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Identity/AdminIdentityDbContextModelSnapshot.cs index 7f2b9fd8f..b080991ca 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Identity/AdminIdentityDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Identity/AdminIdentityDbContextModelSnapshot.cs @@ -1,8 +1,8 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.Identity diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/20191120085701_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/20191120085701_DbInit.Designer.cs index fea85ef1f..264f80a80 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/20191120085701_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/20191120085701_DbInit.Designer.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.IdentityServerConfiguration diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/20201108173253_UpdateIdentityServerToVersion4.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/20201108173253_UpdateIdentityServerToVersion4.Designer.cs new file mode 100644 index 000000000..7ff4424d6 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/20201108173253_UpdateIdentityServerToVersion4.Designer.cs @@ -0,0 +1,882 @@ +// + +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.IdentityServerConfiguration +{ + [DbContext(typeof(IdentityServerConfigurationDbContext))] + [Migration("20201108173253_UpdateIdentityServerToVersion4")] + partial class UpdateIdentityServerToVersion4 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.9") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AllowedAccessTokenSigningAlgorithms") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastAccessed") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("NonEditable") + .HasColumnType("tinyint(1)"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("tinyint(1)"); + + b.Property("Updated") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("ApiResources"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiResourceId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceClaims"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiResourceId") + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceProperties"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiResourceId") + .HasColumnType("int"); + + b.Property("Scope") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceScopes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiResourceId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(4000); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceSecrets"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Emphasize") + .HasColumnType("tinyint(1)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Required") + .HasColumnType("tinyint(1)"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("ApiScopes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ScopeId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ScopeId"); + + b.ToTable("ApiScopeClaims"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("ScopeId") + .HasColumnType("int"); + + b.Property("Value") + .IsRequired() + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ScopeId"); + + b.ToTable("ApiScopeProperties"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AbsoluteRefreshTokenLifetime") + .HasColumnType("int"); + + b.Property("AccessTokenLifetime") + .HasColumnType("int"); + + b.Property("AccessTokenType") + .HasColumnType("int"); + + b.Property("AllowAccessTokensViaBrowser") + .HasColumnType("tinyint(1)"); + + b.Property("AllowOfflineAccess") + .HasColumnType("tinyint(1)"); + + b.Property("AllowPlainTextPkce") + .HasColumnType("tinyint(1)"); + + b.Property("AllowRememberConsent") + .HasColumnType("tinyint(1)"); + + b.Property("AllowedIdentityTokenSigningAlgorithms") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("AlwaysIncludeUserClaimsInIdToken") + .HasColumnType("tinyint(1)"); + + b.Property("AlwaysSendClientClaims") + .HasColumnType("tinyint(1)"); + + b.Property("AuthorizationCodeLifetime") + .HasColumnType("int"); + + b.Property("BackChannelLogoutSessionRequired") + .HasColumnType("tinyint(1)"); + + b.Property("BackChannelLogoutUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("ClientClaimsPrefix") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("ConsentLifetime") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DeviceCodeLifetime") + .HasColumnType("int"); + + b.Property("EnableLocalLogin") + .HasColumnType("tinyint(1)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("FrontChannelLogoutSessionRequired") + .HasColumnType("tinyint(1)"); + + b.Property("FrontChannelLogoutUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("IdentityTokenLifetime") + .HasColumnType("int"); + + b.Property("IncludeJwtId") + .HasColumnType("tinyint(1)"); + + b.Property("LastAccessed") + .HasColumnType("datetime(6)"); + + b.Property("LogoUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("NonEditable") + .HasColumnType("tinyint(1)"); + + b.Property("PairWiseSubjectSalt") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ProtocolType") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("RefreshTokenExpiration") + .HasColumnType("int"); + + b.Property("RefreshTokenUsage") + .HasColumnType("int"); + + b.Property("RequireClientSecret") + .HasColumnType("tinyint(1)"); + + b.Property("RequireConsent") + .HasColumnType("tinyint(1)"); + + b.Property("RequirePkce") + .HasColumnType("tinyint(1)"); + + b.Property("RequireRequestObject") + .HasColumnType("tinyint(1)"); + + b.Property("SlidingRefreshTokenLifetime") + .HasColumnType("int"); + + b.Property("UpdateAccessTokenClaimsOnRefresh") + .HasColumnType("tinyint(1)"); + + b.Property("Updated") + .HasColumnType("datetime(6)"); + + b.Property("UserCodeType") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("UserSsoLifetime") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique(); + + b.ToTable("Clients"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientClaims"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("Origin") + .IsRequired() + .HasColumnType("varchar(150) CHARACTER SET utf8mb4") + .HasMaxLength(150); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientCorsOrigins"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("GrantType") + .IsRequired() + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientGrantTypes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("Provider") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientIdPRestrictions"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("PostLogoutRedirectUri") + .IsRequired() + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientPostLogoutRedirectUris"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientProperties"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("RedirectUri") + .IsRequired() + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientRedirectUris"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("Scope") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientScopes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(4000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientSecrets"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Emphasize") + .HasColumnType("tinyint(1)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("NonEditable") + .HasColumnType("tinyint(1)"); + + b.Property("Required") + .HasColumnType("tinyint(1)"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("tinyint(1)"); + + b.Property("Updated") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("IdentityResources"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("IdentityResourceId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.ToTable("IdentityResourceClaims"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("IdentityResourceId") + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.ToTable("IdentityResourceProperties"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Properties") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Scopes") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Secrets") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope") + .WithMany("UserClaims") + .HasForeignKey("ScopeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope") + .WithMany("Properties") + .HasForeignKey("ScopeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("Claims") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("AllowedCorsOrigins") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("AllowedGrantTypes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("IdentityProviderRestrictions") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("PostLogoutRedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("Properties") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("RedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("AllowedScopes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("ClientSecrets") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource") + .WithMany("UserClaims") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource") + .WithMany("Properties") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/20201108173253_UpdateIdentityServerToVersion4.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/20201108173253_UpdateIdentityServerToVersion4.cs new file mode 100644 index 000000000..8b7947260 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/20201108173253_UpdateIdentityServerToVersion4.cs @@ -0,0 +1,564 @@ +// Original SQL scripts for database migration come from: https://github.com/RockSolidKnowledge/IdentityServer4.Migration.Scripts/blob/master/MySql/ConfigurationDbContext.sql +// Modified by Jan Škoruba + +using System; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.IdentityServerConfiguration +{ + public partial class UpdateIdentityServerToVersion4 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ApiClaims_ApiResources_ApiResourceId", + table: "ApiClaims"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiProperties_ApiResources_ApiResourceId", + table: "ApiProperties"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiScopeClaims_ApiScopes_ApiScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiScopes_ApiResources_ApiResourceId", + table: "ApiScopes"); + + migrationBuilder.DropForeignKey( + name: "FK_IdentityProperties_IdentityResources_IdentityResourceId", + table: "IdentityProperties"); + + migrationBuilder.DropIndex( + name: "IX_ApiScopes_ApiResourceId", + table: "ApiScopes"); + + migrationBuilder.DropIndex( + name: "IX_ApiScopeClaims_ApiScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropPrimaryKey( + name: "PK_IdentityProperties", + table: "IdentityProperties"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ApiProperties", + table: "ApiProperties"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ApiClaims", + table: "ApiClaims"); + + migrationBuilder.RenameTable( + name: "IdentityProperties", + newName: "IdentityResourceProperties"); + + migrationBuilder.RenameTable( + name: "ApiProperties", + newName: "ApiResourceProperties"); + + migrationBuilder.RenameTable( + name: "ApiClaims", + newName: "ApiResourceClaims"); + + migrationBuilder.RenameIndex( + name: "IX_IdentityProperties_IdentityResourceId", + table: "IdentityResourceProperties", + newName: "IX_IdentityResourceProperties_IdentityResourceId"); + + migrationBuilder.RenameIndex( + name: "IX_ApiProperties_ApiResourceId", + table: "ApiResourceProperties", + newName: "IX_ApiResourceProperties_ApiResourceId"); + + migrationBuilder.RenameIndex( + name: "IX_ApiClaims_ApiResourceId", + table: "ApiResourceClaims", + newName: "IX_ApiResourceClaims_ApiResourceId"); + + migrationBuilder.AddColumn( + name: "AllowedIdentityTokenSigningAlgorithms", + table: "Clients", + maxLength: 100, + nullable: true); + + migrationBuilder.AddColumn( + name: "RequireRequestObject", + table: "Clients", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "Enabled", + table: "ApiScopes", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "ScopeId", + table: "ApiScopeClaims", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "AllowedAccessTokenSigningAlgorithms", + table: "ApiResources", + maxLength: 100, + nullable: true); + + migrationBuilder.AddColumn( + name: "ShowInDiscoveryDocument", + table: "ApiResources", + nullable: false, + defaultValue: false); + + migrationBuilder.AddPrimaryKey( + name: "PK_IdentityResourceProperties", + table: "IdentityResourceProperties", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ApiResourceProperties", + table: "ApiResourceProperties", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ApiResourceClaims", + table: "ApiResourceClaims", + column: "Id"); + + migrationBuilder.CreateTable( + name: "ApiResourceScopes", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Scope = table.Column(maxLength: 200, nullable: false), + ApiResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiResourceScopes", x => x.Id); + table.ForeignKey( + name: "FK_ApiResourceScopes_ApiResources_ApiResourceId", + column: x => x.ApiResourceId, + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ApiResourceSecrets", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Description = table.Column(maxLength: 1000, nullable: true), + Value = table.Column(maxLength: 4000, nullable: false), + Expiration = table.Column(nullable: true), + Type = table.Column(maxLength: 250, nullable: false), + Created = table.Column(nullable: false), + ApiResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiResourceSecrets", x => x.Id); + table.ForeignKey( + name: "FK_ApiResourceSecrets_ApiResources_ApiResourceId", + column: x => x.ApiResourceId, + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ApiScopeProperties", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Key = table.Column(maxLength: 250, nullable: false), + Value = table.Column(maxLength: 2000, nullable: false), + ScopeId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiScopeProperties", x => x.Id); + table.ForeignKey( + name: "FK_ApiScopeProperties_ApiScopes_ScopeId", + column: x => x.ScopeId, + principalTable: "ApiScopes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityResourceClaims", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Type = table.Column(maxLength: 200, nullable: false), + IdentityResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityResourceClaims", x => x.Id); + table.ForeignKey( + name: "FK_IdentityResourceClaims_IdentityResources_IdentityResourceId", + column: x => x.IdentityResourceId, + principalTable: "IdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ApiScopeClaims_ScopeId", + table: "ApiScopeClaims", + column: "ScopeId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiResourceScopes_ApiResourceId", + table: "ApiResourceScopes", + column: "ApiResourceId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiResourceSecrets_ApiResourceId", + table: "ApiResourceSecrets", + column: "ApiResourceId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiScopeProperties_ScopeId", + table: "ApiScopeProperties", + column: "ScopeId"); + + migrationBuilder.CreateIndex( + name: "IX_IdentityResourceClaims_IdentityResourceId", + table: "IdentityResourceClaims", + column: "IdentityResourceId"); + + migrationBuilder.AddForeignKey( + name: "FK_ApiResourceClaims_ApiResources_ApiResourceId", + table: "ApiResourceClaims", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ApiResourceProperties_ApiResources_ApiResourceId", + table: "ApiResourceProperties", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + // migrate data + + migrationBuilder.Sql(@"INSERT INTO `ApiResourceSecrets` + (`Id`, `Description`, `Value`, `Expiration`, `Type`, `Created`, `ApiResourceId`) +SELECT + `Id`, `Description`, `Value`, `Expiration`, `Type`, `Created`, `ApiResourceId` +FROM `ApiSecrets`;"); + + migrationBuilder.Sql(@"INSERT INTO `IdentityResourceClaims` + (`Id`, `Type`, `IdentityResourceId`) +SELECT + `Id`, `Type`, `IdentityResourceId` +FROM `IdentityClaims`;"); + + migrationBuilder.Sql(@"INSERT INTO `ApiResourceScopes` + (`Scope`, `ApiResourceId`) +SELECT + `Name`, `ApiResourceId` +FROM `ApiScopes`;"); + + migrationBuilder.Sql(@"UPDATE `ApiScopeClaims` SET `ScopeId` = `ApiScopeId`"); + + migrationBuilder.Sql(@"UPDATE `ApiScopes` SET `Enabled` = 1"); + + migrationBuilder.DropTable( + name: "ApiSecrets"); + + migrationBuilder.DropTable( + name: "IdentityClaims"); + + migrationBuilder.DropColumn( + name: "ApiResourceId", + table: "ApiScopes"); + + migrationBuilder.DropColumn( + name: "ApiScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.AddForeignKey( + name: "FK_ApiScopeClaims_ApiScopes_ScopeId", + table: "ApiScopeClaims", + column: "ScopeId", + principalTable: "ApiScopes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_IdentityResourceProperties_IdentityResources_IdentityResourc~", + table: "IdentityResourceProperties", + column: "IdentityResourceId", + principalTable: "IdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ApiResourceClaims_ApiResources_ApiResourceId", + table: "ApiResourceClaims"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiResourceProperties_ApiResources_ApiResourceId", + table: "ApiResourceProperties"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiScopeClaims_ApiScopes_ScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropForeignKey( + name: "FK_IdentityResourceProperties_IdentityResources_IdentityResourc~", + table: "IdentityResourceProperties"); + + migrationBuilder.DropIndex( + name: "IX_ApiScopeClaims_ScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropPrimaryKey( + name: "PK_IdentityResourceProperties", + table: "IdentityResourceProperties"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ApiResourceProperties", + table: "ApiResourceProperties"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ApiResourceClaims", + table: "ApiResourceClaims"); + + migrationBuilder.RenameTable( + name: "IdentityResourceProperties", + newName: "IdentityProperties"); + + migrationBuilder.RenameTable( + name: "ApiResourceProperties", + newName: "ApiProperties"); + + migrationBuilder.RenameTable( + name: "ApiResourceClaims", + newName: "ApiClaims"); + + migrationBuilder.RenameIndex( + name: "IX_IdentityResourceProperties_IdentityResourceId", + table: "IdentityProperties", + newName: "IX_IdentityProperties_IdentityResourceId"); + + migrationBuilder.RenameIndex( + name: "IX_ApiResourceProperties_ApiResourceId", + table: "ApiProperties", + newName: "IX_ApiProperties_ApiResourceId"); + + migrationBuilder.RenameIndex( + name: "IX_ApiResourceClaims_ApiResourceId", + table: "ApiClaims", + newName: "IX_ApiClaims_ApiResourceId"); + + migrationBuilder.AddColumn( + name: "ApiResourceId", + table: "ApiScopes", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "ApiScopeId", + table: "ApiScopeClaims", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddPrimaryKey( + name: "PK_IdentityProperties", + table: "IdentityProperties", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ApiProperties", + table: "ApiProperties", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ApiClaims", + table: "ApiClaims", + column: "Id"); + + migrationBuilder.CreateTable( + name: "ApiSecrets", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + ApiResourceId = table.Column(type: "int", nullable: false), + Created = table.Column(type: "datetime(6)", nullable: false), + Description = table.Column(type: "varchar(1000) CHARACTER SET utf8mb4", maxLength: 1000, nullable: true), + Expiration = table.Column(type: "datetime(6)", nullable: true), + Type = table.Column(type: "varchar(250) CHARACTER SET utf8mb4", maxLength: 250, nullable: false), + Value = table.Column(type: "longtext CHARACTER SET utf8mb4", maxLength: 4000, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiSecrets", x => x.Id); + table.ForeignKey( + name: "FK_ApiSecrets_ApiResources_ApiResourceId", + column: x => x.ApiResourceId, + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityClaims", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + IdentityResourceId = table.Column(type: "int", nullable: false), + Type = table.Column(type: "varchar(200) CHARACTER SET utf8mb4", maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityClaims", x => x.Id); + table.ForeignKey( + name: "FK_IdentityClaims_IdentityResources_IdentityResourceId", + column: x => x.IdentityResourceId, + principalTable: "IdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ApiScopes_ApiResourceId", + table: "ApiScopes", + column: "ApiResourceId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiScopeClaims_ApiScopeId", + table: "ApiScopeClaims", + column: "ApiScopeId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiSecrets_ApiResourceId", + table: "ApiSecrets", + column: "ApiResourceId"); + + migrationBuilder.CreateIndex( + name: "IX_IdentityClaims_IdentityResourceId", + table: "IdentityClaims", + column: "IdentityResourceId"); + + migrationBuilder.AddForeignKey( + name: "FK_ApiClaims_ApiResources_ApiResourceId", + table: "ApiClaims", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ApiProperties_ApiResources_ApiResourceId", + table: "ApiProperties", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + // Rollback data back + migrationBuilder.Sql(@"INSERT INTO `ApiSecrets` + (`Id`, `Description`, `Value`, `Expiration`, `Type`, `Created`, `ApiResourceId`) +SELECT + Id, `Description`, `Value`, `Expiration`, `Type`, `Created`, `ApiResourceId` +FROM `ApiResourceSecrets`"); + + migrationBuilder.Sql(@"INSERT INTO `IdentityClaims` + (`Id`, `Type`, `IdentityResourceId`) +SELECT + `Id`, `Type`, `IdentityResourceId` +FROM `IdentityResourceClaims`"); + + migrationBuilder.Sql(@"UPDATE `ApiScopes` asp + INNER JOIN `ApiResourceScopes` arc + ON arc.`Id` = asp.`Id` +SET asp.`ApiResourceId` = arc.`ApiResourceId`;"); + + migrationBuilder.Sql(@"UPDATE `ApiScopeClaims` SET `ApiScopeId` = `ScopeId`"); + + migrationBuilder.DropTable( + name: "ApiResourceScopes"); + + migrationBuilder.DropTable( + name: "ApiResourceSecrets"); + + migrationBuilder.DropTable( + name: "ApiScopeProperties"); + + migrationBuilder.DropTable( + name: "IdentityResourceClaims"); + + migrationBuilder.DropColumn( + name: "AllowedIdentityTokenSigningAlgorithms", + table: "Clients"); + + migrationBuilder.DropColumn( + name: "RequireRequestObject", + table: "Clients"); + + migrationBuilder.DropColumn( + name: "Enabled", + table: "ApiScopes"); + + migrationBuilder.DropColumn( + name: "ScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropColumn( + name: "AllowedAccessTokenSigningAlgorithms", + table: "ApiResources"); + + migrationBuilder.DropColumn( + name: "ShowInDiscoveryDocument", + table: "ApiResources"); + + migrationBuilder.AddForeignKey( + name: "FK_ApiScopeClaims_ApiScopes_ApiScopeId", + table: "ApiScopeClaims", + column: "ApiScopeId", + principalTable: "ApiScopes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ApiScopes_ApiResources_ApiResourceId", + table: "ApiScopes", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_IdentityProperties_IdentityResources_IdentityResourceId", + table: "IdentityProperties", + column: "IdentityResourceId", + principalTable: "IdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/IdentityServerConfigurationDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/IdentityServerConfigurationDbContextModelSnapshot.cs index daaf9173e..1a34d9277 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/IdentityServerConfigurationDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerConfiguration/IdentityServerConfigurationDbContextModelSnapshot.cs @@ -1,8 +1,8 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.IdentityServerConfiguration @@ -14,7 +14,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.0.0") + .HasAnnotation("ProductVersion", "3.1.9") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b => @@ -23,6 +23,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("int"); + b.Property("AllowedAccessTokenSigningAlgorithms") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + b.Property("Created") .HasColumnType("datetime(6)"); @@ -48,6 +52,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("NonEditable") .HasColumnType("tinyint(1)"); + b.Property("ShowInDiscoveryDocument") + .HasColumnType("tinyint(1)"); + b.Property("Updated") .HasColumnType("datetime(6)"); @@ -77,7 +84,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("ApiResourceId"); - b.ToTable("ApiClaims"); + b.ToTable("ApiResourceClaims"); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b => @@ -103,10 +110,31 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("ApiResourceId"); - b.ToTable("ApiProperties"); + b.ToTable("ApiResourceProperties"); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiResourceId") + .HasColumnType("int"); + + b.Property("Scope") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceScopes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -115,6 +143,39 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ApiResourceId") .HasColumnType("int"); + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(4000); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceSecrets"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + b.Property("Description") .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") .HasMaxLength(1000); @@ -126,6 +187,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Emphasize") .HasColumnType("tinyint(1)"); + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + b.Property("Name") .IsRequired() .HasColumnType("varchar(200) CHARACTER SET utf8mb4") @@ -139,8 +203,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("ApiResourceId"); - b.HasIndex("Name") .IsUnique(); @@ -153,7 +215,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("int"); - b.Property("ApiScopeId") + b.Property("ScopeId") .HasColumnType("int"); b.Property("Type") @@ -163,45 +225,35 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("ApiScopeId"); + b.HasIndex("ScopeId"); b.ToTable("ApiScopeClaims"); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); - b.Property("ApiResourceId") - .HasColumnType("int"); - - b.Property("Created") - .HasColumnType("datetime(6)"); - - b.Property("Description") - .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") - .HasMaxLength(1000); - - b.Property("Expiration") - .HasColumnType("datetime(6)"); - - b.Property("Type") + b.Property("Key") .IsRequired() .HasColumnType("varchar(250) CHARACTER SET utf8mb4") .HasMaxLength(250); + b.Property("ScopeId") + .HasColumnType("int"); + b.Property("Value") .IsRequired() - .HasColumnType("longtext CHARACTER SET utf8mb4") - .HasMaxLength(4000); + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); b.HasKey("Id"); - b.HasIndex("ApiResourceId"); + b.HasIndex("ScopeId"); - b.ToTable("ApiSecrets"); + b.ToTable("ApiScopeProperties"); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b => @@ -231,6 +283,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("AllowRememberConsent") .HasColumnType("tinyint(1)"); + b.Property("AllowedIdentityTokenSigningAlgorithms") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + b.Property("AlwaysIncludeUserClaimsInIdToken") .HasColumnType("tinyint(1)"); @@ -330,6 +386,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("RequirePkce") .HasColumnType("tinyint(1)"); + b.Property("RequireRequestObject") + .HasColumnType("tinyint(1)"); + b.Property("SlidingRefreshTokenLifetime") .HasColumnType("int"); @@ -568,27 +627,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("ClientSecrets"); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - b.Property("IdentityResourceId") - .HasColumnType("int"); - - b.Property("Type") - .IsRequired() - .HasColumnType("varchar(200) CHARACTER SET utf8mb4") - .HasMaxLength(200); - - b.HasKey("Id"); - - b.HasIndex("IdentityResourceId"); - - b.ToTable("IdentityClaims"); - }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b => { b.Property("Id") @@ -637,6 +675,27 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("IdentityResources"); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("IdentityResourceId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.ToTable("IdentityResourceClaims"); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b => { b.Property("Id") @@ -660,7 +719,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("IdentityResourceId"); - b.ToTable("IdentityProperties"); + b.ToTable("IdentityResourceProperties"); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b => @@ -681,7 +740,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b => { b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") .WithMany("Scopes") @@ -690,20 +749,29 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Secrets") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b => { - b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "ApiScope") + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope") .WithMany("UserClaims") - .HasForeignKey("ApiScopeId") + .HasForeignKey("ScopeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b => { - b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") - .WithMany("Secrets") - .HasForeignKey("ApiResourceId") + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope") + .WithMany("Properties") + .HasForeignKey("ScopeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); @@ -789,7 +857,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b => { b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource") .WithMany("UserClaims") diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/20191120085729_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/20191120085729_DbInit.Designer.cs index b00bebacf..2ead83cef 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/20191120085729_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/20191120085729_DbInit.Designer.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.IdentityServerGrants diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/20201108173143_UpdateIdentityServerToVersion4.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/20201108173143_UpdateIdentityServerToVersion4.Designer.cs new file mode 100644 index 000000000..d16660f09 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/20201108173143_UpdateIdentityServerToVersion4.Designer.cs @@ -0,0 +1,127 @@ +// + +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.IdentityServerGrants +{ + [DbContext(typeof(IdentityServerPersistedGrantDbContext))] + [Migration("20201108173143_UpdateIdentityServerToVersion4")] + partial class UpdateIdentityServerToVersion4 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.9") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(50000); + + b.Property("Description") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("DeviceCode") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime(6)"); + + b.Property("SessionId") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("SubjectId") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Key") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ConsumedTime") + .HasColumnType("datetime(6)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(50000); + + b.Property("Description") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.Property("SessionId") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("SubjectId") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.HasIndex("SubjectId", "SessionId", "Type"); + + b.ToTable("PersistedGrants"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/20201108173143_UpdateIdentityServerToVersion4.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/20201108173143_UpdateIdentityServerToVersion4.cs new file mode 100644 index 000000000..afda5c205 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/20201108173143_UpdateIdentityServerToVersion4.cs @@ -0,0 +1,72 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.IdentityServerGrants +{ + public partial class UpdateIdentityServerToVersion4 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ConsumedTime", + table: "PersistedGrants", + nullable: true); + + migrationBuilder.AddColumn( + name: "Description", + table: "PersistedGrants", + maxLength: 200, + nullable: true); + + migrationBuilder.AddColumn( + name: "SessionId", + table: "PersistedGrants", + maxLength: 100, + nullable: true); + + migrationBuilder.AddColumn( + name: "Description", + table: "DeviceCodes", + maxLength: 200, + nullable: true); + + migrationBuilder.AddColumn( + name: "SessionId", + table: "DeviceCodes", + maxLength: 100, + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_PersistedGrants_SubjectId_SessionId_Type", + table: "PersistedGrants", + columns: new[] { "SubjectId", "SessionId", "Type" }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_PersistedGrants_SubjectId_SessionId_Type", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "ConsumedTime", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "Description", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "SessionId", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "Description", + table: "DeviceCodes"); + + migrationBuilder.DropColumn( + name: "SessionId", + table: "DeviceCodes"); + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/IdentityServerPersistedGrantDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/IdentityServerPersistedGrantDbContextModelSnapshot.cs index 9f33655e2..6dbaed38e 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/IdentityServerPersistedGrantDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/IdentityServerGrants/IdentityServerPersistedGrantDbContextModelSnapshot.cs @@ -1,8 +1,8 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.IdentityServerGrants @@ -14,7 +14,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.0.0") + .HasAnnotation("ProductVersion", "3.1.9") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => @@ -36,6 +36,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(50000); + b.Property("Description") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + b.Property("DeviceCode") .IsRequired() .HasColumnType("varchar(200) CHARACTER SET utf8mb4") @@ -45,6 +49,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired() .HasColumnType("datetime(6)"); + b.Property("SessionId") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + b.Property("SubjectId") .HasColumnType("varchar(200) CHARACTER SET utf8mb4") .HasMaxLength(200); @@ -70,6 +78,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("varchar(200) CHARACTER SET utf8mb4") .HasMaxLength(200); + b.Property("ConsumedTime") + .HasColumnType("datetime(6)"); + b.Property("CreationTime") .HasColumnType("datetime(6)"); @@ -78,9 +89,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("longtext CHARACTER SET utf8mb4") .HasMaxLength(50000); + b.Property("Description") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + b.Property("Expiration") .HasColumnType("datetime(6)"); + b.Property("SessionId") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + b.Property("SubjectId") .HasColumnType("varchar(200) CHARACTER SET utf8mb4") .HasMaxLength(200); @@ -96,6 +115,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("SubjectId", "ClientId", "Type"); + b.HasIndex("SubjectId", "SessionId", "Type"); + b.ToTable("PersistedGrants"); }); #pragma warning restore 612, 618 diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Logging/20191120085635_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Logging/20191120085635_DbInit.Designer.cs index aaaeb025f..e9d3db70c 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Logging/20191120085635_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Logging/20191120085635_DbInit.Designer.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.Logging diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Logging/AdminLogDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Logging/AdminLogDbContextModelSnapshot.cs index 7f75145eb..65a442ce6 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Logging/AdminLogDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Migrations/Logging/AdminLogDbContextModelSnapshot.cs @@ -1,8 +1,8 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.MySql.Migrations.Logging diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Skoruba.IdentityServer4.Admin.EntityFramework.MySql.csproj b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Skoruba.IdentityServer4.Admin.EntityFramework.MySql.csproj index 67d39cdab..d7932b969 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Skoruba.IdentityServer4.Admin.EntityFramework.MySql.csproj +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.MySql/Skoruba.IdentityServer4.Admin.EntityFramework.MySql.csproj @@ -1,8 +1,8 @@  - netcoreapp3.1 - 1.0.0 + net5.0 + 2.0.0 Jan Škoruba IdentityServer4 Admin OpenIDConnect OAuth2 Identity Entity Framework layer for the administration of the IdentityServer4 and Asp.Net Core Identity with MySql support @@ -12,8 +12,8 @@ - - + + @@ -28,3 +28,11 @@ + + + + + + + + diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Extensions/DatabaseExtensions.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Extensions/DatabaseExtensions.cs deleted file mode 100644 index 509f8aba0..000000000 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Extensions/DatabaseExtensions.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using System.Reflection; -using IdentityServer4.EntityFramework.Storage; -using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Skoruba.AuditLogging.EntityFramework.DbContexts; -using Skoruba.AuditLogging.EntityFramework.Entities; -using Skoruba.IdentityServer4.Admin.EntityFramework.Interfaces; - -namespace Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL.Extensions -{ - public static class DatabaseExtensions - { - /// - /// Register DbContexts for IdentityServer ConfigurationStore and PersistedGrants, Identity and Logging - /// Configure the connection strings in AppSettings.json - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static void RegisterNpgSqlDbContexts(this IServiceCollection services, - string identityConnectionString, string configurationConnectionString, - string persistedGrantConnectionString, string errorLoggingConnectionString, - string auditLoggingConnectionString, string dataProtectionConnectionString = null) - where TIdentityDbContext : DbContext - where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext - where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext - where TLogDbContext : DbContext, IAdminLogDbContext - where TAuditLoggingDbContext : DbContext, IAuditLoggingDbContext - where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext - { - var migrationsAssembly = typeof(DatabaseExtensions).GetTypeInfo().Assembly.GetName().Name; - - // Config DB for identity - services.AddDbContext(options => - options.UseNpgsql(identityConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Config DB from existing connection - services.AddConfigurationDbContext(options => - options.ConfigureDbContext = b => - b.UseNpgsql(configurationConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Operational DB from existing connection - services.AddOperationalDbContext(options => options.ConfigureDbContext = b => - b.UseNpgsql(persistedGrantConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Log DB from existing connection - services.AddDbContext(options => options.UseNpgsql(errorLoggingConnectionString, - optionsSql => optionsSql.MigrationsAssembly(migrationsAssembly))); - - // Audit logging connection - services.AddDbContext(options => options.UseNpgsql(auditLoggingConnectionString, - optionsSql => optionsSql.MigrationsAssembly(migrationsAssembly))); - - // DataProtectionKey DB from existing connection - if (!string.IsNullOrEmpty(dataProtectionConnectionString)) - services.AddDbContext(options => options.UseNpgsql(dataProtectionConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - } - - /// - /// Register DbContexts for IdentityServer ConfigurationStore and PersistedGrants and Identity - /// Configure the connection strings in AppSettings.json - /// - /// - /// - /// - /// - /// - /// - /// - public static void RegisterNpgSqlDbContexts(this IServiceCollection services, - string identityConnectionString, string configurationConnectionString, - string persistedGrantConnectionString, string dataProtectionConnectionString) - where TIdentityDbContext : DbContext - where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext - where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext - where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext - { - var migrationsAssembly = typeof(DatabaseExtensions).GetTypeInfo().Assembly.GetName().Name; - - // Config DB for identity - services.AddDbContext(options => options.UseNpgsql(identityConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Config DB from existing connection - services.AddConfigurationDbContext(options => options.ConfigureDbContext = b => b.UseNpgsql(configurationConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Operational DB from existing connection - services.AddOperationalDbContext(options => options.ConfigureDbContext = b => b.UseNpgsql(persistedGrantConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // DataProtectionKey DB from existing connection - services.AddDbContext(options => options.UseNpgsql(dataProtectionConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - } - } -} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Helpers/MigrationAssembly.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Helpers/MigrationAssembly.cs new file mode 100644 index 000000000..75014e6ef --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Helpers/MigrationAssembly.cs @@ -0,0 +1,7 @@ +namespace Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL.Helpers +{ + public class MigrationAssembly + { + + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/AuditLogging/20191120100220_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/AuditLogging/20191120100220_DbInit.Designer.cs index 80e9b52c0..515e1252f 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/AuditLogging/20191120100220_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/AuditLogging/20191120100220_DbInit.Designer.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/AuditLogging/20200419130247_ChangeAuditLogToLong.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/AuditLogging/20200419130247_ChangeAuditLogToLong.Designer.cs index 26af6c6b6..8465da62b 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/AuditLogging/20200419130247_ChangeAuditLogToLong.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/AuditLogging/20200419130247_ChangeAuditLogToLong.Designer.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/AuditLogging/AdminAuditLogDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/AuditLogging/AdminAuditLogDbContextModelSnapshot.cs index e4d5fff25..4c4fcd260 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/AuditLogging/AdminAuditLogDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/AuditLogging/AdminAuditLogDbContextModelSnapshot.cs @@ -1,8 +1,8 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/DataProtection/20200419131536_AddDataProtection.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/DataProtection/20200419131536_AddDataProtection.Designer.cs index e0aa76361..dd8ce9480 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/DataProtection/20200419131536_AddDataProtection.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/DataProtection/20200419131536_AddDataProtection.Designer.cs @@ -1,8 +1,8 @@ // + using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/DataProtection/IdentityServerDataProtectionDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/DataProtection/IdentityServerDataProtectionDbContextModelSnapshot.cs index c2bde9c9f..91a349201 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/DataProtection/IdentityServerDataProtectionDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/DataProtection/IdentityServerDataProtectionDbContextModelSnapshot.cs @@ -1,7 +1,7 @@ // + using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Identity/20191120100035_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Identity/20191120100035_DbInit.Designer.cs index 83de728c9..329982b61 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Identity/20191120100035_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Identity/20191120100035_DbInit.Designer.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Identity/AdminIdentityDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Identity/AdminIdentityDbContextModelSnapshot.cs index fc05e24c9..c895528bf 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Identity/AdminIdentityDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Identity/AdminIdentityDbContextModelSnapshot.cs @@ -1,8 +1,8 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/20191120100129_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/20191120100129_DbInit.Designer.cs index 1cbba5018..801c03abe 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/20191120100129_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/20191120100129_DbInit.Designer.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/20201108170812_UpdateIdentityServerToVersion4.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/20201108170812_UpdateIdentityServerToVersion4.Designer.cs new file mode 100644 index 000000000..a1b8ecce5 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/20201108170812_UpdateIdentityServerToVersion4.Designer.cs @@ -0,0 +1,905 @@ +// + +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL.Migrations.IdentityServerConfiguration +{ + [DbContext(typeof(IdentityServerConfigurationDbContext))] + [Migration("20201108170812_UpdateIdentityServerToVersion4")] + partial class UpdateIdentityServerToVersion4 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .HasAnnotation("ProductVersion", "3.1.9") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("AllowedAccessTokenSigningAlgorithms") + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + b.Property("Created") + .HasColumnType("timestamp without time zone"); + + b.Property("Description") + .HasColumnType("character varying(1000)") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("LastAccessed") + .HasColumnType("timestamp without time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("NonEditable") + .HasColumnType("boolean"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("boolean"); + + b.Property("Updated") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("ApiResources"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ApiResourceId") + .HasColumnType("integer"); + + b.Property("Type") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceClaims"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ApiResourceId") + .HasColumnType("integer"); + + b.Property("Key") + .IsRequired() + .HasColumnType("character varying(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("character varying(2000)") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceProperties"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ApiResourceId") + .HasColumnType("integer"); + + b.Property("Scope") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceScopes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ApiResourceId") + .HasColumnType("integer"); + + b.Property("Created") + .HasColumnType("timestamp without time zone"); + + b.Property("Description") + .HasColumnType("character varying(1000)") + .HasMaxLength(1000); + + b.Property("Expiration") + .HasColumnType("timestamp without time zone"); + + b.Property("Type") + .IsRequired() + .HasColumnType("character varying(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("character varying(4000)") + .HasMaxLength(4000); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceSecrets"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("Description") + .HasColumnType("character varying(1000)") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("Emphasize") + .HasColumnType("boolean"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("Required") + .HasColumnType("boolean"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("ApiScopes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ScopeId") + .HasColumnType("integer"); + + b.Property("Type") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ScopeId"); + + b.ToTable("ApiScopeClaims"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("Key") + .IsRequired() + .HasColumnType("character varying(250)") + .HasMaxLength(250); + + b.Property("ScopeId") + .HasColumnType("integer"); + + b.Property("Value") + .IsRequired() + .HasColumnType("character varying(2000)") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ScopeId"); + + b.ToTable("ApiScopeProperties"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("AbsoluteRefreshTokenLifetime") + .HasColumnType("integer"); + + b.Property("AccessTokenLifetime") + .HasColumnType("integer"); + + b.Property("AccessTokenType") + .HasColumnType("integer"); + + b.Property("AllowAccessTokensViaBrowser") + .HasColumnType("boolean"); + + b.Property("AllowOfflineAccess") + .HasColumnType("boolean"); + + b.Property("AllowPlainTextPkce") + .HasColumnType("boolean"); + + b.Property("AllowRememberConsent") + .HasColumnType("boolean"); + + b.Property("AllowedIdentityTokenSigningAlgorithms") + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + b.Property("AlwaysIncludeUserClaimsInIdToken") + .HasColumnType("boolean"); + + b.Property("AlwaysSendClientClaims") + .HasColumnType("boolean"); + + b.Property("AuthorizationCodeLifetime") + .HasColumnType("integer"); + + b.Property("BackChannelLogoutSessionRequired") + .HasColumnType("boolean"); + + b.Property("BackChannelLogoutUri") + .HasColumnType("character varying(2000)") + .HasMaxLength(2000); + + b.Property("ClientClaimsPrefix") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("ClientName") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("ClientUri") + .HasColumnType("character varying(2000)") + .HasMaxLength(2000); + + b.Property("ConsentLifetime") + .HasColumnType("integer"); + + b.Property("Created") + .HasColumnType("timestamp without time zone"); + + b.Property("Description") + .HasColumnType("character varying(1000)") + .HasMaxLength(1000); + + b.Property("DeviceCodeLifetime") + .HasColumnType("integer"); + + b.Property("EnableLocalLogin") + .HasColumnType("boolean"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("FrontChannelLogoutSessionRequired") + .HasColumnType("boolean"); + + b.Property("FrontChannelLogoutUri") + .HasColumnType("character varying(2000)") + .HasMaxLength(2000); + + b.Property("IdentityTokenLifetime") + .HasColumnType("integer"); + + b.Property("IncludeJwtId") + .HasColumnType("boolean"); + + b.Property("LastAccessed") + .HasColumnType("timestamp without time zone"); + + b.Property("LogoUri") + .HasColumnType("character varying(2000)") + .HasMaxLength(2000); + + b.Property("NonEditable") + .HasColumnType("boolean"); + + b.Property("PairWiseSubjectSalt") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("ProtocolType") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("RefreshTokenExpiration") + .HasColumnType("integer"); + + b.Property("RefreshTokenUsage") + .HasColumnType("integer"); + + b.Property("RequireClientSecret") + .HasColumnType("boolean"); + + b.Property("RequireConsent") + .HasColumnType("boolean"); + + b.Property("RequirePkce") + .HasColumnType("boolean"); + + b.Property("RequireRequestObject") + .HasColumnType("boolean"); + + b.Property("SlidingRefreshTokenLifetime") + .HasColumnType("integer"); + + b.Property("UpdateAccessTokenClaimsOnRefresh") + .HasColumnType("boolean"); + + b.Property("Updated") + .HasColumnType("timestamp without time zone"); + + b.Property("UserCodeType") + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + b.Property("UserSsoLifetime") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique(); + + b.ToTable("Clients"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClientId") + .HasColumnType("integer"); + + b.Property("Type") + .IsRequired() + .HasColumnType("character varying(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("character varying(250)") + .HasMaxLength(250); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientClaims"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClientId") + .HasColumnType("integer"); + + b.Property("Origin") + .IsRequired() + .HasColumnType("character varying(150)") + .HasMaxLength(150); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientCorsOrigins"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClientId") + .HasColumnType("integer"); + + b.Property("GrantType") + .IsRequired() + .HasColumnType("character varying(250)") + .HasMaxLength(250); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientGrantTypes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClientId") + .HasColumnType("integer"); + + b.Property("Provider") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientIdPRestrictions"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClientId") + .HasColumnType("integer"); + + b.Property("PostLogoutRedirectUri") + .IsRequired() + .HasColumnType("character varying(2000)") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientPostLogoutRedirectUris"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClientId") + .HasColumnType("integer"); + + b.Property("Key") + .IsRequired() + .HasColumnType("character varying(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("character varying(2000)") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientProperties"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClientId") + .HasColumnType("integer"); + + b.Property("RedirectUri") + .IsRequired() + .HasColumnType("character varying(2000)") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientRedirectUris"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClientId") + .HasColumnType("integer"); + + b.Property("Scope") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientScopes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClientId") + .HasColumnType("integer"); + + b.Property("Created") + .HasColumnType("timestamp without time zone"); + + b.Property("Description") + .HasColumnType("character varying(2000)") + .HasMaxLength(2000); + + b.Property("Expiration") + .HasColumnType("timestamp without time zone"); + + b.Property("Type") + .IsRequired() + .HasColumnType("character varying(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("character varying(4000)") + .HasMaxLength(4000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientSecrets"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("Created") + .HasColumnType("timestamp without time zone"); + + b.Property("Description") + .HasColumnType("character varying(1000)") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("Emphasize") + .HasColumnType("boolean"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("NonEditable") + .HasColumnType("boolean"); + + b.Property("Required") + .HasColumnType("boolean"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("boolean"); + + b.Property("Updated") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("IdentityResources"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("IdentityResourceId") + .HasColumnType("integer"); + + b.Property("Type") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.ToTable("IdentityResourceClaims"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("IdentityResourceId") + .HasColumnType("integer"); + + b.Property("Key") + .IsRequired() + .HasColumnType("character varying(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("character varying(2000)") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.ToTable("IdentityResourceProperties"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Properties") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Scopes") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Secrets") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope") + .WithMany("UserClaims") + .HasForeignKey("ScopeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope") + .WithMany("Properties") + .HasForeignKey("ScopeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("Claims") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("AllowedCorsOrigins") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("AllowedGrantTypes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("IdentityProviderRestrictions") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("PostLogoutRedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("Properties") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("RedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("AllowedScopes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("ClientSecrets") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource") + .WithMany("UserClaims") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource") + .WithMany("Properties") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/20201108170812_UpdateIdentityServerToVersion4.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/20201108170812_UpdateIdentityServerToVersion4.cs new file mode 100644 index 000000000..dd891eb50 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/20201108170812_UpdateIdentityServerToVersion4.cs @@ -0,0 +1,563 @@ +// Original SQL scripts for database migration come from: https://github.com/RockSolidKnowledge/IdentityServer4.Migration.Scripts/blob/master/Postgres/ConfigurationDbContext.sql +// Modified by Jan Škoruba + +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL.Migrations.IdentityServerConfiguration +{ + public partial class UpdateIdentityServerToVersion4 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ApiClaims_ApiResources_ApiResourceId", + table: "ApiClaims"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiProperties_ApiResources_ApiResourceId", + table: "ApiProperties"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiScopeClaims_ApiScopes_ApiScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiScopes_ApiResources_ApiResourceId", + table: "ApiScopes"); + + migrationBuilder.DropForeignKey( + name: "FK_IdentityProperties_IdentityResources_IdentityResourceId", + table: "IdentityProperties"); + + migrationBuilder.DropIndex( + name: "IX_ApiScopes_ApiResourceId", + table: "ApiScopes"); + + migrationBuilder.DropIndex( + name: "IX_ApiScopeClaims_ApiScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropPrimaryKey( + name: "PK_IdentityProperties", + table: "IdentityProperties"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ApiProperties", + table: "ApiProperties"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ApiClaims", + table: "ApiClaims"); + + migrationBuilder.RenameTable( + name: "IdentityProperties", + newName: "IdentityResourceProperties"); + + migrationBuilder.RenameTable( + name: "ApiProperties", + newName: "ApiResourceProperties"); + + migrationBuilder.RenameTable( + name: "ApiClaims", + newName: "ApiResourceClaims"); + + migrationBuilder.RenameIndex( + name: "IX_IdentityProperties_IdentityResourceId", + table: "IdentityResourceProperties", + newName: "IX_IdentityResourceProperties_IdentityResourceId"); + + migrationBuilder.RenameIndex( + name: "IX_ApiProperties_ApiResourceId", + table: "ApiResourceProperties", + newName: "IX_ApiResourceProperties_ApiResourceId"); + + migrationBuilder.RenameIndex( + name: "IX_ApiClaims_ApiResourceId", + table: "ApiResourceClaims", + newName: "IX_ApiResourceClaims_ApiResourceId"); + + migrationBuilder.AddColumn( + name: "AllowedIdentityTokenSigningAlgorithms", + table: "Clients", + maxLength: 100, + nullable: true); + + migrationBuilder.AddColumn( + name: "RequireRequestObject", + table: "Clients", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "Enabled", + table: "ApiScopes", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "ScopeId", + table: "ApiScopeClaims", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "AllowedAccessTokenSigningAlgorithms", + table: "ApiResources", + maxLength: 100, + nullable: true); + + migrationBuilder.AddColumn( + name: "ShowInDiscoveryDocument", + table: "ApiResources", + nullable: false, + defaultValue: false); + + migrationBuilder.AddPrimaryKey( + name: "PK_IdentityResourceProperties", + table: "IdentityResourceProperties", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ApiResourceProperties", + table: "ApiResourceProperties", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ApiResourceClaims", + table: "ApiResourceClaims", + column: "Id"); + + migrationBuilder.CreateTable( + name: "ApiResourceScopes", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Scope = table.Column(maxLength: 200, nullable: false), + ApiResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiResourceScopes", x => x.Id); + table.ForeignKey( + name: "FK_ApiResourceScopes_ApiResources_ApiResourceId", + column: x => x.ApiResourceId, + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ApiResourceSecrets", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Description = table.Column(maxLength: 1000, nullable: true), + Value = table.Column(maxLength: 4000, nullable: false), + Expiration = table.Column(nullable: true), + Type = table.Column(maxLength: 250, nullable: false), + Created = table.Column(nullable: false), + ApiResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiResourceSecrets", x => x.Id); + table.ForeignKey( + name: "FK_ApiResourceSecrets_ApiResources_ApiResourceId", + column: x => x.ApiResourceId, + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ApiScopeProperties", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Key = table.Column(maxLength: 250, nullable: false), + Value = table.Column(maxLength: 2000, nullable: false), + ScopeId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiScopeProperties", x => x.Id); + table.ForeignKey( + name: "FK_ApiScopeProperties_ApiScopes_ScopeId", + column: x => x.ScopeId, + principalTable: "ApiScopes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityResourceClaims", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Type = table.Column(maxLength: 200, nullable: false), + IdentityResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityResourceClaims", x => x.Id); + table.ForeignKey( + name: "FK_IdentityResourceClaims_IdentityResources_IdentityResourceId", + column: x => x.IdentityResourceId, + principalTable: "IdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ApiScopeClaims_ScopeId", + table: "ApiScopeClaims", + column: "ScopeId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiResourceScopes_ApiResourceId", + table: "ApiResourceScopes", + column: "ApiResourceId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiResourceSecrets_ApiResourceId", + table: "ApiResourceSecrets", + column: "ApiResourceId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiScopeProperties_ScopeId", + table: "ApiScopeProperties", + column: "ScopeId"); + + migrationBuilder.CreateIndex( + name: "IX_IdentityResourceClaims_IdentityResourceId", + table: "IdentityResourceClaims", + column: "IdentityResourceId"); + + migrationBuilder.AddForeignKey( + name: "FK_ApiResourceClaims_ApiResources_ApiResourceId", + table: "ApiResourceClaims", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + // migrate data + + migrationBuilder.Sql(@"INSERT INTO ""ApiResourceSecrets"" + (""Id"", ""Description"", ""Value"", ""Expiration"", ""Type"", ""Created"", ""ApiResourceId"") + SELECT + ""Id"", ""Description"", ""Value"", ""Expiration"", ""Type"", ""Created"", ""ApiResourceId"" + FROM ""ApiSecrets"";"); + + migrationBuilder.Sql(@"INSERT INTO ""IdentityResourceClaims"" + (""Id"", ""Type"", ""IdentityResourceId"") +SELECT + ""Id"", ""Type"", ""IdentityResourceId"" +FROM ""IdentityClaims"";"); + + migrationBuilder.Sql(@"INSERT INTO ""ApiResourceScopes"" + (""Scope"", ""ApiResourceId"") +SELECT + ""Name"", ""ApiResourceId"" +FROM ""ApiScopes"";"); + + migrationBuilder.Sql(@"UPDATE ""ApiScopeClaims"" SET ""ScopeId"" = ""ApiScopeId"";"); + + migrationBuilder.Sql(@"UPDATE ""ApiScopes"" SET ""Enabled"" = TRUE;"); + + migrationBuilder.DropTable( + name: "ApiSecrets"); + + migrationBuilder.DropTable( + name: "IdentityClaims"); + + migrationBuilder.DropColumn( + name: "ApiResourceId", + table: "ApiScopes"); + + migrationBuilder.DropColumn( + name: "ApiScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.AddForeignKey( + name: "FK_ApiResourceProperties_ApiResources_ApiResourceId", + table: "ApiResourceProperties", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ApiScopeClaims_ApiScopes_ScopeId", + table: "ApiScopeClaims", + column: "ScopeId", + principalTable: "ApiScopes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_IdentityResourceProperties_IdentityResources_IdentityResour~", + table: "IdentityResourceProperties", + column: "IdentityResourceId", + principalTable: "IdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ApiResourceClaims_ApiResources_ApiResourceId", + table: "ApiResourceClaims"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiResourceProperties_ApiResources_ApiResourceId", + table: "ApiResourceProperties"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiScopeClaims_ApiScopes_ScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropForeignKey( + name: "FK_IdentityResourceProperties_IdentityResources_IdentityResour~", + table: "IdentityResourceProperties"); + + migrationBuilder.DropIndex( + name: "IX_ApiScopeClaims_ScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropPrimaryKey( + name: "PK_IdentityResourceProperties", + table: "IdentityResourceProperties"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ApiResourceProperties", + table: "ApiResourceProperties"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ApiResourceClaims", + table: "ApiResourceClaims"); + + migrationBuilder.RenameTable( + name: "IdentityResourceProperties", + newName: "IdentityProperties"); + + migrationBuilder.RenameTable( + name: "ApiResourceProperties", + newName: "ApiProperties"); + + migrationBuilder.RenameTable( + name: "ApiResourceClaims", + newName: "ApiClaims"); + + migrationBuilder.RenameIndex( + name: "IX_IdentityResourceProperties_IdentityResourceId", + table: "IdentityProperties", + newName: "IX_IdentityProperties_IdentityResourceId"); + + migrationBuilder.RenameIndex( + name: "IX_ApiResourceProperties_ApiResourceId", + table: "ApiProperties", + newName: "IX_ApiProperties_ApiResourceId"); + + migrationBuilder.RenameIndex( + name: "IX_ApiResourceClaims_ApiResourceId", + table: "ApiClaims", + newName: "IX_ApiClaims_ApiResourceId"); + + migrationBuilder.AddColumn( + name: "ApiResourceId", + table: "ApiScopes", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "ApiScopeId", + table: "ApiScopeClaims", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddPrimaryKey( + name: "PK_IdentityProperties", + table: "IdentityProperties", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ApiProperties", + table: "ApiProperties", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ApiClaims", + table: "ApiClaims", + column: "Id"); + + migrationBuilder.CreateTable( + name: "ApiSecrets", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + ApiResourceId = table.Column(type: "integer", nullable: false), + Created = table.Column(type: "timestamp without time zone", nullable: false), + Description = table.Column(type: "character varying(1000)", maxLength: 1000, nullable: true), + Expiration = table.Column(type: "timestamp without time zone", nullable: true), + Type = table.Column(type: "character varying(250)", maxLength: 250, nullable: false), + Value = table.Column(type: "character varying(4000)", maxLength: 4000, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiSecrets", x => x.Id); + table.ForeignKey( + name: "FK_ApiSecrets_ApiResources_ApiResourceId", + column: x => x.ApiResourceId, + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityClaims", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + IdentityResourceId = table.Column(type: "integer", nullable: false), + Type = table.Column(type: "character varying(200)", maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityClaims", x => x.Id); + table.ForeignKey( + name: "FK_IdentityClaims_IdentityResources_IdentityResourceId", + column: x => x.IdentityResourceId, + principalTable: "IdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ApiScopes_ApiResourceId", + table: "ApiScopes", + column: "ApiResourceId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiScopeClaims_ApiScopeId", + table: "ApiScopeClaims", + column: "ApiScopeId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiSecrets_ApiResourceId", + table: "ApiSecrets", + column: "ApiResourceId"); + + migrationBuilder.CreateIndex( + name: "IX_IdentityClaims_IdentityResourceId", + table: "IdentityClaims", + column: "IdentityResourceId"); + + migrationBuilder.AddForeignKey( + name: "FK_ApiClaims_ApiResources_ApiResourceId", + table: "ApiClaims", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ApiProperties_ApiResources_ApiResourceId", + table: "ApiProperties", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + // Rollback data back + migrationBuilder.Sql(@"INSERT INTO ""ApiSecrets"" + (""Id"", ""Description"", ""Value"", ""Expiration"", ""Type"", ""Created"", ""ApiResourceId"") +SELECT ""Id"", ""Description"", ""Value"", ""Expiration"", ""Type"", ""Created"", ""ApiResourceId"" +FROM ""ApiResourceSecrets"";"); + + migrationBuilder.Sql(@"INSERT INTO ""IdentityClaims"" + (""Id"", ""Type"", ""IdentityResourceId"") +SELECT + ""Id"", ""Type"", ""IdentityResourceId"" +FROM ""IdentityResourceClaims"";"); + + migrationBuilder.Sql(@"UPDATE ""ApiScopes"" asp +SET ""ApiResourceId"" = arc.""ApiResourceId"" +FROM ""ApiResourceScopes"" arc +WHERE arc.""Id"" = asp.""Id"";"); + + migrationBuilder.Sql(@"UPDATE ""ApiScopeClaims"" SET ""ApiScopeId"" = ""ScopeId"";"); + + migrationBuilder.DropTable( + name: "ApiResourceScopes"); + + migrationBuilder.DropTable( + name: "ApiResourceSecrets"); + + migrationBuilder.DropTable( + name: "ApiScopeProperties"); + + migrationBuilder.DropTable( + name: "IdentityResourceClaims"); + + migrationBuilder.DropColumn( + name: "AllowedIdentityTokenSigningAlgorithms", + table: "Clients"); + + migrationBuilder.DropColumn( + name: "RequireRequestObject", + table: "Clients"); + + migrationBuilder.DropColumn( + name: "Enabled", + table: "ApiScopes"); + + migrationBuilder.DropColumn( + name: "ScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropColumn( + name: "AllowedAccessTokenSigningAlgorithms", + table: "ApiResources"); + + migrationBuilder.DropColumn( + name: "ShowInDiscoveryDocument", + table: "ApiResources"); + + migrationBuilder.AddForeignKey( + name: "FK_ApiScopeClaims_ApiScopes_ApiScopeId", + table: "ApiScopeClaims", + column: "ApiScopeId", + principalTable: "ApiScopes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ApiScopes_ApiResources_ApiResourceId", + table: "ApiScopes", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_IdentityProperties_IdentityResources_IdentityResourceId", + table: "IdentityProperties", + column: "IdentityResourceId", + principalTable: "IdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/IdentityServerConfigurationDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/IdentityServerConfigurationDbContextModelSnapshot.cs index ada2e9c39..1ab5ea127 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/IdentityServerConfigurationDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerConfiguration/IdentityServerConfigurationDbContextModelSnapshot.cs @@ -1,8 +1,8 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; @@ -16,7 +16,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) #pragma warning disable 612, 618 modelBuilder .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) - .HasAnnotation("ProductVersion", "3.0.0") + .HasAnnotation("ProductVersion", "3.1.9") .HasAnnotation("Relational:MaxIdentifierLength", 63); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b => @@ -26,6 +26,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("integer") .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + b.Property("AllowedAccessTokenSigningAlgorithms") + .HasColumnType("character varying(100)") + .HasMaxLength(100); + b.Property("Created") .HasColumnType("timestamp without time zone"); @@ -51,6 +55,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("NonEditable") .HasColumnType("boolean"); + b.Property("ShowInDiscoveryDocument") + .HasColumnType("boolean"); + b.Property("Updated") .HasColumnType("timestamp without time zone"); @@ -81,7 +88,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("ApiResourceId"); - b.ToTable("ApiClaims"); + b.ToTable("ApiResourceClaims"); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b => @@ -108,10 +115,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("ApiResourceId"); - b.ToTable("ApiProperties"); + b.ToTable("ApiResourceProperties"); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -121,6 +128,62 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ApiResourceId") .HasColumnType("integer"); + b.Property("Scope") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceScopes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ApiResourceId") + .HasColumnType("integer"); + + b.Property("Created") + .HasColumnType("timestamp without time zone"); + + b.Property("Description") + .HasColumnType("character varying(1000)") + .HasMaxLength(1000); + + b.Property("Expiration") + .HasColumnType("timestamp without time zone"); + + b.Property("Type") + .IsRequired() + .HasColumnType("character varying(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("character varying(4000)") + .HasMaxLength(4000); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceSecrets"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + b.Property("Description") .HasColumnType("character varying(1000)") .HasMaxLength(1000); @@ -132,6 +195,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Emphasize") .HasColumnType("boolean"); + b.Property("Enabled") + .HasColumnType("boolean"); + b.Property("Name") .IsRequired() .HasColumnType("character varying(200)") @@ -145,8 +211,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("ApiResourceId"); - b.HasIndex("Name") .IsUnique(); @@ -160,7 +224,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("integer") .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - b.Property("ApiScopeId") + b.Property("ScopeId") .HasColumnType("integer"); b.Property("Type") @@ -170,46 +234,36 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("ApiScopeId"); + b.HasIndex("ScopeId"); b.ToTable("ApiScopeClaims"); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("integer") .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - b.Property("ApiResourceId") - .HasColumnType("integer"); - - b.Property("Created") - .HasColumnType("timestamp without time zone"); - - b.Property("Description") - .HasColumnType("character varying(1000)") - .HasMaxLength(1000); - - b.Property("Expiration") - .HasColumnType("timestamp without time zone"); - - b.Property("Type") + b.Property("Key") .IsRequired() .HasColumnType("character varying(250)") .HasMaxLength(250); + b.Property("ScopeId") + .HasColumnType("integer"); + b.Property("Value") .IsRequired() - .HasColumnType("character varying(4000)") - .HasMaxLength(4000); + .HasColumnType("character varying(2000)") + .HasMaxLength(2000); b.HasKey("Id"); - b.HasIndex("ApiResourceId"); + b.HasIndex("ScopeId"); - b.ToTable("ApiSecrets"); + b.ToTable("ApiScopeProperties"); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b => @@ -240,6 +294,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("AllowRememberConsent") .HasColumnType("boolean"); + b.Property("AllowedIdentityTokenSigningAlgorithms") + .HasColumnType("character varying(100)") + .HasMaxLength(100); + b.Property("AlwaysIncludeUserClaimsInIdToken") .HasColumnType("boolean"); @@ -339,6 +397,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("RequirePkce") .HasColumnType("boolean"); + b.Property("RequireRequestObject") + .HasColumnType("boolean"); + b.Property("SlidingRefreshTokenLifetime") .HasColumnType("integer"); @@ -586,28 +647,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("ClientSecrets"); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("IdentityResourceId") - .HasColumnType("integer"); - - b.Property("Type") - .IsRequired() - .HasColumnType("character varying(200)") - .HasMaxLength(200); - - b.HasKey("Id"); - - b.HasIndex("IdentityResourceId"); - - b.ToTable("IdentityClaims"); - }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b => { b.Property("Id") @@ -657,6 +696,28 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("IdentityResources"); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("IdentityResourceId") + .HasColumnType("integer"); + + b.Property("Type") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.ToTable("IdentityResourceClaims"); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b => { b.Property("Id") @@ -681,7 +742,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("IdentityResourceId"); - b.ToTable("IdentityProperties"); + b.ToTable("IdentityResourceProperties"); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b => @@ -702,7 +763,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b => { b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") .WithMany("Scopes") @@ -711,20 +772,29 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Secrets") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b => { - b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "ApiScope") + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope") .WithMany("UserClaims") - .HasForeignKey("ApiScopeId") + .HasForeignKey("ScopeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b => { - b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") - .WithMany("Secrets") - .HasForeignKey("ApiResourceId") + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope") + .WithMany("Properties") + .HasForeignKey("ScopeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); @@ -810,7 +880,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b => { b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource") .WithMany("UserClaims") diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/20191120100155_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/20191120100155_DbInit.Designer.cs index 79c719e1b..769509d27 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/20191120100155_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/20191120100155_DbInit.Designer.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/20201108165927_UpdateIdentityServerToVersion4.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/20201108165927_UpdateIdentityServerToVersion4.Designer.cs new file mode 100644 index 000000000..77be4f2b0 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/20201108165927_UpdateIdentityServerToVersion4.Designer.cs @@ -0,0 +1,129 @@ +// + +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL.Migrations.IdentityServerGrants +{ + [DbContext(typeof(IdentityServerPersistedGrantDbContext))] + [Migration("20201108165927_UpdateIdentityServerToVersion4")] + partial class UpdateIdentityServerToVersion4 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .HasAnnotation("ProductVersion", "3.1.9") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .IsRequired() + .HasColumnType("character varying(50000)") + .HasMaxLength(50000); + + b.Property("Description") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("DeviceCode") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("timestamp without time zone"); + + b.Property("SessionId") + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + b.Property("SubjectId") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Key") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("ConsumedTime") + .HasColumnType("timestamp without time zone"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .IsRequired() + .HasColumnType("character varying(50000)") + .HasMaxLength(50000); + + b.Property("Description") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("Expiration") + .HasColumnType("timestamp without time zone"); + + b.Property("SessionId") + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + b.Property("SubjectId") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("Type") + .IsRequired() + .HasColumnType("character varying(50)") + .HasMaxLength(50); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.HasIndex("SubjectId", "SessionId", "Type"); + + b.ToTable("PersistedGrants"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/20201108165927_UpdateIdentityServerToVersion4.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/20201108165927_UpdateIdentityServerToVersion4.cs new file mode 100644 index 000000000..32783b1f7 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/20201108165927_UpdateIdentityServerToVersion4.cs @@ -0,0 +1,72 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL.Migrations.IdentityServerGrants +{ + public partial class UpdateIdentityServerToVersion4 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ConsumedTime", + table: "PersistedGrants", + nullable: true); + + migrationBuilder.AddColumn( + name: "Description", + table: "PersistedGrants", + maxLength: 200, + nullable: true); + + migrationBuilder.AddColumn( + name: "SessionId", + table: "PersistedGrants", + maxLength: 100, + nullable: true); + + migrationBuilder.AddColumn( + name: "Description", + table: "DeviceCodes", + maxLength: 200, + nullable: true); + + migrationBuilder.AddColumn( + name: "SessionId", + table: "DeviceCodes", + maxLength: 100, + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_PersistedGrants_SubjectId_SessionId_Type", + table: "PersistedGrants", + columns: new[] { "SubjectId", "SessionId", "Type" }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_PersistedGrants_SubjectId_SessionId_Type", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "ConsumedTime", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "Description", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "SessionId", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "Description", + table: "DeviceCodes"); + + migrationBuilder.DropColumn( + name: "SessionId", + table: "DeviceCodes"); + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/IdentityServerPersistedGrantDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/IdentityServerPersistedGrantDbContextModelSnapshot.cs index cae5bb065..c000b55c2 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/IdentityServerPersistedGrantDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/IdentityServerGrants/IdentityServerPersistedGrantDbContextModelSnapshot.cs @@ -1,8 +1,8 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; @@ -16,7 +16,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) #pragma warning disable 612, 618 modelBuilder .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) - .HasAnnotation("ProductVersion", "3.0.0") + .HasAnnotation("ProductVersion", "3.1.9") .HasAnnotation("Relational:MaxIdentifierLength", 63); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => @@ -38,6 +38,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("character varying(50000)") .HasMaxLength(50000); + b.Property("Description") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + b.Property("DeviceCode") .IsRequired() .HasColumnType("character varying(200)") @@ -47,6 +51,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired() .HasColumnType("timestamp without time zone"); + b.Property("SessionId") + .HasColumnType("character varying(100)") + .HasMaxLength(100); + b.Property("SubjectId") .HasColumnType("character varying(200)") .HasMaxLength(200); @@ -72,6 +80,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("character varying(200)") .HasMaxLength(200); + b.Property("ConsumedTime") + .HasColumnType("timestamp without time zone"); + b.Property("CreationTime") .HasColumnType("timestamp without time zone"); @@ -80,9 +91,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("character varying(50000)") .HasMaxLength(50000); + b.Property("Description") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + b.Property("Expiration") .HasColumnType("timestamp without time zone"); + b.Property("SessionId") + .HasColumnType("character varying(100)") + .HasMaxLength(100); + b.Property("SubjectId") .HasColumnType("character varying(200)") .HasMaxLength(200); @@ -98,6 +117,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("SubjectId", "ClientId", "Type"); + b.HasIndex("SubjectId", "SessionId", "Type"); + b.ToTable("PersistedGrants"); }); #pragma warning restore 612, 618 diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Logging/20191120100104_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Logging/20191120100104_DbInit.Designer.cs index 00e6a2803..e1b45f352 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Logging/20191120100104_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Logging/20191120100104_DbInit.Designer.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Logging/AdminLogDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Logging/AdminLogDbContextModelSnapshot.cs index 66de01cb1..b2c01e6ac 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Logging/AdminLogDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Migrations/Logging/AdminLogDbContextModelSnapshot.cs @@ -1,8 +1,8 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL.csproj b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL.csproj index 494daf9c0..38a1816cd 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL.csproj +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL/Skoruba.IdentityServer4.Admin.EntityFramework.PostgreSQL.csproj @@ -1,8 +1,8 @@  - netcoreapp3.1 - 1.0.0 + net5.0 + 2.0.0 Jan Škoruba IdentityServer4 Admin OpenIDConnect OAuth2 Identity Entity Framework layer for the administration of the IdentityServer4 and Asp.Net Core Identity with PostrgreSQL support @@ -12,8 +12,8 @@ - - + + @@ -27,3 +27,11 @@ + + + + + + + + diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Configuration/DatabaseProviderConfiguration.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Configuration/DatabaseProviderConfiguration.cs deleted file mode 100644 index 8622bea8d..000000000 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Configuration/DatabaseProviderConfiguration.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Skoruba.IdentityServer4.Admin.EntityFramework.Shared.Configuration -{ - public class DatabaseProviderConfiguration - { - public DatabaseProviderType ProviderType { get; set; } - } -} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Configuration/DatabaseProviderType.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Configuration/DatabaseProviderType.cs deleted file mode 100644 index 3e7cd9e6c..000000000 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Configuration/DatabaseProviderType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Skoruba.IdentityServer4.Admin.EntityFramework.Shared.Configuration -{ - public enum DatabaseProviderType - { - SqlServer, - PostgreSQL, - MySql - } -} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/DbContexts/IdentityServerConfigurationDbContext.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/DbContexts/IdentityServerConfigurationDbContext.cs index 5419c16fb..59ac8e796 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/DbContexts/IdentityServerConfigurationDbContext.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/DbContexts/IdentityServerConfigurationDbContext.cs @@ -17,13 +17,11 @@ public IdentityServerConfigurationDbContext(DbContextOptions IdentityResourceProperties { get; set; } - public DbSet ApiSecrets { get; set; } - - public DbSet ApiScopes { get; set; } + public DbSet ApiSecrets { get; set; } public DbSet ApiScopeClaims { get; set; } - public DbSet IdentityClaims { get; set; } + public DbSet IdentityClaims { get; set; } public DbSet ApiResourceClaims { get; set; } @@ -35,8 +33,6 @@ public IdentityServerConfigurationDbContext(DbContextOptions ClientPostLogoutRedirectUris { get; set; } - public DbSet ClientCorsOrigins { get; set; } - public DbSet ClientIdPRestrictions { get; set; } public DbSet ClientRedirectUris { get; set; } @@ -44,5 +40,9 @@ public IdentityServerConfigurationDbContext(DbContextOptions ClientClaims { get; set; } public DbSet ClientProperties { get; set; } + + public DbSet ApiScopeProperties { get; set; } + + public DbSet ApiResourceScopes { get; set; } } } \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Helpers/DbMigrationHelpers.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Helpers/DbMigrationHelpers.cs new file mode 100644 index 000000000..b7f417d3a --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Helpers/DbMigrationHelpers.cs @@ -0,0 +1,262 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using IdentityModel; +using IdentityServer4.EntityFramework.Mappers; +using IdentityServer4.Models; +using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Skoruba.AuditLogging.EntityFramework.DbContexts; +using Skoruba.AuditLogging.EntityFramework.Entities; +using Skoruba.IdentityServer4.Admin.EntityFramework.Configuration.Configuration; +using Skoruba.IdentityServer4.Admin.EntityFramework.Interfaces; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Shared.Helpers +{ + public static class DbMigrationHelpers + { + /// + /// Generate migrations before running this method, you can use these steps bellow: + /// https://github.com/skoruba/IdentityServer4.Admin#ef-core--data-access + /// + /// + /// + /// + /// + public static async Task ApplyDbMigrationsWithDataSeedAsync( + IHost host, bool applyDbMigrationWithDataSeedFromProgramArguments, SeedConfiguration seedConfiguration, + DatabaseMigrationsConfiguration databaseMigrationsConfiguration) + where TIdentityServerDbContext : DbContext, IAdminConfigurationDbContext + where TIdentityDbContext : DbContext + where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext + where TLogDbContext : DbContext, IAdminLogDbContext + where TAuditLogDbContext : DbContext, IAuditLoggingDbContext + where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext + where TUser : IdentityUser, new() + where TRole : IdentityRole, new() + { + using (var serviceScope = host.Services.CreateScope()) + { + var services = serviceScope.ServiceProvider; + + if ((databaseMigrationsConfiguration != null && databaseMigrationsConfiguration.ApplyDatabaseMigrations) + || (applyDbMigrationWithDataSeedFromProgramArguments)) + { + await EnsureDatabasesMigratedAsync(services); + } + + if ((seedConfiguration != null && seedConfiguration.ApplySeed) + || (applyDbMigrationWithDataSeedFromProgramArguments)) + { + await EnsureSeedDataAsync(services); + } + } + } + + public static async Task EnsureDatabasesMigratedAsync(IServiceProvider services) + where TIdentityDbContext : DbContext + where TPersistedGrantDbContext : DbContext + where TConfigurationDbContext : DbContext + where TLogDbContext : DbContext + where TAuditLogDbContext : DbContext + where TDataProtectionDbContext : DbContext + { + using (var scope = services.GetRequiredService().CreateScope()) + { + using (var context = scope.ServiceProvider.GetRequiredService()) + { + await context.Database.MigrateAsync(); + } + + using (var context = scope.ServiceProvider.GetRequiredService()) + { + await context.Database.MigrateAsync(); + } + + using (var context = scope.ServiceProvider.GetRequiredService()) + { + await context.Database.MigrateAsync(); + } + + using (var context = scope.ServiceProvider.GetRequiredService()) + { + await context.Database.MigrateAsync(); + } + + using (var context = scope.ServiceProvider.GetRequiredService()) + { + await context.Database.MigrateAsync(); + } + + using (var context = scope.ServiceProvider.GetRequiredService()) + { + await context.Database.MigrateAsync(); + } + } + } + + public static async Task EnsureSeedDataAsync(IServiceProvider serviceProvider) + where TIdentityServerDbContext : DbContext, IAdminConfigurationDbContext + where TUser : IdentityUser, new() + where TRole : IdentityRole, new() + { + using (var scope = serviceProvider.GetRequiredService().CreateScope()) + { + var context = scope.ServiceProvider.GetRequiredService(); + var userManager = scope.ServiceProvider.GetRequiredService>(); + var roleManager = scope.ServiceProvider.GetRequiredService>(); + var idsDataConfiguration = scope.ServiceProvider.GetRequiredService(); + var idDataConfiguration = scope.ServiceProvider.GetRequiredService(); + + await EnsureSeedIdentityServerData(context, idsDataConfiguration); + await EnsureSeedIdentityData(userManager, roleManager, idDataConfiguration); + } + } + + /// + /// Generate default admin user / role + /// + private static async Task EnsureSeedIdentityData(UserManager userManager, + RoleManager roleManager, IdentityData identityDataConfiguration) + where TUser : IdentityUser, new() + where TRole : IdentityRole, new() + { + // adding roles from seed + foreach (var r in identityDataConfiguration.Roles) + { + if (!await roleManager.RoleExistsAsync(r.Name)) + { + var role = new TRole + { + Name = r.Name + }; + + var result = await roleManager.CreateAsync(role); + + if (result.Succeeded) + { + foreach (var claim in r.Claims) + { + await roleManager.AddClaimAsync(role, new System.Security.Claims.Claim(claim.Type, claim.Value)); + } + } + } + } + + // adding users from seed + foreach (var user in identityDataConfiguration.Users) + { + var identityUser = new TUser + { + UserName = user.Username, + Email = user.Email, + EmailConfirmed = true + }; + + var userByUserName = await userManager.FindByNameAsync(user.Username); + var userByEmail = await userManager.FindByEmailAsync(user.Email); + + // User is already exists in database + if (userByUserName != default || userByEmail != default) + { + continue; + } + + // if there is no password we create user without password + // user can reset password later, because accounts have EmailConfirmed set to true + var result = !string.IsNullOrEmpty(user.Password) + ? await userManager.CreateAsync(identityUser, user.Password) + : await userManager.CreateAsync(identityUser); + + if (result.Succeeded) + { + foreach (var claim in user.Claims) + { + await userManager.AddClaimAsync(identityUser, new System.Security.Claims.Claim(claim.Type, claim.Value)); + } + + foreach (var role in user.Roles) + { + await userManager.AddToRoleAsync(identityUser, role); + } + } + } + } + + /// + /// Generate default clients, identity and api resources + /// + private static async Task EnsureSeedIdentityServerData(TIdentityServerDbContext context, IdentityServerData identityServerDataConfiguration) + where TIdentityServerDbContext : DbContext, IAdminConfigurationDbContext + { + foreach (var resource in identityServerDataConfiguration.IdentityResources) + { + var exits = await context.IdentityResources.AnyAsync(a => a.Name == resource.Name); + + if (exits) + { + continue; + } + + await context.IdentityResources.AddAsync(resource.ToEntity()); + } + + foreach (var apiScope in identityServerDataConfiguration.ApiScopes) + { + var exits = await context.ApiScopes.AnyAsync(a => a.Name == apiScope.Name); + + if (exits) + { + continue; + } + + await context.ApiScopes.AddAsync(apiScope.ToEntity()); + } + + foreach (var resource in identityServerDataConfiguration.ApiResources) + { + var exits = await context.ApiResources.AnyAsync(a => a.Name == resource.Name); + + if (exits) + { + continue; + } + + foreach (var s in resource.ApiSecrets) + { + s.Value = s.Value.ToSha256(); + } + + await context.ApiResources.AddAsync(resource.ToEntity()); + } + + + foreach (var client in identityServerDataConfiguration.Clients) + { + var exits = await context.Clients.AnyAsync(a => a.ClientId == client.ClientId); + + if (exits) + { + continue; + } + + foreach (var secret in client.ClientSecrets) + { + secret.Value = secret.Value.ToSha256(); + } + + client.Claims = client.ClientClaims + .Select(c => new ClientClaim(c.Type, c.Value)) + .ToList(); + + await context.Clients.AddAsync(client.ToEntity()); + } + + await context.SaveChangesAsync(); + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Skoruba.IdentityServer4.Admin.EntityFramework.Shared.csproj b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Skoruba.IdentityServer4.Admin.EntityFramework.Shared.csproj index 4317d49bb..e7aef51be 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Skoruba.IdentityServer4.Admin.EntityFramework.Shared.csproj +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.Shared/Skoruba.IdentityServer4.Admin.EntityFramework.Shared.csproj @@ -1,8 +1,8 @@  - netcoreapp3.1 - 1.0.0 + net5.0 + 2.0.0 Jan Škoruba IdentityServer4 Admin OpenIDConnect OAuth2 Identity DbContexts and Identity entities for the administration of the IdentityServer4 and Asp.Net Core Identity @@ -12,11 +12,12 @@ - - + + + @@ -25,3 +26,11 @@ + + + + + + + + diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Extensions/DatabaseExtensions.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Extensions/DatabaseExtensions.cs deleted file mode 100644 index 1825ebea9..000000000 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Extensions/DatabaseExtensions.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System.Reflection; -using IdentityServer4.EntityFramework.Storage; -using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Skoruba.AuditLogging.EntityFramework.DbContexts; -using Skoruba.AuditLogging.EntityFramework.Entities; -using Skoruba.IdentityServer4.Admin.EntityFramework.Interfaces; - -namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Extensions -{ - public static class DatabaseExtensions - { - /// - /// Register DbContexts for IdentityServer ConfigurationStore and PersistedGrants, Identity and Logging - /// Configure the connection strings in AppSettings.json - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static void RegisterSqlServerDbContexts(this IServiceCollection services, string identityConnectionString, string configurationConnectionString, string persistedGrantConnectionString, string errorLoggingConnectionString, string auditLoggingConnectionString, string dataProtectionConnectionString = null) - where TIdentityDbContext : DbContext - where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext - where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext - where TLogDbContext : DbContext, IAdminLogDbContext - where TAuditLoggingDbContext : DbContext, IAuditLoggingDbContext - where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext - { - var migrationsAssembly = typeof(DatabaseExtensions).GetTypeInfo().Assembly.GetName().Name; - - // Config DB for identity - services.AddDbContext(options => options.UseSqlServer(identityConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Config DB from existing connection - services.AddConfigurationDbContext(options => options.ConfigureDbContext = b => b.UseSqlServer(configurationConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Operational DB from existing connection - services.AddOperationalDbContext(options => options.ConfigureDbContext = b => b.UseSqlServer(persistedGrantConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Log DB from existing connection - services.AddDbContext(options => options.UseSqlServer(errorLoggingConnectionString, optionsSql => optionsSql.MigrationsAssembly(migrationsAssembly))); - - // Audit logging connection - services.AddDbContext(options => options.UseSqlServer(auditLoggingConnectionString, optionsSql => optionsSql.MigrationsAssembly(migrationsAssembly))); - - // DataProtectionKey DB from existing connection - if(!string.IsNullOrEmpty(dataProtectionConnectionString)) - services.AddDbContext(options => options.UseSqlServer(dataProtectionConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - } - - /// - /// Register DbContexts for IdentityServer ConfigurationStore and PersistedGrants and Identity - /// Configure the connection strings in AppSettings.json - /// - /// - /// - /// - /// - /// - /// - /// - public static void RegisterSqlServerDbContexts(this IServiceCollection services, - string identityConnectionString, string configurationConnectionString, - string persistedGrantConnectionString, string dataProtectionConnectionString) - where TIdentityDbContext : DbContext - where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext - where TConfigurationDbContext : DbContext, IAdminConfigurationDbContext - where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext - { - var migrationsAssembly = typeof(DatabaseExtensions).GetTypeInfo().Assembly.GetName().Name; - - // Config DB for identity - services.AddDbContext(options => options.UseSqlServer(identityConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Config DB from existing connection - services.AddConfigurationDbContext(options => options.ConfigureDbContext = b => b.UseSqlServer(configurationConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // Operational DB from existing connection - services.AddOperationalDbContext(options => options.ConfigureDbContext = b => b.UseSqlServer(persistedGrantConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - - // DataProtectionKey DB from existing connection - services.AddDbContext(options => options.UseSqlServer(dataProtectionConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly))); - } - } -} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Helpers/MigrationAssembly.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Helpers/MigrationAssembly.cs new file mode 100644 index 000000000..2dbdf3042 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Helpers/MigrationAssembly.cs @@ -0,0 +1,7 @@ +namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Helpers +{ + public class MigrationAssembly + { + + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/AuditLogging/20191119164022_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/AuditLogging/20191119164022_DbInit.Designer.cs index cc393c821..6c9108603 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/AuditLogging/20191119164022_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/AuditLogging/20191119164022_DbInit.Designer.cs @@ -1,10 +1,10 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.AuditLogging diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/AuditLogging/20200419130339_ChangeAuditLogToLong.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/AuditLogging/20200419130339_ChangeAuditLogToLong.Designer.cs index 9e8e57f02..8d9662a7f 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/AuditLogging/20200419130339_ChangeAuditLogToLong.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/AuditLogging/20200419130339_ChangeAuditLogToLong.Designer.cs @@ -1,10 +1,10 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.AuditLogging diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/AuditLogging/AdminAuditLogDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/AuditLogging/AdminAuditLogDbContextModelSnapshot.cs index 55d486dac..8f99a92f6 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/AuditLogging/AdminAuditLogDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/AuditLogging/AdminAuditLogDbContextModelSnapshot.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.AuditLogging diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/DataProtection/20200221180348_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/DataProtection/20200221180348_DbInit.Designer.cs index 4c6c1fd6d..a6f854a66 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/DataProtection/20200221180348_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/DataProtection/20200221180348_DbInit.Designer.cs @@ -1,9 +1,9 @@ // + using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.DataProtection diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/DataProtection/IdentityServerDataProtectionDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/DataProtection/IdentityServerDataProtectionDbContextModelSnapshot.cs index add3fef2a..01c1b89b8 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/DataProtection/IdentityServerDataProtectionDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/DataProtection/IdentityServerDataProtectionDbContextModelSnapshot.cs @@ -1,8 +1,8 @@ // + using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.DataProtection diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Identity/20191119163918_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Identity/20191119163918_DbInit.Designer.cs index 74ed6bbf2..a3a16a7ed 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Identity/20191119163918_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Identity/20191119163918_DbInit.Designer.cs @@ -1,10 +1,10 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.Identity diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Identity/AdminIdentityDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Identity/AdminIdentityDbContextModelSnapshot.cs index c11aaaf86..096b7efba 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Identity/AdminIdentityDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Identity/AdminIdentityDbContextModelSnapshot.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.Identity diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/20191119163952_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/20191119163952_DbInit.Designer.cs index 12fc1bec9..be4444f6b 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/20191119163952_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/20191119163952_DbInit.Designer.cs @@ -1,10 +1,10 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.IdentityServerConfiguration diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/20201030101938_UpdateIdentityServerToVersion4.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/20201030101938_UpdateIdentityServerToVersion4.Designer.cs new file mode 100644 index 000000000..60e78bba9 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/20201030101938_UpdateIdentityServerToVersion4.Designer.cs @@ -0,0 +1,905 @@ +// + +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.IdentityServerConfiguration +{ + [DbContext(typeof(IdentityServerConfigurationDbContext))] + [Migration("20201030101938_UpdateIdentityServerToVersion4")] + partial class UpdateIdentityServerToVersion4 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.9") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("AllowedAccessTokenSigningAlgorithms") + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnType("nvarchar(1000)") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("LastAccessed") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("NonEditable") + .HasColumnType("bit"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("bit"); + + b.Property("Updated") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("ApiResources"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ApiResourceId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceClaims"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ApiResourceId") + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("nvarchar(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(2000)") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceProperties"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ApiResourceId") + .HasColumnType("int"); + + b.Property("Scope") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceScopes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ApiResourceId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnType("nvarchar(1000)") + .HasMaxLength(1000); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(4000)") + .HasMaxLength(4000); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceSecrets"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Description") + .HasColumnType("nvarchar(1000)") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Emphasize") + .HasColumnType("bit"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("ApiScopes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ScopeId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ScopeId"); + + b.ToTable("ApiScopeClaims"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Key") + .IsRequired() + .HasColumnType("nvarchar(250)") + .HasMaxLength(250); + + b.Property("ScopeId") + .HasColumnType("int"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(2000)") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ScopeId"); + + b.ToTable("ApiScopeProperties"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("AbsoluteRefreshTokenLifetime") + .HasColumnType("int"); + + b.Property("AccessTokenLifetime") + .HasColumnType("int"); + + b.Property("AccessTokenType") + .HasColumnType("int"); + + b.Property("AllowAccessTokensViaBrowser") + .HasColumnType("bit"); + + b.Property("AllowOfflineAccess") + .HasColumnType("bit"); + + b.Property("AllowPlainTextPkce") + .HasColumnType("bit"); + + b.Property("AllowRememberConsent") + .HasColumnType("bit"); + + b.Property("AllowedIdentityTokenSigningAlgorithms") + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + + b.Property("AlwaysIncludeUserClaimsInIdToken") + .HasColumnType("bit"); + + b.Property("AlwaysSendClientClaims") + .HasColumnType("bit"); + + b.Property("AuthorizationCodeLifetime") + .HasColumnType("int"); + + b.Property("BackChannelLogoutSessionRequired") + .HasColumnType("bit"); + + b.Property("BackChannelLogoutUri") + .HasColumnType("nvarchar(2000)") + .HasMaxLength(2000); + + b.Property("ClientClaimsPrefix") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientName") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientUri") + .HasColumnType("nvarchar(2000)") + .HasMaxLength(2000); + + b.Property("ConsentLifetime") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnType("nvarchar(1000)") + .HasMaxLength(1000); + + b.Property("DeviceCodeLifetime") + .HasColumnType("int"); + + b.Property("EnableLocalLogin") + .HasColumnType("bit"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("FrontChannelLogoutSessionRequired") + .HasColumnType("bit"); + + b.Property("FrontChannelLogoutUri") + .HasColumnType("nvarchar(2000)") + .HasMaxLength(2000); + + b.Property("IdentityTokenLifetime") + .HasColumnType("int"); + + b.Property("IncludeJwtId") + .HasColumnType("bit"); + + b.Property("LastAccessed") + .HasColumnType("datetime2"); + + b.Property("LogoUri") + .HasColumnType("nvarchar(2000)") + .HasMaxLength(2000); + + b.Property("NonEditable") + .HasColumnType("bit"); + + b.Property("PairWiseSubjectSalt") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ProtocolType") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("RefreshTokenExpiration") + .HasColumnType("int"); + + b.Property("RefreshTokenUsage") + .HasColumnType("int"); + + b.Property("RequireClientSecret") + .HasColumnType("bit"); + + b.Property("RequireConsent") + .HasColumnType("bit"); + + b.Property("RequirePkce") + .HasColumnType("bit"); + + b.Property("RequireRequestObject") + .HasColumnType("bit"); + + b.Property("SlidingRefreshTokenLifetime") + .HasColumnType("int"); + + b.Property("UpdateAccessTokenClaimsOnRefresh") + .HasColumnType("bit"); + + b.Property("Updated") + .HasColumnType("datetime2"); + + b.Property("UserCodeType") + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + + b.Property("UserSsoLifetime") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique(); + + b.ToTable("Clients"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(250)") + .HasMaxLength(250); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientClaims"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("Origin") + .IsRequired() + .HasColumnType("nvarchar(150)") + .HasMaxLength(150); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientCorsOrigins"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("GrantType") + .IsRequired() + .HasColumnType("nvarchar(250)") + .HasMaxLength(250); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientGrantTypes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("Provider") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientIdPRestrictions"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("PostLogoutRedirectUri") + .IsRequired() + .HasColumnType("nvarchar(2000)") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientPostLogoutRedirectUris"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("nvarchar(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(2000)") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientProperties"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("RedirectUri") + .IsRequired() + .HasColumnType("nvarchar(2000)") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientRedirectUris"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("Scope") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientScopes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClientId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnType("nvarchar(2000)") + .HasMaxLength(2000); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(4000)") + .HasMaxLength(4000); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientSecrets"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnType("nvarchar(1000)") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Emphasize") + .HasColumnType("bit"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("NonEditable") + .HasColumnType("bit"); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("bit"); + + b.Property("Updated") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("IdentityResources"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("IdentityResourceId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.ToTable("IdentityResourceClaims"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("IdentityResourceId") + .HasColumnType("int"); + + b.Property("Key") + .IsRequired() + .HasColumnType("nvarchar(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(2000)") + .HasMaxLength(2000); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.ToTable("IdentityResourceProperties"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Properties") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Scopes") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Secrets") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope") + .WithMany("UserClaims") + .HasForeignKey("ScopeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope") + .WithMany("Properties") + .HasForeignKey("ScopeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("Claims") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("AllowedCorsOrigins") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("AllowedGrantTypes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("IdentityProviderRestrictions") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("PostLogoutRedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("Properties") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("RedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("AllowedScopes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client") + .WithMany("ClientSecrets") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource") + .WithMany("UserClaims") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource") + .WithMany("Properties") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/20201030101938_UpdateIdentityServerToVersion4.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/20201030101938_UpdateIdentityServerToVersion4.cs new file mode 100644 index 000000000..f492bbe17 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/20201030101938_UpdateIdentityServerToVersion4.cs @@ -0,0 +1,591 @@ +// Original SQL scripts for database migration come from: https://github.com/RockSolidKnowledge/IdentityServer4.Migration.Scripts/blob/master/MSSQL/ConfigurationDbContext.sql +// Modified by Jan Škoruba + +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.IdentityServerConfiguration +{ + public partial class UpdateIdentityServerToVersion4 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ApiClaims_ApiResources_ApiResourceId", + table: "ApiClaims"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiProperties_ApiResources_ApiResourceId", + table: "ApiProperties"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiScopeClaims_ApiScopes_ApiScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiScopes_ApiResources_ApiResourceId", + table: "ApiScopes"); + + migrationBuilder.DropForeignKey( + name: "FK_IdentityProperties_IdentityResources_IdentityResourceId", + table: "IdentityProperties"); + + migrationBuilder.DropIndex( + name: "IX_ApiScopes_ApiResourceId", + table: "ApiScopes"); + + migrationBuilder.DropIndex( + name: "IX_ApiScopeClaims_ApiScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropPrimaryKey( + name: "PK_IdentityProperties", + table: "IdentityProperties"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ApiProperties", + table: "ApiProperties"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ApiClaims", + table: "ApiClaims"); + + migrationBuilder.RenameTable( + name: "IdentityProperties", + newName: "IdentityResourceProperties"); + + migrationBuilder.RenameTable( + name: "ApiProperties", + newName: "ApiResourceProperties"); + + migrationBuilder.RenameTable( + name: "ApiClaims", + newName: "ApiResourceClaims"); + + migrationBuilder.RenameIndex( + name: "IX_IdentityProperties_IdentityResourceId", + table: "IdentityResourceProperties", + newName: "IX_IdentityResourceProperties_IdentityResourceId"); + + migrationBuilder.RenameIndex( + name: "IX_ApiProperties_ApiResourceId", + table: "ApiResourceProperties", + newName: "IX_ApiResourceProperties_ApiResourceId"); + + migrationBuilder.RenameIndex( + name: "IX_ApiClaims_ApiResourceId", + table: "ApiResourceClaims", + newName: "IX_ApiResourceClaims_ApiResourceId"); + + migrationBuilder.AddColumn( + name: "AllowedIdentityTokenSigningAlgorithms", + table: "Clients", + maxLength: 100, + nullable: true); + + migrationBuilder.AddColumn( + name: "RequireRequestObject", + table: "Clients", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "Enabled", + table: "ApiScopes", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "ScopeId", + table: "ApiScopeClaims", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "AllowedAccessTokenSigningAlgorithms", + table: "ApiResources", + maxLength: 100, + nullable: true); + + migrationBuilder.AddColumn( + name: "ShowInDiscoveryDocument", + table: "ApiResources", + nullable: false, + defaultValue: false); + + migrationBuilder.AddPrimaryKey( + name: "PK_IdentityResourceProperties", + table: "IdentityResourceProperties", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ApiResourceProperties", + table: "ApiResourceProperties", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ApiResourceClaims", + table: "ApiResourceClaims", + column: "Id"); + + migrationBuilder.CreateTable( + name: "ApiResourceScopes", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Scope = table.Column(maxLength: 200, nullable: false), + ApiResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiResourceScopes", x => x.Id); + table.ForeignKey( + name: "FK_ApiResourceScopes_ApiResources_ApiResourceId", + column: x => x.ApiResourceId, + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ApiResourceSecrets", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Description = table.Column(maxLength: 1000, nullable: true), + Value = table.Column(maxLength: 4000, nullable: false), + Expiration = table.Column(nullable: true), + Type = table.Column(maxLength: 250, nullable: false), + Created = table.Column(nullable: false), + ApiResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiResourceSecrets", x => x.Id); + table.ForeignKey( + name: "FK_ApiResourceSecrets_ApiResources_ApiResourceId", + column: x => x.ApiResourceId, + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ApiScopeProperties", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Key = table.Column(maxLength: 250, nullable: false), + Value = table.Column(maxLength: 2000, nullable: false), + ScopeId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiScopeProperties", x => x.Id); + table.ForeignKey( + name: "FK_ApiScopeProperties_ApiScopes_ScopeId", + column: x => x.ScopeId, + principalTable: "ApiScopes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityResourceClaims", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Type = table.Column(maxLength: 200, nullable: false), + IdentityResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityResourceClaims", x => x.Id); + table.ForeignKey( + name: "FK_IdentityResourceClaims_IdentityResources_IdentityResourceId", + column: x => x.IdentityResourceId, + principalTable: "IdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ApiScopeClaims_ScopeId", + table: "ApiScopeClaims", + column: "ScopeId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiResourceScopes_ApiResourceId", + table: "ApiResourceScopes", + column: "ApiResourceId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiResourceSecrets_ApiResourceId", + table: "ApiResourceSecrets", + column: "ApiResourceId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiScopeProperties_ScopeId", + table: "ApiScopeProperties", + column: "ScopeId"); + + migrationBuilder.CreateIndex( + name: "IX_IdentityResourceClaims_IdentityResourceId", + table: "IdentityResourceClaims", + column: "IdentityResourceId"); + + migrationBuilder.AddForeignKey( + name: "FK_ApiResourceClaims_ApiResources_ApiResourceId", + table: "ApiResourceClaims", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ApiResourceProperties_ApiResources_ApiResourceId", + table: "ApiResourceProperties", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + // migrate data + + migrationBuilder.Sql(@"SET IDENTITY_INSERT ApiResourceSecrets ON; +GO + +INSERT INTO ApiResourceSecrets + (Id, [Description], [Value], Expiration, [Type], Created, ApiResourceId) +SELECT + Id, [Description], [Value], Expiration, [Type], Created, ApiResourceId +FROM ApiSecrets +GO + +SET IDENTITY_INSERT ApiResourceSecrets OFF; +GO"); + + migrationBuilder.Sql(@"SET IDENTITY_INSERT IdentityResourceClaims ON; +GO + +INSERT INTO IdentityResourceClaims + (Id, [Type], IdentityResourceId) +SELECT + Id, [Type], IdentityResourceId +FROM IdentityClaims +GO +SET IDENTITY_INSERT IdentityResourceClaims OFF; +GO"); + + migrationBuilder.Sql(@"INSERT INTO ApiResourceScopes + ([Scope], [ApiResourceId]) +SELECT + [Name], [ApiResourceId] +FROM ApiScopes"); + + migrationBuilder.Sql(@"UPDATE ApiScopeClaims SET ScopeId = ApiScopeId"); + + migrationBuilder.Sql(@"UPDATE ApiScopes SET [Enabled] = 1"); + + migrationBuilder.DropTable( + name: "ApiSecrets"); + + migrationBuilder.DropTable( + name: "IdentityClaims"); + + migrationBuilder.DropColumn( + name: "ApiResourceId", + table: "ApiScopes"); + + migrationBuilder.DropColumn( + name: "ApiScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.AddForeignKey( + name: "FK_ApiScopeClaims_ApiScopes_ScopeId", + table: "ApiScopeClaims", + column: "ScopeId", + principalTable: "ApiScopes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_IdentityResourceProperties_IdentityResources_IdentityResourceId", + table: "IdentityResourceProperties", + column: "IdentityResourceId", + principalTable: "IdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ApiResourceClaims_ApiResources_ApiResourceId", + table: "ApiResourceClaims"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiResourceProperties_ApiResources_ApiResourceId", + table: "ApiResourceProperties"); + + migrationBuilder.DropForeignKey( + name: "FK_ApiScopeClaims_ApiScopes_ScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropForeignKey( + name: "FK_IdentityResourceProperties_IdentityResources_IdentityResourceId", + table: "IdentityResourceProperties"); + + migrationBuilder.DropIndex( + name: "IX_ApiScopeClaims_ScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropPrimaryKey( + name: "PK_IdentityResourceProperties", + table: "IdentityResourceProperties"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ApiResourceProperties", + table: "ApiResourceProperties"); + + migrationBuilder.DropPrimaryKey( + name: "PK_ApiResourceClaims", + table: "ApiResourceClaims"); + + migrationBuilder.RenameTable( + name: "IdentityResourceProperties", + newName: "IdentityProperties"); + + migrationBuilder.RenameTable( + name: "ApiResourceProperties", + newName: "ApiProperties"); + + migrationBuilder.RenameTable( + name: "ApiResourceClaims", + newName: "ApiClaims"); + + migrationBuilder.RenameIndex( + name: "IX_IdentityResourceProperties_IdentityResourceId", + table: "IdentityProperties", + newName: "IX_IdentityProperties_IdentityResourceId"); + + migrationBuilder.RenameIndex( + name: "IX_ApiResourceProperties_ApiResourceId", + table: "ApiProperties", + newName: "IX_ApiProperties_ApiResourceId"); + + migrationBuilder.RenameIndex( + name: "IX_ApiResourceClaims_ApiResourceId", + table: "ApiClaims", + newName: "IX_ApiClaims_ApiResourceId"); + + migrationBuilder.AddColumn( + name: "ApiResourceId", + table: "ApiScopes", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "ApiScopeId", + table: "ApiScopeClaims", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddPrimaryKey( + name: "PK_IdentityProperties", + table: "IdentityProperties", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ApiProperties", + table: "ApiProperties", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_ApiClaims", + table: "ApiClaims", + column: "Id"); + + migrationBuilder.CreateTable( + name: "ApiSecrets", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + ApiResourceId = table.Column(type: "int", nullable: false), + Created = table.Column(type: "datetime2", nullable: false), + Description = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + Expiration = table.Column(type: "datetime2", nullable: true), + Type = table.Column(type: "nvarchar(250)", maxLength: 250, nullable: false), + Value = table.Column(type: "nvarchar(4000)", maxLength: 4000, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiSecrets", x => x.Id); + table.ForeignKey( + name: "FK_ApiSecrets_ApiResources_ApiResourceId", + column: x => x.ApiResourceId, + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityClaims", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + IdentityResourceId = table.Column(type: "int", nullable: false), + Type = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityClaims", x => x.Id); + table.ForeignKey( + name: "FK_IdentityClaims_IdentityResources_IdentityResourceId", + column: x => x.IdentityResourceId, + principalTable: "IdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ApiScopes_ApiResourceId", + table: "ApiScopes", + column: "ApiResourceId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiScopeClaims_ApiScopeId", + table: "ApiScopeClaims", + column: "ApiScopeId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiSecrets_ApiResourceId", + table: "ApiSecrets", + column: "ApiResourceId"); + + migrationBuilder.CreateIndex( + name: "IX_IdentityClaims_IdentityResourceId", + table: "IdentityClaims", + column: "IdentityResourceId"); + + migrationBuilder.AddForeignKey( + name: "FK_ApiClaims_ApiResources_ApiResourceId", + table: "ApiClaims", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ApiProperties_ApiResources_ApiResourceId", + table: "ApiProperties", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + // Rollback data back + migrationBuilder.Sql(@"SET IDENTITY_INSERT ApiSecrets ON; +GO + +INSERT INTO ApiSecrets + (Id, [Description], [Value], Expiration, [Type], Created, ApiResourceId) +SELECT + Id, [Description], [Value], Expiration, [Type], Created, ApiResourceId +FROM ApiResourceSecrets +GO + +SET IDENTITY_INSERT ApiSecrets OFF; +GO"); + + migrationBuilder.Sql(@"SET IDENTITY_INSERT IdentityClaims ON; +GO + +INSERT INTO IdentityClaims + (Id, [Type], IdentityResourceId) +SELECT + Id, [Type], IdentityResourceId +FROM IdentityResourceClaims +GO +SET IDENTITY_INSERT IdentityClaims OFF; +GO"); + + migrationBuilder.Sql(@"UPDATE asp +SET ApiResourceId = arc.ApiResourceId +FROM ApiScopes asp + INNER JOIN ApiResourceScopes arc + ON arc.Id = asp.Id +"); + + migrationBuilder.Sql(@"UPDATE ApiScopeClaims SET ApiScopeId = ScopeId"); + + migrationBuilder.DropTable( + name: "ApiResourceScopes"); + + migrationBuilder.DropTable( + name: "ApiResourceSecrets"); + + migrationBuilder.DropTable( + name: "ApiScopeProperties"); + + migrationBuilder.DropTable( + name: "IdentityResourceClaims"); + + migrationBuilder.DropColumn( + name: "AllowedIdentityTokenSigningAlgorithms", + table: "Clients"); + + migrationBuilder.DropColumn( + name: "RequireRequestObject", + table: "Clients"); + + migrationBuilder.DropColumn( + name: "Enabled", + table: "ApiScopes"); + + migrationBuilder.DropColumn( + name: "ScopeId", + table: "ApiScopeClaims"); + + migrationBuilder.DropColumn( + name: "AllowedAccessTokenSigningAlgorithms", + table: "ApiResources"); + + migrationBuilder.DropColumn( + name: "ShowInDiscoveryDocument", + table: "ApiResources"); + + migrationBuilder.AddForeignKey( + name: "FK_ApiScopeClaims_ApiScopes_ApiScopeId", + table: "ApiScopeClaims", + column: "ApiScopeId", + principalTable: "ApiScopes", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ApiScopes_ApiResources_ApiResourceId", + table: "ApiScopes", + column: "ApiResourceId", + principalTable: "ApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_IdentityProperties_IdentityResources_IdentityResourceId", + table: "IdentityProperties", + column: "IdentityResourceId", + principalTable: "IdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/IdentityServerConfigurationDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/IdentityServerConfigurationDbContextModelSnapshot.cs index da2d4654d..ac5832ee6 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/IdentityServerConfigurationDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerConfiguration/IdentityServerConfigurationDbContextModelSnapshot.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.IdentityServerConfiguration @@ -15,7 +15,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.0.0") + .HasAnnotation("ProductVersion", "3.1.9") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -26,6 +26,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("int") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + b.Property("AllowedAccessTokenSigningAlgorithms") + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + b.Property("Created") .HasColumnType("datetime2"); @@ -51,6 +55,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("NonEditable") .HasColumnType("bit"); + b.Property("ShowInDiscoveryDocument") + .HasColumnType("bit"); + b.Property("Updated") .HasColumnType("datetime2"); @@ -81,7 +88,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("ApiResourceId"); - b.ToTable("ApiClaims"); + b.ToTable("ApiResourceClaims"); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b => @@ -108,10 +115,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("ApiResourceId"); - b.ToTable("ApiProperties"); + b.ToTable("ApiResourceProperties"); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -121,6 +128,62 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ApiResourceId") .HasColumnType("int"); + b.Property("Scope") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceScopes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ApiResourceId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnType("nvarchar(1000)") + .HasMaxLength(1000); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(250)") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(4000)") + .HasMaxLength(4000); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceSecrets"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + b.Property("Description") .HasColumnType("nvarchar(1000)") .HasMaxLength(1000); @@ -132,6 +195,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Emphasize") .HasColumnType("bit"); + b.Property("Enabled") + .HasColumnType("bit"); + b.Property("Name") .IsRequired() .HasColumnType("nvarchar(200)") @@ -145,8 +211,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("ApiResourceId"); - b.HasIndex("Name") .IsUnique(); @@ -160,7 +224,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("int") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ApiScopeId") + b.Property("ScopeId") .HasColumnType("int"); b.Property("Type") @@ -170,46 +234,36 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("ApiScopeId"); + b.HasIndex("ScopeId"); b.ToTable("ApiScopeClaims"); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("ApiResourceId") - .HasColumnType("int"); - - b.Property("Created") - .HasColumnType("datetime2"); - - b.Property("Description") - .HasColumnType("nvarchar(1000)") - .HasMaxLength(1000); - - b.Property("Expiration") - .HasColumnType("datetime2"); - - b.Property("Type") + b.Property("Key") .IsRequired() .HasColumnType("nvarchar(250)") .HasMaxLength(250); + b.Property("ScopeId") + .HasColumnType("int"); + b.Property("Value") .IsRequired() - .HasColumnType("nvarchar(4000)") - .HasMaxLength(4000); + .HasColumnType("nvarchar(2000)") + .HasMaxLength(2000); b.HasKey("Id"); - b.HasIndex("ApiResourceId"); + b.HasIndex("ScopeId"); - b.ToTable("ApiSecrets"); + b.ToTable("ApiScopeProperties"); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b => @@ -240,6 +294,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("AllowRememberConsent") .HasColumnType("bit"); + b.Property("AllowedIdentityTokenSigningAlgorithms") + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + b.Property("AlwaysIncludeUserClaimsInIdToken") .HasColumnType("bit"); @@ -339,6 +397,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("RequirePkce") .HasColumnType("bit"); + b.Property("RequireRequestObject") + .HasColumnType("bit"); + b.Property("SlidingRefreshTokenLifetime") .HasColumnType("int"); @@ -586,28 +647,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("ClientSecrets"); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("IdentityResourceId") - .HasColumnType("int"); - - b.Property("Type") - .IsRequired() - .HasColumnType("nvarchar(200)") - .HasMaxLength(200); - - b.HasKey("Id"); - - b.HasIndex("IdentityResourceId"); - - b.ToTable("IdentityClaims"); - }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b => { b.Property("Id") @@ -657,6 +696,28 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("IdentityResources"); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("IdentityResourceId") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.ToTable("IdentityResourceClaims"); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b => { b.Property("Id") @@ -681,7 +742,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("IdentityResourceId"); - b.ToTable("IdentityProperties"); + b.ToTable("IdentityResourceProperties"); }); modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b => @@ -702,7 +763,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b => { b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") .WithMany("Scopes") @@ -711,20 +772,29 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b => + { + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") + .WithMany("Secrets") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b => { - b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "ApiScope") + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope") .WithMany("UserClaims") - .HasForeignKey("ApiScopeId") + .HasForeignKey("ScopeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiSecret", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b => { - b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource") - .WithMany("Secrets") - .HasForeignKey("ApiResourceId") + b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope") + .WithMany("Properties") + .HasForeignKey("ScopeId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); @@ -810,7 +880,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); - modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityClaim", b => + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b => { b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource") .WithMany("UserClaims") diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/20191119164007_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/20191119164007_DbInit.Designer.cs index 3e8082727..e1f7d5bf9 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/20191119164007_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/20191119164007_DbInit.Designer.cs @@ -1,10 +1,10 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.IdentityServerGrants diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/20201030101834_UpdateIdentityServerToVersion4.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/20201030101834_UpdateIdentityServerToVersion4.Designer.cs new file mode 100644 index 000000000..b99f2da08 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/20201030101834_UpdateIdentityServerToVersion4.Designer.cs @@ -0,0 +1,129 @@ +// + +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.IdentityServerGrants +{ + [DbContext(typeof(IdentityServerPersistedGrantDbContext))] + [Migration("20201030101834_UpdateIdentityServerToVersion4")] + partial class UpdateIdentityServerToVersion4 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.9") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(50000); + + b.Property("Description") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("DeviceCode") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + + b.Property("SubjectId") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Key") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ConsumedTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(50000); + + b.Property("Description") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + + b.Property("SubjectId") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(50)") + .HasMaxLength(50); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.HasIndex("SubjectId", "SessionId", "Type"); + + b.ToTable("PersistedGrants"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/20201030101834_UpdateIdentityServerToVersion4.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/20201030101834_UpdateIdentityServerToVersion4.cs new file mode 100644 index 000000000..43dcd33ce --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/20201030101834_UpdateIdentityServerToVersion4.cs @@ -0,0 +1,72 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.IdentityServerGrants +{ + public partial class UpdateIdentityServerToVersion4 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ConsumedTime", + table: "PersistedGrants", + nullable: true); + + migrationBuilder.AddColumn( + name: "Description", + table: "PersistedGrants", + maxLength: 200, + nullable: true); + + migrationBuilder.AddColumn( + name: "SessionId", + table: "PersistedGrants", + maxLength: 100, + nullable: true); + + migrationBuilder.AddColumn( + name: "Description", + table: "DeviceCodes", + maxLength: 200, + nullable: true); + + migrationBuilder.AddColumn( + name: "SessionId", + table: "DeviceCodes", + maxLength: 100, + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_PersistedGrants_SubjectId_SessionId_Type", + table: "PersistedGrants", + columns: new[] { "SubjectId", "SessionId", "Type" }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_PersistedGrants_SubjectId_SessionId_Type", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "ConsumedTime", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "Description", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "SessionId", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "Description", + table: "DeviceCodes"); + + migrationBuilder.DropColumn( + name: "SessionId", + table: "DeviceCodes"); + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/IdentityServerPersistedGrantDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/IdentityServerPersistedGrantDbContextModelSnapshot.cs index 5e089b1f6..74ad787a5 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/IdentityServerPersistedGrantDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/IdentityServerGrants/IdentityServerPersistedGrantDbContextModelSnapshot.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.IdentityServerGrants @@ -15,7 +15,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.0.0") + .HasAnnotation("ProductVersion", "3.1.9") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -38,6 +38,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("nvarchar(max)") .HasMaxLength(50000); + b.Property("Description") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + b.Property("DeviceCode") .IsRequired() .HasColumnType("nvarchar(200)") @@ -47,6 +51,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired() .HasColumnType("datetime2"); + b.Property("SessionId") + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + b.Property("SubjectId") .HasColumnType("nvarchar(200)") .HasMaxLength(200); @@ -72,6 +80,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("nvarchar(200)") .HasMaxLength(200); + b.Property("ConsumedTime") + .HasColumnType("datetime2"); + b.Property("CreationTime") .HasColumnType("datetime2"); @@ -80,9 +91,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("nvarchar(max)") .HasMaxLength(50000); + b.Property("Description") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + b.Property("Expiration") .HasColumnType("datetime2"); + b.Property("SessionId") + .HasColumnType("nvarchar(100)") + .HasMaxLength(100); + b.Property("SubjectId") .HasColumnType("nvarchar(200)") .HasMaxLength(200); @@ -98,6 +117,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("SubjectId", "ClientId", "Type"); + b.HasIndex("SubjectId", "SessionId", "Type"); + b.ToTable("PersistedGrants"); }); #pragma warning restore 612, 618 diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Logging/20191119163936_DbInit.Designer.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Logging/20191119163936_DbInit.Designer.cs index 0445557ec..4ca4b2a1c 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Logging/20191119163936_DbInit.Designer.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Logging/20191119163936_DbInit.Designer.cs @@ -1,10 +1,10 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.Logging diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Logging/AdminLogDbContextModelSnapshot.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Logging/AdminLogDbContextModelSnapshot.cs index 776db4c9d..63e50c8b7 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Logging/AdminLogDbContextModelSnapshot.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Migrations/Logging/AdminLogDbContextModelSnapshot.cs @@ -1,9 +1,9 @@ // + using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts; namespace Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.Migrations.Logging diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.csproj b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.csproj index e9a67b815..769834f8c 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.csproj +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer/Skoruba.IdentityServer4.Admin.EntityFramework.SqlServer.csproj @@ -1,8 +1,8 @@  - netcoreapp3.1 - 1.0.0 + net5.0 + 2.0.0 Jan Škoruba IdentityServer4 Admin OpenIDConnect OAuth2 Identity Entity Framework layer for the administration of the IdentityServer4 and Asp.Net Core Identity with SqlServer support @@ -12,8 +12,8 @@ - - + + @@ -27,3 +27,11 @@ + + + + + + + + diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Constants/ClientConsts.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Constants/ClientConsts.cs index c78f8cd23..db8b5a26f 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Constants/ClientConsts.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Constants/ClientConsts.cs @@ -46,19 +46,37 @@ public static List GetStandardClaims() public static List GetGrantTypes() { var allowedGrantypes = new List - { - "implicit", - "client_credentials", - "authorization_code", - "hybrid", - "password", - "urn:ietf:params:oauth:grant-type:device_code", - "delegation" - }; + { + "implicit", + "client_credentials", + "authorization_code", + "hybrid", + "password", + "urn:ietf:params:oauth:grant-type:device_code", + "delegation" + }; return allowedGrantypes; } + public static List SigningAlgorithms() + { + var signingAlgorithms = new List + { + "RS256", + "RS384", + "RS512", + "PS256", + "PS384", + "PS512", + "ES256", + "ES384", + "ES512" + }; + + return signingAlgorithms; + } + public static List GetProtocolTypes() { var protocolTypes = new List { new SelectItem("oidc", "OpenID Connect") }; diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Interfaces/IAdminConfigurationDbContext.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Interfaces/IAdminConfigurationDbContext.cs index dd30a14f7..8151886b3 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Interfaces/IAdminConfigurationDbContext.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Interfaces/IAdminConfigurationDbContext.cs @@ -6,13 +6,11 @@ namespace Skoruba.IdentityServer4.Admin.EntityFramework.Interfaces { public interface IAdminConfigurationDbContext : IConfigurationDbContext { - DbSet ApiSecrets { get; set; } - - DbSet ApiScopes { get; set; } + DbSet ApiSecrets { get; set; } DbSet ApiScopeClaims { get; set; } - DbSet IdentityClaims { get; set; } + DbSet IdentityClaims { get; set; } DbSet ApiResourceClaims { get; set; } @@ -24,8 +22,6 @@ public interface IAdminConfigurationDbContext : IConfigurationDbContext DbSet ClientPostLogoutRedirectUris { get; set; } - DbSet ClientCorsOrigins { get; set; } - DbSet ClientIdPRestrictions { get; set; } DbSet ClientRedirectUris { get; set; } @@ -37,5 +33,9 @@ public interface IAdminConfigurationDbContext : IConfigurationDbContext DbSet IdentityResourceProperties { get; set; } DbSet ApiResourceProperties { get; set; } + + DbSet ApiScopeProperties { get; set; } + + DbSet ApiResourceScopes { get; set; } } } diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/ApiResourceRepository.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/ApiResourceRepository.cs index 7ff24ab48..6d090cc1c 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/ApiResourceRepository.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/ApiResourceRepository.cs @@ -43,6 +43,7 @@ public virtual Task GetApiResourceAsync(int apiResourceId) { return DbContext.ApiResources .Include(x => x.UserClaims) + .Include(x => x.Scopes) .Where(x => x.Id == apiResourceId) .AsNoTracking() .SingleOrDefaultAsync(); @@ -109,20 +110,6 @@ public virtual async Task CanInsertApiResourcePropertyAsync(ApiResourcePro return existsWithSameName == null; } - public virtual async Task CanInsertApiScopeAsync(ApiScope apiScope) - { - if (apiScope.Id == 0) - { - var existsWithSameName = await DbContext.ApiScopes.Where(x => x.Name == apiScope.Name).SingleOrDefaultAsync(); - return existsWithSameName == null; - } - else - { - var existsWithSameName = await DbContext.ApiScopes.Where(x => x.Name == apiScope.Name && x.Id != apiScope.Id).SingleOrDefaultAsync(); - return existsWithSameName == null; - } - } - /// /// Add new api resource /// @@ -139,15 +126,23 @@ public virtual async Task AddApiResourceAsync(ApiResource apiResource) private async Task RemoveApiResourceClaimsAsync(ApiResource identityResource) { - //Remove old identity claims + //Remove old api resource claims var apiResourceClaims = await DbContext.ApiResourceClaims.Where(x => x.ApiResource.Id == identityResource.Id).ToListAsync(); DbContext.ApiResourceClaims.RemoveRange(apiResourceClaims); } + private async Task RemoveApiResourceScopesAsync(ApiResource identityResource) + { + //Remove old api resource scopes + var apiResourceScopes = await DbContext.ApiResourceScopes.Where(x => x.ApiResource.Id == identityResource.Id).ToListAsync(); + DbContext.ApiResourceScopes.RemoveRange(apiResourceScopes); + } + public virtual async Task UpdateApiResourceAsync(ApiResource apiResource) { //Remove old relations await RemoveApiResourceClaimsAsync(apiResource); + await RemoveApiResourceScopesAsync(apiResource); //Update with new data DbContext.ApiResources.Update(apiResource); @@ -164,81 +159,10 @@ public virtual async Task DeleteApiResourceAsync(ApiResource apiResource) return await AutoSaveChangesAsync(); } - public virtual async Task> GetApiScopesAsync(int apiResourceId, int page = 1, int pageSize = 10) - { - var pagedList = new PagedList(); - - var apiScopes = await DbContext.ApiScopes - .Include(x => x.ApiResource) - .Where(x => x.ApiResource.Id == apiResourceId).PageBy(x => x.Name, page, pageSize).ToListAsync(); - - pagedList.Data.AddRange(apiScopes); - pagedList.TotalCount = await DbContext.ApiScopes.Where(x => x.ApiResource.Id == apiResourceId).CountAsync(); - pagedList.PageSize = pageSize; - - return pagedList; - } - - public virtual Task GetApiScopeAsync(int apiResourceId, int apiScopeId) - { - return DbContext.ApiScopes - .Include(x => x.UserClaims) - .Include(x => x.ApiResource) - .Where(x => x.Id == apiScopeId && x.ApiResource.Id == apiResourceId) - .AsNoTracking() - .SingleOrDefaultAsync(); - } - - /// - /// Add new api scope - /// - /// - /// - /// This method return new api scope id - public virtual async Task AddApiScopeAsync(int apiResourceId, ApiScope apiScope) - { - var apiResource = await DbContext.ApiResources.Where(x => x.Id == apiResourceId).SingleOrDefaultAsync(); - apiScope.ApiResource = apiResource; - - DbContext.ApiScopes.Add(apiScope); - - await AutoSaveChangesAsync(); - - return apiScope.Id; - } - - private async Task RemoveApiScopeClaimsAsync(ApiScope apiScope) - { - //Remove old api scope claims - var apiScopeClaims = await DbContext.ApiScopeClaims.Where(x => x.ApiScope.Id == apiScope.Id).ToListAsync(); - DbContext.ApiScopeClaims.RemoveRange(apiScopeClaims); - } - - public virtual async Task UpdateApiScopeAsync(int apiResourceId, ApiScope apiScope) - { - var apiResource = await DbContext.ApiResources.Where(x => x.Id == apiResourceId).SingleOrDefaultAsync(); - apiScope.ApiResource = apiResource; - - //Remove old relations - await RemoveApiScopeClaimsAsync(apiScope); - - //Update with new data - DbContext.ApiScopes.Update(apiScope); - - return await AutoSaveChangesAsync(); - } - - public virtual async Task DeleteApiScopeAsync(ApiScope apiScope) - { - var apiScopeToDelete = await DbContext.ApiScopes.Where(x => x.Id == apiScope.Id).SingleOrDefaultAsync(); - DbContext.ApiScopes.Remove(apiScopeToDelete); - - return await AutoSaveChangesAsync(); - } - - public virtual async Task> GetApiSecretsAsync(int apiResourceId, int page = 1, int pageSize = 10) + + public virtual async Task> GetApiSecretsAsync(int apiResourceId, int page = 1, int pageSize = 10) { - var pagedList = new PagedList(); + var pagedList = new PagedList(); var apiSecrets = await DbContext.ApiSecrets.Where(x => x.ApiResource.Id == apiResourceId).PageBy(x => x.Id, page, pageSize).ToListAsync(); pagedList.Data.AddRange(apiSecrets); @@ -248,7 +172,7 @@ public virtual async Task> GetApiSecretsAsync(int apiResour return pagedList; } - public virtual Task GetApiSecretAsync(int apiSecretId) + public virtual Task GetApiSecretAsync(int apiSecretId) { return DbContext.ApiSecrets .Include(x => x.ApiResource) @@ -257,7 +181,7 @@ public virtual Task GetApiSecretAsync(int apiSecretId) .SingleOrDefaultAsync(); } - public virtual async Task AddApiSecretAsync(int apiResourceId, ApiSecret apiSecret) + public virtual async Task AddApiSecretAsync(int apiResourceId, ApiResourceSecret apiSecret) { apiSecret.ApiResource = await DbContext.ApiResources.Where(x => x.Id == apiResourceId).SingleOrDefaultAsync(); await DbContext.ApiSecrets.AddAsync(apiSecret); @@ -265,7 +189,7 @@ public virtual async Task AddApiSecretAsync(int apiResourceId, ApiSecret ap return await AutoSaveChangesAsync(); } - public virtual async Task DeleteApiSecretAsync(ApiSecret apiSecret) + public virtual async Task DeleteApiSecretAsync(ApiResourceSecret apiSecret) { var apiSecretToDelete = await DbContext.ApiSecrets.Where(x => x.Id == apiSecret.Id).SingleOrDefaultAsync(); DbContext.ApiSecrets.Remove(apiSecretToDelete); diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/ApiScopeRepository.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/ApiScopeRepository.cs new file mode 100644 index 000000000..1730594f4 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/ApiScopeRepository.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using IdentityServer4.EntityFramework.Entities; +using Microsoft.EntityFrameworkCore; +using Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.Common; +using Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.Enums; +using Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.Extensions; +using Skoruba.IdentityServer4.Admin.EntityFramework.Interfaces; +using Skoruba.IdentityServer4.Admin.EntityFramework.Repositories.Interfaces; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Repositories +{ + public class ApiScopeRepository : IApiScopeRepository + where TDbContext : DbContext, IAdminConfigurationDbContext + { + protected readonly TDbContext DbContext; + + public bool AutoSaveChanges { get; set; } = true; + + public ApiScopeRepository(TDbContext dbContext) + { + DbContext = dbContext; + } + + public virtual Task GetApiScopePropertyAsync(int apiScopePropertyId) + { + return DbContext.ApiScopeProperties + .Include(x => x.Scope) + .Where(x => x.Id == apiScopePropertyId) + .SingleOrDefaultAsync(); + } + + public virtual async Task AddApiScopePropertyAsync(int apiScopeId, ApiScopeProperty apiScopeProperty) + { + var apiScope = await DbContext.ApiScopes.Where(x => x.Id == apiScopeId).SingleOrDefaultAsync(); + + apiScopeProperty.Scope = apiScope; + await DbContext.ApiScopeProperties.AddAsync(apiScopeProperty); + + return await AutoSaveChangesAsync(); + } + + public virtual async Task DeleteApiScopePropertyAsync(ApiScopeProperty apiScopeProperty) + { + var propertyToDelete = await DbContext.ApiScopeProperties.Where(x => x.Id == apiScopeProperty.Id).SingleOrDefaultAsync(); + + DbContext.ApiScopeProperties.Remove(propertyToDelete); + + return await AutoSaveChangesAsync(); + } + + public virtual async Task CanInsertApiScopePropertyAsync(ApiScopeProperty apiScopeProperty) + { + var existsWithSameName = await DbContext.ApiScopeProperties.Where(x => x.Key == apiScopeProperty.Key + && x.Scope.Id == apiScopeProperty.Scope.Id).SingleOrDefaultAsync(); + return existsWithSameName == null; + } + + + public virtual async Task GetApiScopeNameAsync(int apiScopeId) + { + var apiScopeName = await DbContext.ApiScopes.Where(x => x.Id == apiScopeId).Select(x => x.Name).SingleOrDefaultAsync(); + + return apiScopeName; + } + + public virtual async Task> GetApiScopePropertiesAsync(int apiScopeId, int page = 1, int pageSize = 10) + { + var pagedList = new PagedList(); + + var apiScopeProperties = DbContext.ApiScopeProperties.Where(x => x.Scope.Id == apiScopeId); + + var properties = await apiScopeProperties.PageBy(x => x.Id, page, pageSize) + .ToListAsync(); + + pagedList.Data.AddRange(properties); + pagedList.TotalCount = await apiScopeProperties.CountAsync(); + pagedList.PageSize = pageSize; + + return pagedList; + } + + public virtual async Task CanInsertApiScopeAsync(ApiScope apiScope) + { + if (apiScope.Id == 0) + { + var existsWithSameName = await DbContext.ApiScopes.Where(x => x.Name == apiScope.Name).SingleOrDefaultAsync(); + return existsWithSameName == null; + } + else + { + var existsWithSameName = await DbContext.ApiScopes.Where(x => x.Name == apiScope.Name && x.Id != apiScope.Id).SingleOrDefaultAsync(); + return existsWithSameName == null; + } + } + + public virtual async Task> GetApiScopesAsync(string search, int page = 1, int pageSize = 10) + { + var pagedList = new PagedList(); + Expression> searchCondition = x => x.Name.Contains(search); + + var filteredApiScopes = DbContext.ApiScopes + .WhereIf(!string.IsNullOrEmpty(search), searchCondition); + + var apiScopes = await filteredApiScopes + .PageBy(x => x.Name, page, pageSize).ToListAsync(); + + pagedList.Data.AddRange(apiScopes); + pagedList.TotalCount = await filteredApiScopes.CountAsync(); + pagedList.PageSize = pageSize; + + return pagedList; + } + + public virtual async Task> GetApiScopesNameAsync(string scope, int limit = 0) + { + var apiScopes = await DbContext.ApiScopes + .WhereIf(!string.IsNullOrEmpty(scope), x => x.Name.Contains(scope)) + .TakeIf(x => x.Id, limit > 0, limit) + .Select(x => x.Name).ToListAsync(); + + return apiScopes; + } + + public virtual Task GetApiScopeAsync(int apiScopeId) + { + return DbContext.ApiScopes + .Include(x => x.UserClaims) + .Where(x => x.Id == apiScopeId) + .AsNoTracking() + .SingleOrDefaultAsync(); + } + + /// + /// Add new api scope + /// + /// + /// This method return new api scope id + public virtual async Task AddApiScopeAsync(ApiScope apiScope) + { + await DbContext.ApiScopes.AddAsync(apiScope); + + await AutoSaveChangesAsync(); + + return apiScope.Id; + } + + private async Task RemoveApiScopeClaimsAsync(ApiScope apiScope) + { + //Remove old api scope claims + var apiScopeClaims = await DbContext.ApiScopeClaims.Where(x => x.Scope.Id == apiScope.Id).ToListAsync(); + DbContext.ApiScopeClaims.RemoveRange(apiScopeClaims); + } + + public virtual async Task UpdateApiScopeAsync(ApiScope apiScope) + { + //Remove old relations + await RemoveApiScopeClaimsAsync(apiScope); + + //Update with new data + DbContext.ApiScopes.Update(apiScope); + + return await AutoSaveChangesAsync(); + } + + public virtual async Task DeleteApiScopeAsync(ApiScope apiScope) + { + var apiScopeToDelete = await DbContext.ApiScopes.Where(x => x.Id == apiScope.Id).SingleOrDefaultAsync(); + DbContext.ApiScopes.Remove(apiScopeToDelete); + + return await AutoSaveChangesAsync(); + } + + protected virtual async Task AutoSaveChangesAsync() + { + return AutoSaveChanges ? await DbContext.SaveChangesAsync() : (int)SavedStatus.WillBeSavedExplicitly; + } + + public virtual async Task SaveAllChangesAsync() + { + return await DbContext.SaveChangesAsync(); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/ClientRepository.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/ClientRepository.cs index 4c23b9d69..7fc060587 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/ClientRepository.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/ClientRepository.cs @@ -14,6 +14,7 @@ using Skoruba.IdentityServer4.Admin.EntityFramework.Interfaces; using Skoruba.IdentityServer4.Admin.EntityFramework.Repositories.Interfaces; using Client = IdentityServer4.EntityFramework.Entities.Client; +using ClientClaim = IdentityServer4.EntityFramework.Entities.ClientClaim; namespace Skoruba.IdentityServer4.Admin.EntityFramework.Repositories { @@ -85,6 +86,17 @@ public virtual List GetGrantTypes(string grant, int limit = 0) return filteredGrants; } + public virtual List GetSigningAlgorithms(string algorithm, int limit = 0) + { + var signingAlgorithms = ClientConsts.SigningAlgorithms() + .WhereIf(!string.IsNullOrWhiteSpace(algorithm), x => x.Contains(algorithm)) + .TakeIf(x => x, limit > 0, limit) + .OrderBy(x => x) + .ToList(); + + return signingAlgorithms; + } + public virtual List GetProtocolTypes() { return ClientConsts.GetProtocolTypes(); diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/Interfaces/IApiResourceRepository.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/Interfaces/IApiResourceRepository.cs index b1adc6b2f..fc6281f90 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/Interfaces/IApiResourceRepository.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/Interfaces/IApiResourceRepository.cs @@ -29,25 +29,13 @@ public interface IApiResourceRepository Task CanInsertApiResourceAsync(ApiResource apiResource); - Task> GetApiScopesAsync(int apiResourceId, int page = 1, int pageSize = 10); + Task> GetApiSecretsAsync(int apiResourceId, int page = 1, int pageSize = 10); - Task GetApiScopeAsync(int apiResourceId, int apiScopeId); + Task AddApiSecretAsync(int apiResourceId, ApiResourceSecret apiSecret); - Task AddApiScopeAsync(int apiResourceId, ApiScope apiScope); + Task GetApiSecretAsync(int apiSecretId); - Task UpdateApiScopeAsync(int apiResourceId, ApiScope apiScope); - - Task DeleteApiScopeAsync(ApiScope apiScope); - - Task> GetApiSecretsAsync(int apiResourceId, int page = 1, int pageSize = 10); - - Task AddApiSecretAsync(int apiResourceId, ApiSecret apiSecret); - - Task GetApiSecretAsync(int apiSecretId); - - Task DeleteApiSecretAsync(ApiSecret apiSecret); - - Task CanInsertApiScopeAsync(ApiScope apiScope); + Task DeleteApiSecretAsync(ApiResourceSecret apiSecret); Task SaveAllChangesAsync(); diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/Interfaces/IApiScopeRepository.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/Interfaces/IApiScopeRepository.cs new file mode 100644 index 000000000..9c46dc9e2 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/Interfaces/IApiScopeRepository.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using IdentityServer4.EntityFramework.Entities; +using Skoruba.IdentityServer4.Admin.EntityFramework.Extensions.Common; + +namespace Skoruba.IdentityServer4.Admin.EntityFramework.Repositories.Interfaces +{ + public interface IApiScopeRepository + { + Task> GetApiScopesAsync(string search, int page = 1, int pageSize = 10); + + Task GetApiScopeAsync(int apiScopeId); + + Task AddApiScopeAsync(ApiScope apiScope); + + Task UpdateApiScopeAsync(ApiScope apiScope); + + Task DeleteApiScopeAsync(ApiScope apiScope); + + Task CanInsertApiScopeAsync(ApiScope apiScope); + + Task> GetApiScopesNameAsync(string scope, int limit = 0); + + Task> GetApiScopePropertiesAsync(int apiScopeId, int page = 1, int pageSize = 10); + + Task GetApiScopePropertyAsync(int apiScopePropertyId); + + Task AddApiScopePropertyAsync(int apiScopeId, ApiScopeProperty apiScopeProperty); + + Task CanInsertApiScopePropertyAsync(ApiScopeProperty apiScopeProperty); + + Task DeleteApiScopePropertyAsync(ApiScopeProperty apiScopeProperty); + + Task GetApiScopeNameAsync(int apiScopeId); + + Task SaveAllChangesAsync(); + + bool AutoSaveChanges { get; set; } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/Interfaces/IClientRepository.cs b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/Interfaces/IClientRepository.cs index a96c95546..677d62c8d 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/Interfaces/IClientRepository.cs +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Repositories/Interfaces/IClientRepository.cs @@ -73,7 +73,9 @@ Task CloneClientAsync(Client client, Task DeleteClientPropertyAsync(ClientProperty clientProperty); - Task SaveAllChangesAsync(); + List GetSigningAlgorithms(string algorithm, int limit = 0); + + Task SaveAllChangesAsync(); bool AutoSaveChanges { get; set; } } diff --git a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Skoruba.IdentityServer4.Admin.EntityFramework.csproj b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Skoruba.IdentityServer4.Admin.EntityFramework.csproj index 7125cddd9..bb8bf88fe 100644 --- a/src/Skoruba.IdentityServer4.Admin.EntityFramework/Skoruba.IdentityServer4.Admin.EntityFramework.csproj +++ b/src/Skoruba.IdentityServer4.Admin.EntityFramework/Skoruba.IdentityServer4.Admin.EntityFramework.csproj @@ -1,8 +1,8 @@  - netcoreapp3.1 - 1.0.0 + net5.0 + 2.0.0 Jan Škoruba IdentityServer4 Admin OpenIDConnect OAuth2 Identity Entity Framework layer for the administration of the IdentityServer4 @@ -12,7 +12,7 @@ - + @@ -24,3 +24,11 @@ + + + + + + + + diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/AccountController.cs b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/AccountController.cs new file mode 100644 index 000000000..7edd81b24 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/AccountController.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants; +using System.Collections.Generic; + +namespace Skoruba.IdentityServer4.Admin.UI.Areas.AdminUI.Controllers +{ + [Authorize] + [Area(CommonConsts.AdminUIArea)] + public class AccountController : BaseController + { + public AccountController(ILogger logger) : base(logger) + { + } + + public IActionResult AccessDenied() + { + return View(); + } + + public IActionResult Logout() + { + return new SignOutResult(new List { AuthenticationConsts.SignInScheme, AuthenticationConsts.OidcAuthenticationScheme }); + } + } +} diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/BaseController.cs b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/BaseController.cs new file mode 100644 index 000000000..b3e86b381 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/BaseController.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants; +using Skoruba.IdentityServer4.Admin.UI.Helpers; + +namespace Skoruba.IdentityServer4.Admin.UI.Areas.AdminUI.Controllers +{ + [Area(CommonConsts.AdminUIArea)] + public class BaseController : Controller + { + private readonly ILogger _logger; + + public BaseController(ILogger logger) + { + _logger = logger; + } + + protected void SuccessNotification(string message, string title = "") + { + CreateNotification(NotificationHelpers.AlertType.Success, message, title); + } + + protected void CreateNotification(NotificationHelpers.AlertType type, string message, string title = "") + { + var toast = new NotificationHelpers.Alert + { + Type = type, + Message = message, + Title = title + }; + + var alerts = new List(); + + if (TempData.ContainsKey(NotificationHelpers.NotificationKey)) + { + alerts = JsonConvert.DeserializeObject>(TempData[NotificationHelpers.NotificationKey].ToString()); + TempData.Remove(NotificationHelpers.NotificationKey); + } + + alerts.Add(toast); + + var settings = new JsonSerializerSettings + { + TypeNameHandling = TypeNameHandling.All + }; + + var alertJson = JsonConvert.SerializeObject(alerts, settings); + + TempData.Add(NotificationHelpers.NotificationKey, alertJson); + } + + protected void GenerateNotifications() + { + if (!TempData.ContainsKey(NotificationHelpers.NotificationKey)) return; + ViewBag.Notifications = TempData[NotificationHelpers.NotificationKey]; + TempData.Remove(NotificationHelpers.NotificationKey); + } + + public override void OnActionExecuting(ActionExecutingContext context) + { + GenerateNotifications(); + + base.OnActionExecuting(context); + } + + public override ViewResult View(object model) + { + GenerateNotifications(); + + return base.View(model); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/ConfigurationController.cs b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/ConfigurationController.cs new file mode 100644 index 000000000..9d1908567 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/ConfigurationController.cs @@ -0,0 +1,731 @@ +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Logging; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Helpers; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Services.Interfaces; +using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants; +using Skoruba.IdentityServer4.Admin.UI.ExceptionHandling; +using Skoruba.IdentityServer4.Admin.UI.Helpers; + +namespace Skoruba.IdentityServer4.Admin.UI.Areas.AdminUI.Controllers +{ + [Authorize(Policy = AuthorizationConsts.AdministrationPolicy)] + [TypeFilter(typeof(ControllerExceptionFilterAttribute))] + [Area(CommonConsts.AdminUIArea)] + public class ConfigurationController : BaseController + { + private readonly IIdentityResourceService _identityResourceService; + private readonly IApiResourceService _apiResourceService; + private readonly IClientService _clientService; + private readonly IStringLocalizer _localizer; + private readonly IApiScopeService _apiScopeService; + + public ConfigurationController(IIdentityResourceService identityResourceService, + IApiResourceService apiResourceService, + IClientService clientService, + IStringLocalizer localizer, + ILogger logger, + IApiScopeService apiScopeService) + : base(logger) + { + _identityResourceService = identityResourceService; + _apiResourceService = apiResourceService; + _clientService = clientService; + _localizer = localizer; + _apiScopeService = apiScopeService; + } + + public async Task Client(string id) + { + if (id.IsNotPresentedValidNumber()) + { + return NotFound(); + } + + if (id == default) + { + var clientDto = _clientService.BuildClientViewModel(); + return View(clientDto); + } + + int.TryParse(id, out var clientId); + var client = await _clientService.GetClientAsync(clientId); + client = _clientService.BuildClientViewModel(client); + + return View(client); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Client(ClientDto client) + { + client = _clientService.BuildClientViewModel(client); + + if (!ModelState.IsValid) + { + return View(client); + } + + //Add new client + if (client.Id == 0) + { + var clientId = await _clientService.AddClientAsync(client); + SuccessNotification(string.Format(_localizer["SuccessAddClient"], client.ClientId), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(Client), new { Id = clientId }); + } + + //Update client + await _clientService.UpdateClientAsync(client); + SuccessNotification(string.Format(_localizer["SuccessUpdateClient"], client.ClientId), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(Client), new { client.Id }); + } + + [HttpGet] + public async Task ClientClone(int id) + { + if (id == 0) return NotFound(); + + var clientDto = await _clientService.GetClientAsync(id); + var client = _clientService.BuildClientCloneViewModel(id, clientDto); + + return View(client); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ClientClone(ClientCloneDto client) + { + if (!ModelState.IsValid) + { + return View(client); + } + + var newClientId = await _clientService.CloneClientAsync(client); + SuccessNotification(string.Format(_localizer["SuccessClientClone"], client.ClientId), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(Client), new { Id = newClientId }); + } + + [HttpGet] + public async Task ClientDelete(int id) + { + if (id == 0) return NotFound(); + + var client = await _clientService.GetClientAsync(id); + + return View(client); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ClientDelete(ClientDto client) + { + await _clientService.RemoveClientAsync(client); + + SuccessNotification(_localizer["SuccessClientDelete"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(Clients)); + } + + [HttpGet] + public async Task ClientClaims(int id, int? page) + { + if (id == 0) return NotFound(); + + var claims = await _clientService.GetClientClaimsAsync(id, page ?? 1); + + return View(claims); + } + + [HttpGet] + public async Task ClientProperties(int id, int? page) + { + if (id == 0) return NotFound(); + + var properties = await _clientService.GetClientPropertiesAsync(id, page ?? 1); + + return View(properties); + } + + [HttpGet] + public async Task ApiResourceProperties(int id, int? page) + { + if (id == 0) return NotFound(); + + var properties = await _apiResourceService.GetApiResourcePropertiesAsync(id, page ?? 1); + + return View(properties); + } + + [HttpGet] + public async Task ApiScopeProperties(int id, int? page) + { + if (id == 0) return NotFound(); + + var properties = await _apiScopeService.GetApiScopePropertiesAsync(id, page ?? 1); + + return View(properties); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ApiScopeProperties(ApiScopePropertiesDto apiScopeProperty) + { + if (!ModelState.IsValid) + { + return View(apiScopeProperty); + } + + await _apiScopeService.AddApiScopePropertyAsync(apiScopeProperty); + SuccessNotification(string.Format(_localizer["SuccessAddApiScopeProperty"], apiScopeProperty.Key, apiScopeProperty.ApiScopeName), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ApiScopeProperties), new { Id = apiScopeProperty.ApiScopeId }); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ApiResourceProperties(ApiResourcePropertiesDto apiResourceProperty) + { + if (!ModelState.IsValid) + { + return View(apiResourceProperty); + } + + await _apiResourceService.AddApiResourcePropertyAsync(apiResourceProperty); + SuccessNotification(string.Format(_localizer["SuccessAddApiResourceProperty"], apiResourceProperty.Key, apiResourceProperty.ApiResourceName), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ApiResourceProperties), new { Id = apiResourceProperty.ApiResourceId }); + } + + [HttpGet] + public async Task IdentityResourceProperties(int id, int? page) + { + if (id == 0) return NotFound(); + + var properties = await _identityResourceService.GetIdentityResourcePropertiesAsync(id, page ?? 1); + + return View(properties); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task IdentityResourceProperties(IdentityResourcePropertiesDto identityResourceProperty) + { + if (!ModelState.IsValid) + { + return View(identityResourceProperty); + } + + await _identityResourceService.AddIdentityResourcePropertyAsync(identityResourceProperty); + SuccessNotification(string.Format(_localizer["SuccessAddIdentityResourceProperty"], identityResourceProperty.Value, identityResourceProperty.IdentityResourceName), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(IdentityResourceProperties), new { Id = identityResourceProperty.IdentityResourceId }); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ClientProperties(ClientPropertiesDto clientProperty) + { + if (!ModelState.IsValid) + { + return View(clientProperty); + } + + await _clientService.AddClientPropertyAsync(clientProperty); + SuccessNotification(string.Format(_localizer["SuccessAddClientProperty"], clientProperty.ClientId, clientProperty.ClientName), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ClientProperties), new { Id = clientProperty.ClientId }); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ClientClaims(ClientClaimsDto clientClaim) + { + if (!ModelState.IsValid) + { + return View(clientClaim); + } + + await _clientService.AddClientClaimAsync(clientClaim); + SuccessNotification(string.Format(_localizer["SuccessAddClientClaim"], clientClaim.Value, clientClaim.ClientName), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ClientClaims), new { Id = clientClaim.ClientId }); + } + + [HttpGet] + public async Task ClientClaimDelete(int id) + { + if (id == 0) return NotFound(); + + var clientClaim = await _clientService.GetClientClaimAsync(id); + + return View(nameof(ClientClaimDelete), clientClaim); + } + + [HttpGet] + public async Task ClientPropertyDelete(int id) + { + if (id == 0) return NotFound(); + + var clientProperty = await _clientService.GetClientPropertyAsync(id); + + return View(nameof(ClientPropertyDelete), clientProperty); + } + + [HttpGet] + public async Task ApiResourcePropertyDelete(int id) + { + if (id == 0) return NotFound(); + + var apiResourceProperty = await _apiResourceService.GetApiResourcePropertyAsync(id); + + return View(nameof(ApiResourcePropertyDelete), apiResourceProperty); + } + + [HttpGet] + public async Task ApiScopePropertyDelete(int id) + { + if (id == 0) return NotFound(); + + var apiScopeProperty = await _apiScopeService.GetApiScopePropertyAsync(id); + + return View(nameof(ApiScopePropertyDelete), apiScopeProperty); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ApiScopePropertyDelete(ApiScopePropertiesDto apiScopeProperty) + { + await _apiScopeService.DeleteApiScopePropertyAsync(apiScopeProperty); + SuccessNotification(_localizer["SuccessDeleteApiScopeProperty"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ApiScopeProperties), new { Id = apiScopeProperty.ApiScopeId }); + } + + [HttpGet] + public async Task IdentityResourcePropertyDelete(int id) + { + if (id == 0) return NotFound(); + + var identityResourceProperty = await _identityResourceService.GetIdentityResourcePropertyAsync(id); + + return View(nameof(IdentityResourcePropertyDelete), identityResourceProperty); + } + + [HttpPost] + public async Task ClientClaimDelete(ClientClaimsDto clientClaim) + { + await _clientService.DeleteClientClaimAsync(clientClaim); + SuccessNotification(_localizer["SuccessDeleteClientClaim"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ClientClaims), new { Id = clientClaim.ClientId }); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ClientPropertyDelete(ClientPropertiesDto clientProperty) + { + await _clientService.DeleteClientPropertyAsync(clientProperty); + SuccessNotification(_localizer["SuccessDeleteClientProperty"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ClientProperties), new { Id = clientProperty.ClientId }); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ApiResourcePropertyDelete(ApiResourcePropertiesDto apiResourceProperty) + { + await _apiResourceService.DeleteApiResourcePropertyAsync(apiResourceProperty); + SuccessNotification(_localizer["SuccessDeleteApiResourceProperty"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ApiResourceProperties), new { Id = apiResourceProperty.ApiResourceId }); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task IdentityResourcePropertyDelete(IdentityResourcePropertiesDto identityResourceProperty) + { + await _identityResourceService.DeleteIdentityResourcePropertyAsync(identityResourceProperty); + SuccessNotification(_localizer["SuccessDeleteIdentityResourceProperty"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(IdentityResourceProperties), new { Id = identityResourceProperty.IdentityResourceId }); + } + + [HttpGet] + public async Task ClientSecrets(int id, int? page) + { + if (id == 0) return NotFound(); + + var clientSecrets = await _clientService.GetClientSecretsAsync(id, page ?? 1); + _clientService.BuildClientSecretsViewModel(clientSecrets); + + return View(clientSecrets); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ClientSecrets(ClientSecretsDto clientSecret) + { + await _clientService.AddClientSecretAsync(clientSecret); + SuccessNotification(string.Format(_localizer["SuccessAddClientSecret"], clientSecret.ClientName), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ClientSecrets), new { Id = clientSecret.ClientId }); + } + + [HttpGet] + public async Task ClientSecretDelete(int id) + { + if (id == 0) return NotFound(); + + var clientSecret = await _clientService.GetClientSecretAsync(id); + + return View(nameof(ClientSecretDelete), clientSecret); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ClientSecretDelete(ClientSecretsDto clientSecret) + { + await _clientService.DeleteClientSecretAsync(clientSecret); + SuccessNotification(_localizer["SuccessDeleteClientSecret"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ClientSecrets), new { Id = clientSecret.ClientId }); + } + + [HttpGet] + public async Task SearchScopes(string scope, int limit = 0) + { + var scopes = await _clientService.GetScopesAsync(scope, limit); + + return Ok(scopes); + } + + [HttpGet] + public async Task SearchApiScopes(string scope, int limit = 0) + { + var scopes = await _apiScopeService.GetApiScopesNameAsync(scope, limit); + + return Ok(scopes.ToList()); + } + + [HttpGet] + public IActionResult SearchClaims(string claim, int limit = 0) + { + var claims = _clientService.GetStandardClaims(claim, limit); + + return Ok(claims); + } + + [HttpGet] + public IActionResult SearchSigningAlgorithms(string algorithm, int limit = 0) + { + var signingAlgorithms = _clientService.GetSigningAlgorithms(algorithm, limit); + + return Ok(signingAlgorithms); + } + + + [HttpGet] + public IActionResult SearchGrantTypes(string grant, int limit = 0) + { + var grants = _clientService.GetGrantTypes(grant, limit); + + return Ok(grants); + } + + [HttpGet] + public async Task Clients(int? page, string search) + { + ViewBag.Search = search; + return View(await _clientService.GetClientsAsync(search, page ?? 1)); + } + + [HttpGet] + public async Task IdentityResourceDelete(int id) + { + if (id == 0) return NotFound(); + + var identityResource = await _identityResourceService.GetIdentityResourceAsync(id); + + return View(identityResource); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task IdentityResourceDelete(IdentityResourceDto identityResource) + { + await _identityResourceService.DeleteIdentityResourceAsync(identityResource); + SuccessNotification(_localizer["SuccessDeleteIdentityResource"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(IdentityResources)); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task IdentityResource(IdentityResourceDto identityResource) + { + if (!ModelState.IsValid) + { + return View(identityResource); + } + + identityResource = _identityResourceService.BuildIdentityResourceViewModel(identityResource); + + int identityResourceId; + + if (identityResource.Id == 0) + { + identityResourceId = await _identityResourceService.AddIdentityResourceAsync(identityResource); + } + else + { + identityResourceId = identityResource.Id; + await _identityResourceService.UpdateIdentityResourceAsync(identityResource); + } + + SuccessNotification(string.Format(_localizer["SuccessAddIdentityResource"], identityResource.Name), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(IdentityResource), new { Id = identityResourceId }); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ApiResource(ApiResourceDto apiResource) + { + if (!ModelState.IsValid) + { + return View(apiResource); + } + + ComboBoxHelpers.PopulateValuesToList(apiResource.UserClaimsItems, apiResource.UserClaims); + ComboBoxHelpers.PopulateValuesToList(apiResource.ScopesItems, apiResource.Scopes); + ComboBoxHelpers.PopulateValuesToList(apiResource.AllowedAccessTokenSigningAlgorithmsItems, apiResource.AllowedAccessTokenSigningAlgorithms); + + int apiResourceId; + + if (apiResource.Id == 0) + { + apiResourceId = await _apiResourceService.AddApiResourceAsync(apiResource); + } + else + { + apiResourceId = apiResource.Id; + await _apiResourceService.UpdateApiResourceAsync(apiResource); + } + + SuccessNotification(string.Format(_localizer["SuccessAddApiResource"], apiResource.Name), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ApiResource), new { Id = apiResourceId }); + } + + [HttpGet] + public async Task ApiResourceDelete(int id) + { + if (id == 0) return NotFound(); + + var apiResource = await _apiResourceService.GetApiResourceAsync(id); + + return View(apiResource); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ApiResourceDelete(ApiResourceDto apiResource) + { + await _apiResourceService.DeleteApiResourceAsync(apiResource); + SuccessNotification(_localizer["SuccessDeleteApiResource"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ApiResources)); + } + + [HttpGet] + public async Task ApiResource(string id) + { + if (id.IsNotPresentedValidNumber()) + { + return NotFound(); + } + + if (id == default) + { + var apiResourceDto = new ApiResourceDto(); + return View(apiResourceDto); + } + + int.TryParse(id, out var apiResourceId); + var apiResource = await _apiResourceService.GetApiResourceAsync(apiResourceId); + + return View(apiResource); + } + + [HttpGet] + public async Task ApiSecrets(int id, int? page) + { + if (id == 0) return NotFound(); + + var apiSecrets = await _apiResourceService.GetApiSecretsAsync(id, page ?? 1); + _apiResourceService.BuildApiSecretsViewModel(apiSecrets); + + return View(apiSecrets); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ApiSecrets(ApiSecretsDto apiSecret) + { + if (!ModelState.IsValid) + { + return View(apiSecret); + } + + await _apiResourceService.AddApiSecretAsync(apiSecret); + SuccessNotification(_localizer["SuccessAddApiSecret"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ApiSecrets), new { Id = apiSecret.ApiResourceId }); + } + + [HttpGet] + public async Task ApiScopes(string search, int? page) + { + ViewBag.Search = search; + var apiScopesDto = await _apiScopeService.GetApiScopesAsync(search, page ?? 1); + + return View(apiScopesDto); + } + + [HttpGet] + public async Task ApiScope(string id) + { + if (id.IsNotPresentedValidNumber()) + { + return NotFound(); + } + + if (id == default) + { + var apiScopeDto = new ApiScopeDto(); + + return View(apiScopeDto); + } + else + { + int.TryParse(id, out var apiScopeId); + var apiScopeDto = await _apiScopeService.GetApiScopeAsync(apiScopeId); + + return View(apiScopeDto); + } + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ApiScope(ApiScopeDto apiScope) + { + if (!ModelState.IsValid) + { + return View(apiScope); + } + + _apiScopeService.BuildApiScopeViewModel(apiScope); + + int apiScopeId; + + if (apiScope.Id == 0) + { + apiScopeId = await _apiScopeService.AddApiScopeAsync(apiScope); + } + else + { + apiScopeId = apiScope.Id; + await _apiScopeService.UpdateApiScopeAsync(apiScope); + } + + SuccessNotification(string.Format(_localizer["SuccessAddApiScope"], apiScope.Name), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ApiScope), new { id = apiScopeId }); + } + + [HttpGet] + public async Task ApiScopeDelete(int id) + { + if (id == 0) return NotFound(); + + var apiScope = await _apiScopeService.GetApiScopeAsync(id); + + return View(nameof(ApiScopeDelete), apiScope); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ApiScopeDelete(ApiScopeDto apiScope) + { + await _apiScopeService.DeleteApiScopeAsync(apiScope); + SuccessNotification(_localizer["SuccessDeleteApiScope"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ApiScopes)); + } + + [HttpGet] + public async Task ApiResources(int? page, string search) + { + ViewBag.Search = search; + var apiResources = await _apiResourceService.GetApiResourcesAsync(search, page ?? 1); + + return View(apiResources); + } + + [HttpGet] + public async Task IdentityResources(int? page, string search) + { + ViewBag.Search = search; + var identityResourcesDto = await _identityResourceService.GetIdentityResourcesAsync(search, page ?? 1); + + return View(identityResourcesDto); + } + + [HttpGet] + public async Task ApiSecretDelete(int id) + { + if (id == 0) return NotFound(); + + var clientSecret = await _apiResourceService.GetApiSecretAsync(id); + + return View(nameof(ApiSecretDelete), clientSecret); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ApiSecretDelete(ApiSecretsDto apiSecret) + { + await _apiResourceService.DeleteApiSecretAsync(apiSecret); + SuccessNotification(_localizer["SuccessDeleteApiSecret"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(ApiSecrets), new { Id = apiSecret.ApiResourceId }); + } + + [HttpGet] + public async Task IdentityResource(string id) + { + if (id.IsNotPresentedValidNumber()) + { + return NotFound(); + } + + if (id == default) + { + var identityResourceDto = new IdentityResourceDto(); + return View(identityResourceDto); + } + + int.TryParse(id, out var identityResourceId); + var identityResource = await _identityResourceService.GetIdentityResourceAsync(identityResourceId); + + return View(identityResource); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/GrantController.cs b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/GrantController.cs new file mode 100644 index 000000000..fae54e5aa --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/GrantController.cs @@ -0,0 +1,83 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Logging; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Grant; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Services.Interfaces; +using Skoruba.IdentityServer4.Admin.UI.ExceptionHandling; +using Skoruba.IdentityServer4.Admin.UI.Helpers; +using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants; + +namespace Skoruba.IdentityServer4.Admin.UI.Areas.AdminUI.Controllers +{ + [Authorize(Policy = AuthorizationConsts.AdministrationPolicy)] + [TypeFilter(typeof(ControllerExceptionFilterAttribute))] + [Area(CommonConsts.AdminUIArea)] + public class GrantController : BaseController + { + private readonly IPersistedGrantAspNetIdentityService _persistedGrantService; + private readonly IStringLocalizer _localizer; + + public GrantController(IPersistedGrantAspNetIdentityService persistedGrantService, + ILogger logger, + IStringLocalizer localizer) : base(logger) + { + _persistedGrantService = persistedGrantService; + _localizer = localizer; + } + + [HttpGet] + public async Task PersistedGrants(int? page, string search) + { + ViewBag.Search = search; + var persistedGrants = await _persistedGrantService.GetPersistedGrantsByUsersAsync(search, page ?? 1); + + return View(persistedGrants); + } + + [HttpGet] + public async Task PersistedGrantDelete(string id) + { + if (string.IsNullOrEmpty(id)) return NotFound(); + + var grant = await _persistedGrantService.GetPersistedGrantAsync(UrlHelpers.QueryStringUnSafeHash(id)); + if (grant == null) return NotFound(); + + return View(grant); + } + + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task PersistedGrantDelete(PersistedGrantDto grant) + { + await _persistedGrantService.DeletePersistedGrantAsync(grant.Key); + + SuccessNotification(_localizer["SuccessPersistedGrantDelete"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(PersistedGrants)); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task PersistedGrantsDelete(PersistedGrantsDto grants) + { + await _persistedGrantService.DeletePersistedGrantsAsync(grants.SubjectId); + + SuccessNotification(_localizer["SuccessPersistedGrantsDelete"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(PersistedGrants)); + } + + + [HttpGet] + public async Task PersistedGrant(string id, int? page) + { + var persistedGrants = await _persistedGrantService.GetPersistedGrantsByUserAsync(id, page ?? 1); + persistedGrants.SubjectId = id; + + return View(persistedGrants); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/HomeController.cs b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/HomeController.cs new file mode 100644 index 000000000..df5f1a60e --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/HomeController.cs @@ -0,0 +1,75 @@ +using System; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Diagnostics; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Localization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants; +using Skoruba.IdentityServer4.Admin.UI.ExceptionHandling; +using Skoruba.IdentityServer4.Shared.Configuration.Helpers; + +namespace Skoruba.IdentityServer4.Admin.UI.Areas.AdminUI.Controllers +{ + [Authorize(Policy = AuthorizationConsts.AdministrationPolicy)] + [TypeFilter(typeof(ControllerExceptionFilterAttribute))] + [Area(CommonConsts.AdminUIArea)] + public class HomeController : BaseController + { + private readonly ILogger _logger; + + public HomeController(ILogger logger) : base(logger) + { + _logger = logger; + } + + public IActionResult Index() + { + return View(); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public IActionResult SetLanguage(string culture, string returnUrl) + { + Response.Cookies.Append( + CookieRequestCultureProvider.DefaultCookieName, + CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)), + new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) } + ); + return LocalRedirect(returnUrl); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public IActionResult SelectTheme(string theme, string returnUrl) + { + Response.Cookies.Append( + ThemeHelpers.CookieThemeKey, + theme, + new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) } + ); + + return LocalRedirect(returnUrl); + } + + public IActionResult Error() + { + // Get the details of the exception that occurred + var exceptionFeature = HttpContext.Features.Get(); + + if (exceptionFeature == null) return View(); + + // Get which route the exception occurred at + string routeWhereExceptionOccurred = exceptionFeature.Path; + + // Get the exception that occurred + Exception exceptionThatOccurred = exceptionFeature.Error; + + // Log the exception + _logger.LogError(exceptionThatOccurred, $"Exception at route {routeWhereExceptionOccurred}"); + + return View(); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/IdentityController.cs b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/IdentityController.cs new file mode 100644 index 000000000..6353a0755 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/IdentityController.cs @@ -0,0 +1,445 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using IdentityServer4.Extensions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Services.Interfaces; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common; +using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants; +using Skoruba.IdentityServer4.Admin.UI.ExceptionHandling; +using Skoruba.IdentityServer4.Admin.UI.Helpers.Localization; + +namespace Skoruba.IdentityServer4.Admin.UI.Areas.AdminUI.Controllers +{ + [Authorize(Policy = AuthorizationConsts.AdministrationPolicy)] + [TypeFilter(typeof(ControllerExceptionFilterAttribute))] + [Area(CommonConsts.AdminUIArea)] + public class IdentityController : BaseController + where TUserDto : UserDto, new() + where TRoleDto : RoleDto, new() + where TUser : IdentityUser + where TRole : IdentityRole + where TKey : IEquatable + where TUserClaim : IdentityUserClaim + where TUserRole : IdentityUserRole + where TUserLogin : IdentityUserLogin + where TRoleClaim : IdentityRoleClaim + where TUserToken : IdentityUserToken + where TUsersDto : UsersDto + where TRolesDto : RolesDto + where TUserRolesDto : UserRolesDto + where TUserClaimsDto : UserClaimsDto + where TUserProviderDto : UserProviderDto + where TUserProvidersDto : UserProvidersDto + where TUserChangePasswordDto : UserChangePasswordDto + where TRoleClaimsDto : RoleClaimsDto + where TUserClaimDto : UserClaimDto + where TRoleClaimDto : RoleClaimDto + { + private readonly IIdentityService _identityService; + private readonly IGenericControllerLocalizer> _localizer; + + public IdentityController(IIdentityService identityService, + ILogger logger, + IGenericControllerLocalizer> localizer) : base(logger) + { + _identityService = identityService; + _localizer = localizer; + } + + [HttpGet] + public async Task Roles(int? page, string search) + { + ViewBag.Search = search; + var roles = await _identityService.GetRolesAsync(search, page ?? 1); + + return View(roles); + } + + [HttpGet] + public async Task Role(TKey id) + { + if (EqualityComparer.Default.Equals(id, default)) + { + return View(new TRoleDto()); + } + + var role = await _identityService.GetRoleAsync(id.ToString()); + + return View(role); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Role(TRoleDto role) + { + if (!ModelState.IsValid) + { + return View(role); + } + + TKey roleId; + + if (EqualityComparer.Default.Equals(role.Id, default)) + { + var roleData = await _identityService.CreateRoleAsync(role); + roleId = roleData.roleId; + } + else + { + var roleData = await _identityService.UpdateRoleAsync(role); + roleId = roleData.roleId; + } + + SuccessNotification(string.Format(_localizer["SuccessCreateRole"], role.Name), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(Role), new { Id = roleId }); + } + + [HttpGet] + public async Task Users(int? page, string search) + { + ViewBag.Search = search; + var usersDto = await _identityService.GetUsersAsync(search, page ?? 1); + + return View(usersDto); + } + + [HttpGet] + public async Task RoleUsers(string id, int? page, string search) + { + ViewBag.Search = search; + var roleUsers = await _identityService.GetRoleUsersAsync(id, search, page ?? 1); + + var roleDto = await _identityService.GetRoleAsync(id); + ViewData["RoleName"] = roleDto.Name; + + return View(roleUsers); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task UserProfile(TUserDto user) + { + if (!ModelState.IsValid) + { + return View(user); + } + + TKey userId; + + if (EqualityComparer.Default.Equals(user.Id, default)) + { + var userData = await _identityService.CreateUserAsync(user); + userId = userData.userId; + } + else + { + var userData = await _identityService.UpdateUserAsync(user); + userId = userData.userId; + } + + SuccessNotification(string.Format(_localizer["SuccessCreateUser"], user.UserName), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(UserProfile), new { Id = userId }); + } + + [HttpGet] + public async Task UserProfile(TKey id) + { + if (EqualityComparer.Default.Equals(id, default)) + { + var newUser = new TUserDto(); + + return View("UserProfile", newUser); + } + + var user = await _identityService.GetUserAsync(id.ToString()); + if (user == null) return NotFound(); + + return View("UserProfile", user); + } + + [HttpGet] + public async Task UserRoles(TKey id, int? page) + { + if (EqualityComparer.Default.Equals(id, default)) return NotFound(); + + var userRoles = await _identityService.BuildUserRolesViewModel(id, page); + + return View(userRoles); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task UserRoles(TUserRolesDto role) + { + await _identityService.CreateUserRoleAsync(role); + SuccessNotification(_localizer["SuccessCreateUserRole"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(UserRoles), new { Id = role.UserId }); + } + + [HttpGet] + public async Task UserRolesDelete(TKey id, TKey roleId) + { + await _identityService.ExistsUserAsync(id.ToString()); + await _identityService.ExistsRoleAsync(roleId.ToString()); + + var userDto = await _identityService.GetUserAsync(id.ToString()); + var roles = await _identityService.GetRolesAsync(); + + var rolesDto = new UserRolesDto + { + UserId = id, + RolesList = roles.Select(x => new SelectItemDto(x.Id.ToString(), x.Name)).ToList(), + RoleId = roleId, + UserName = userDto.UserName + }; + + return View(rolesDto); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task UserRolesDelete(TUserRolesDto role) + { + await _identityService.DeleteUserRoleAsync(role); + SuccessNotification(_localizer["SuccessDeleteUserRole"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(UserRoles), new { Id = role.UserId }); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task UserClaims(TUserClaimsDto claim) + { + if (!ModelState.IsValid) + { + return View(claim); + } + + await _identityService.CreateUserClaimsAsync(claim); + SuccessNotification(string.Format(_localizer["SuccessCreateUserClaims"], claim.ClaimType, claim.ClaimValue), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(UserClaims), new { Id = claim.UserId }); + } + + [HttpGet] + public async Task UserClaims(TKey id, int? page) + { + if (EqualityComparer.Default.Equals(id, default)) return NotFound(); + + var claims = await _identityService.GetUserClaimsAsync(id.ToString(), page ?? 1); + claims.UserId = id; + + return View(claims); + } + + [HttpGet] + public async Task UserClaimsDelete(TKey id, int claimId) + { + if (EqualityComparer.Default.Equals(id, default) + || EqualityComparer.Default.Equals(claimId, default)) return NotFound(); + + var claim = await _identityService.GetUserClaimAsync(id.ToString(), claimId); + if (claim == null) return NotFound(); + + var userDto = await _identityService.GetUserAsync(id.ToString()); + claim.UserName = userDto.UserName; + + return View(claim); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task UserClaimsDelete(TUserClaimsDto claim) + { + await _identityService.DeleteUserClaimAsync(claim); + SuccessNotification(_localizer["SuccessDeleteUserClaims"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(UserClaims), new { Id = claim.UserId }); + } + + [HttpGet] + public async Task UserProviders(TKey id) + { + if (EqualityComparer.Default.Equals(id, default)) return NotFound(); + + var providers = await _identityService.GetUserProvidersAsync(id.ToString()); + + return View(providers); + } + + [HttpGet] + public async Task UserProvidersDelete(TKey id, string providerKey) + { + if (EqualityComparer.Default.Equals(id, default) || string.IsNullOrEmpty(providerKey)) return NotFound(); + + var provider = await _identityService.GetUserProviderAsync(id.ToString(), providerKey); + if (provider == null) return NotFound(); + + return View(provider); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task UserProvidersDelete(TUserProviderDto provider) + { + await _identityService.DeleteUserProvidersAsync(provider); + SuccessNotification(_localizer["SuccessDeleteUserProviders"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(UserProviders), new { Id = provider.UserId }); + } + + [HttpGet] + public async Task UserChangePassword(TKey id) + { + if (EqualityComparer.Default.Equals(id, default)) return NotFound(); + + var user = await _identityService.GetUserAsync(id.ToString()); + var userDto = new UserChangePasswordDto { UserId = id, UserName = user.UserName }; + + return View(userDto); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task UserChangePassword(TUserChangePasswordDto userPassword) + { + if (!ModelState.IsValid) + { + return View(userPassword); + } + + var identityResult = await _identityService.UserChangePasswordAsync(userPassword); + + if (!identityResult.Errors.Any()) + { + SuccessNotification(_localizer["SuccessUserChangePassword"], _localizer["SuccessTitle"]); + + return RedirectToAction("UserProfile", new { Id = userPassword.UserId }); + } + + foreach (var error in identityResult.Errors) + { + ModelState.AddModelError(string.Empty, error.Description); + } + + return View(userPassword); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task RoleClaims(TRoleClaimsDto claim) + { + if (!ModelState.IsValid) + { + return View(claim); + } + + await _identityService.CreateRoleClaimsAsync(claim); + SuccessNotification(string.Format(_localizer["SuccessCreateRoleClaims"], claim.ClaimType, claim.ClaimValue), _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(RoleClaims), new { Id = claim.RoleId }); + } + + [HttpGet] + public async Task RoleClaims(TKey id, int? page) + { + if (EqualityComparer.Default.Equals(id, default)) return NotFound(); + + var claims = await _identityService.GetRoleClaimsAsync(id.ToString(), page ?? 1); + claims.RoleId = id; + + return View(claims); + } + + [HttpGet] + public async Task RoleClaimsDelete(TKey id, int claimId) + { + if (EqualityComparer.Default.Equals(id, default) || + EqualityComparer.Default.Equals(claimId, default)) return NotFound(); + + var claim = await _identityService.GetRoleClaimAsync(id.ToString(), claimId); + + return View(claim); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task RoleClaimsDelete(TRoleClaimsDto claim) + { + await _identityService.DeleteRoleClaimAsync(claim); + SuccessNotification(_localizer["SuccessDeleteRoleClaims"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(RoleClaims), new { Id = claim.RoleId }); + } + + [HttpGet] + public async Task RoleDelete(TKey id) + { + if (EqualityComparer.Default.Equals(id, default)) return NotFound(); + + var roleDto = await _identityService.GetRoleAsync(id.ToString()); + if (roleDto == null) return NotFound(); + + return View(roleDto); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task RoleDelete(TRoleDto role) + { + await _identityService.DeleteRoleAsync(role); + SuccessNotification(_localizer["SuccessDeleteRole"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(Roles)); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task UserDelete(TUserDto user) + { + var currentUserId = User.GetSubjectId(); + if (user.Id.ToString() == currentUserId) + { + CreateNotification(Helpers.NotificationHelpers.AlertType.Warning, _localizer["ErrorDeleteUser_CannotSelfDelete"]); + return RedirectToAction(nameof(UserDelete), user.Id); + } + else + { + await _identityService.DeleteUserAsync(user.Id.ToString(), user); + SuccessNotification(_localizer["SuccessDeleteUser"], _localizer["SuccessTitle"]); + + return RedirectToAction(nameof(Users)); + } + } + + [HttpGet] + public async Task UserDelete(TKey id) + { + if (EqualityComparer.Default.Equals(id, default)) return NotFound(); + + var user = await _identityService.GetUserAsync(id.ToString()); + if (user == null) return NotFound(); + + return View(user); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/LogController.cs b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/LogController.cs new file mode 100644 index 000000000..9ee5c4852 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Controllers/LogController.cs @@ -0,0 +1,77 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Log; +using Skoruba.IdentityServer4.Admin.BusinessLogic.Services.Interfaces; +using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants; + +namespace Skoruba.IdentityServer4.Admin.UI.Areas.AdminUI.Controllers +{ + [Authorize(Policy = AuthorizationConsts.AdministrationPolicy)] + [Area(CommonConsts.AdminUIArea)] + public class LogController : BaseController + { + private readonly ILogService _logService; + private readonly IAuditLogService _auditLogService; + + public LogController(ILogService logService, + ILogger logger, + IAuditLogService auditLogService) : base(logger) + { + _logService = logService; + _auditLogService = auditLogService; + } + + [HttpGet] + public async Task ErrorsLog(int? page, string search) + { + ViewBag.Search = search; + var logs = await _logService.GetLogsAsync(search, page ?? 1); + + return View(logs); + } + + [HttpGet] + public async Task AuditLog([FromQuery]AuditLogFilterDto filters) + { + ViewBag.SubjectIdentifier = filters.SubjectIdentifier; + ViewBag.SubjectName = filters.SubjectName; + ViewBag.Event = filters.Event; + ViewBag.Source = filters.Source; + ViewBag.Category = filters.Category; + + var logs = await _auditLogService.GetAsync(filters); + + return View(logs); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task DeleteLogs(LogsDto log) + { + if (!ModelState.IsValid) + { + return View(nameof(ErrorsLog), log); + } + + await _logService.DeleteLogsOlderThanAsync(log.DeleteOlderThan.Value); + + return RedirectToAction(nameof(ErrorsLog)); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task DeleteAuditLogs(AuditLogsDto log) + { + if (!ModelState.IsValid) + { + return View(nameof(AuditLog), log); + } + + await _auditLogService.DeleteLogsOlderThanAsync(log.DeleteOlderThan.Value); + + return RedirectToAction(nameof(AuditLog)); + } + } +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Account/AccessDenied.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Account/AccessDenied.cshtml new file mode 100644 index 000000000..77c37a8ea --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Account/AccessDenied.cshtml @@ -0,0 +1,53 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@inject IViewLocalizer Localizer +@inject AdminConfiguration AdminConfiguration +@{ Layout = null; } + + + + + + + + @Localizer["PageTitle"] + + + + + + + + + + + +
+
+
+
+
+
+

@Localizer["PageTitle"]

+
+ +
+
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResource.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResource.cshtml new file mode 100644 index 000000000..850266437 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResource.cshtml @@ -0,0 +1,196 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ApiResourceDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+

@Localizer["PageTitle"]

+
+
+ +
+ +
+ + + + +
+
@Localizer["PanelTitle"]
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + @if (Model.Id != 0) + { + +
+ + +
+ +
+ + +
+ } + + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + @if (Model.Id != 0) + { + @Localizer["ButtonDeleteApiResource"] + } +
+
+
+
+ +
+ +@section scripts + { + +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin/Views/Configuration/ApiResource/Section/Label.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResource/Section/Label.cshtml similarity index 100% rename from src/Skoruba.IdentityServer4.Admin/Views/Configuration/ApiResource/Section/Label.cshtml rename to src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResource/Section/Label.cshtml diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResourceDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResourceDelete.cshtml new file mode 100644 index 000000000..f53eb08cd --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResourceDelete.cshtml @@ -0,0 +1,56 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ApiResourceDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+

@Localizer["PageTitle"]

+
+
+ +
+ + + + +
+
@Localizer["PanelTitle"]
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResourceProperties.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResourceProperties.cshtml new file mode 100644 index 000000000..4201a609a --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResourceProperties.cshtml @@ -0,0 +1,112 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ApiResourcePropertiesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+ +
+ +

@Localizer["PageTitle"]

+ +
+ + + + + + + +
+
@Localizer["PanelTitleNew"]
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+
+
+
+
+
+ +
+
+
+
@Localizer["PanelTitle"]
+
+
+ + + + + + + + + + @foreach (var apiResourceProperty in Model.ApiResourceProperties) + { + + + + + + } + +
@Localizer["TableKey"]@Localizer["TableValue"]
@apiResourceProperty.Key@apiResourceProperty.Value@Localizer["TableButtonRemove"]
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "ApiResourceProperties", PageSize = Model.PageSize, TotalCount = Model.TotalCount }) +
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResourcePropertyDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResourcePropertyDelete.cshtml new file mode 100644 index 000000000..8ffce88aa --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResourcePropertyDelete.cshtml @@ -0,0 +1,67 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ApiResourcePropertiesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ + + +
+

@Localizer["PageTitle"]

+ + + + + +
+
@Localizer["PanelTitle"]
+
+ +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResources.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResources.cshtml new file mode 100644 index 000000000..c9d91e94d --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiResources.cshtml @@ -0,0 +1,59 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ApiResourcesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+ +
+

@Localizer["PageTitle"]

+
+ + + +
+ @await Html.PartialAsync("Common/Search", new Search() { Action = "ApiResources", Controller = "Configuration" }) +
+
+
+
+
+ + + + + + + + + + + @foreach (var api in Model.ApiResources) + { + + + + + + } + +
@Localizer["TableName"]
@Localizer["TableButtonEdit"]@api.Name + +
+
+
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "ApiResources", PageSize = Model.PageSize, TotalCount = Model.TotalCount, EnableSearch = true, Search = @ViewBag.Search }) +
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScope.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScope.cshtml new file mode 100644 index 000000000..1de50949f --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScope.cshtml @@ -0,0 +1,177 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ApiScopeDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+

@Localizer["PanelTitle"]

+
+
+ +
+ +
+ + + + +
+
@Localizer["PanelTitle"]
+
+ +
+ +
+ + +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + @if (Model.Id != 0) + { + +
+ + +
+ } + + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+
+
+ +
+ +@section scripts + { + +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin/Views/Configuration/IdentityResource/Section/Label.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScope/Section/Label.cshtml similarity index 100% rename from src/Skoruba.IdentityServer4.Admin/Views/Configuration/IdentityResource/Section/Label.cshtml rename to src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScope/Section/Label.cshtml diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScopeDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScopeDelete.cshtml new file mode 100644 index 000000000..43bef7381 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScopeDelete.cshtml @@ -0,0 +1,57 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ApiScopeDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+

@Localizer["PageTitle"]

+
+
+ +
+ + + + +
+
@Localizer["PanelTitle"]
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+ +
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScopeProperties.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScopeProperties.cshtml new file mode 100644 index 000000000..5b889101d --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScopeProperties.cshtml @@ -0,0 +1,112 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ApiScopePropertiesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+ +
+ +

@Localizer["PageTitle"]

+ +
+ + + + + + + +
+
@Localizer["PageSubTitle"]
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+
+
+
+
+
+ +
+
+
+
@Localizer["PageTitle"]
+
+
+ + + + + + + + + + @foreach (var apiResourceProperty in Model.ApiScopeProperties) + { + + + + + + } + +
@Localizer["TableKey"]@Localizer["TableValue"]
@apiResourceProperty.Key@apiResourceProperty.Value@Localizer["TableDelete"]
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "ApiResourceProperties", PageSize = Model.PageSize, TotalCount = Model.TotalCount }) +
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScopePropertyDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScopePropertyDelete.cshtml new file mode 100644 index 000000000..d07125b26 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScopePropertyDelete.cshtml @@ -0,0 +1,67 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ApiScopePropertiesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ + + +
+

@Localizer["PageTitle"]

+ + + + + +
+
@Localizer["PageTitle"]
+
+ +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScopes.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScopes.cshtml new file mode 100644 index 000000000..7c897f9ac --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiScopes.cshtml @@ -0,0 +1,69 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ApiScopesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+

@Localizer["PageTitle"]

+
+ + + +
+ @await Html.PartialAsync("Common/Search", new Search() { Action = "ApiScopes", Controller = "Configuration" }) +
+
+ +
+
+ +
+ + + + + + + + + + + @foreach (var scope in Model.Scopes) + { + + + + + + } + +
@Localizer["TableName"]
@Localizer["TableButtonEdit"]@scope.Name
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager() { Action = "ApiScopes", PageSize = Model.PageSize, TotalCount = Model.TotalCount, EnableSearch = true, Search = @ViewBag.Search }) +
+
+ +
+
+ +@section scripts + { + +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiSecretDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiSecretDelete.cshtml new file mode 100644 index 000000000..b243e7ee2 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiSecretDelete.cshtml @@ -0,0 +1,70 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ApiSecretsDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ + + +
+

@Localizer["PageTitle"]

+ + + + + + + +
+
@Localizer["PanelDeleteApiSecret"]
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiSecrets.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiSecrets.cshtml new file mode 100644 index 000000000..13f3df2b1 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ApiSecrets.cshtml @@ -0,0 +1,167 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ApiSecretsDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+ +
+

@Localizer["PageTitle"]

+
+ +
+
+
+ +
+
+
@Localizer["PanelNewTitle"]
+
+ + + + + +
+ +
+ +
+
+ + +
+ +
+ +
+ +
+ +
+
+ + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+
+ +
+ +
+
+
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+ +
+
+
+ +
+
+
+
@Localizer["PanelTitle"]
+
+ +
+ + + + + + + + + + + + + @foreach (var secret in Model.ApiSecrets) + { + + + + + + + + } + +
@Localizer["TableType"]@Localizer["TableDescription"]@Localizer["TableExpiration"]@Localizer["TableCreated"]
@Localizer["TableButtonRemove"]@secret.Type@secret.Description@(secret.Expiration.HasValue ? secret.Expiration.Value.Date.ToShortDateString() : string.Empty)@secret.Created.Date.ToShortDateString()
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "ApiSecrets", PageSize = Model.PageSize, TotalCount = Model.TotalCount }) +
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client.cshtml new file mode 100644 index 000000000..564b153f6 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client.cshtml @@ -0,0 +1,57 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ClientDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+ +
+
+ +
+ + @if (Model.Id != 0) + { +
+

@Localizer["Title"] @Model.ClientId

+
+ } + +
+
+
+
+ + @if (Model.Id != 0) + { + @await Html.PartialAsync("Client/Section/ActionButtons") + } + + @await Html.PartialAsync("Client/Settings") + @await Html.PartialAsync("Client/Section/ActionButtons") +
+ +@section scripts + { + +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/ActionButtons.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/ActionButtons.cshtml new file mode 100644 index 000000000..e3250f252 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/ActionButtons.cshtml @@ -0,0 +1,16 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ClientDto +@inject IViewLocalizer Localizer + +
+
+ + + @if (Model.Id != 0) + { + @Localizer["ButtonClone"] + @Localizer["ButtonDelete"] + } +
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin/Views/Configuration/Client/Section/Authentication.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Authentication.cshtml similarity index 100% rename from src/Skoruba.IdentityServer4.Admin/Views/Configuration/Client/Section/Authentication.cshtml rename to src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Authentication.cshtml diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Basics.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Basics.cshtml new file mode 100644 index 000000000..04add9fc8 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Basics.cshtml @@ -0,0 +1,194 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ClientDto +@inject IViewLocalizer Localizer + + + +
+
@Localizer["PanelTitle"]
+
+ +
+ +
+ + + +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + + +
+
+ +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + +
+
+ + + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ + +
+ + + +
+ + +
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin/Views/Configuration/Client/Section/Consent.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Consent.cshtml similarity index 100% rename from src/Skoruba.IdentityServer4.Admin/Views/Configuration/Client/Section/Consent.cshtml rename to src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Consent.cshtml diff --git a/src/Skoruba.IdentityServer4.Admin/Views/Configuration/Client/Section/DeviceFlow.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/DeviceFlow.cshtml similarity index 100% rename from src/Skoruba.IdentityServer4.Admin/Views/Configuration/Client/Section/DeviceFlow.cshtml rename to src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/DeviceFlow.cshtml diff --git a/src/Skoruba.IdentityServer4.Admin/Views/Configuration/Client/Section/Label.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Label.cshtml similarity index 100% rename from src/Skoruba.IdentityServer4.Admin/Views/Configuration/Client/Section/Label.cshtml rename to src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Label.cshtml diff --git a/src/Skoruba.IdentityServer4.Admin/Views/Configuration/Client/Section/Name.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Name.cshtml similarity index 100% rename from src/Skoruba.IdentityServer4.Admin/Views/Configuration/Client/Section/Name.cshtml rename to src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Name.cshtml diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Token.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Token.cshtml new file mode 100644 index 000000000..6b8bfc8ff --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Section/Token.cshtml @@ -0,0 +1,205 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ClientDto +@inject IViewLocalizer Localizer + +
+
@Localizer["PanelTitle"]
+
+ +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ + +
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin/Views/Configuration/Client/Settings.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Settings.cshtml similarity index 100% rename from src/Skoruba.IdentityServer4.Admin/Views/Configuration/Client/Settings.cshtml rename to src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Client/Settings.cshtml diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientClaimDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientClaimDelete.cshtml new file mode 100644 index 000000000..f6ed7fe13 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientClaimDelete.cshtml @@ -0,0 +1,69 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ClientClaimsDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ + + +
+

@Localizer["PageTitle"]

+ + + + + + +
+
@Localizer["PanelTitle"]
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientClaims.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientClaims.cshtml new file mode 100644 index 000000000..312e80379 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientClaims.cshtml @@ -0,0 +1,137 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ClientClaimsDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+ +
+

@Localizer["PageTitle"]

+ +
+ + + + + + + +
+
@Localizer["PanelNewTitle"]
+
+ + +
+ +
+ + + + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+
+
+
+
+
+ +
+
+
+
@Localizer["PanelTitle"]
+
+ +
+ + + + + + + + + + + @foreach (var clientClaim in Model.ClientClaims) + { + + + + + + } + +
@Localizer["TableType"]@Localizer["TableValue"]
@clientClaim.Type@clientClaim.Value@Localizer["TableButtonRemove"]
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "ClientClaims", PageSize = Model.PageSize, TotalCount = Model.TotalCount }) +
+
+
+
+
+
+ +@section scripts + { + +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientClone.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientClone.cshtml new file mode 100644 index 000000000..6d1862ce0 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientClone.cshtml @@ -0,0 +1,174 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ClientCloneDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+

@Localizer["PageTitle"] - @Model.ClientIdOriginal (@Model.ClientNameOriginal)

+
+
+ +
+ +
+ +
+
@Localizer["PanelTitle"]
+
+ + + +
+
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ +
+
+
+
+
diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientDelete.cshtml new file mode 100644 index 000000000..bbab63da6 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientDelete.cshtml @@ -0,0 +1,64 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ClientDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + + +
+
+ +
+
+ +
+ + + + +

@Localizer["PageTitle"]

+ +
+
@Localizer["PageTitle"]
+
+ +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientProperties.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientProperties.cshtml new file mode 100644 index 000000000..c8fe486db --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientProperties.cshtml @@ -0,0 +1,112 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ClientPropertiesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+ +
+ +

@Localizer["PageTitle"]

+ +
+ + + + + + + +
+
@Localizer["PanelTitleNew"]
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+
+
+
+
+
+ +
+
+
+
@Localizer["PanelTitle"]
+
+
+ + + + + + + + + + @foreach (var clientProperty in Model.ClientProperties) + { + + + + + + } + +
@Localizer["TableKey"]@Localizer["TableValue"]
@clientProperty.Key@clientProperty.Value@Localizer["TableButtonRemove"]
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "ClientProperties", PageSize = Model.PageSize, TotalCount = Model.TotalCount }) +
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientPropertyDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientPropertyDelete.cshtml new file mode 100644 index 000000000..0682d559f --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientPropertyDelete.cshtml @@ -0,0 +1,67 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ClientPropertiesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ + + +
+

@Localizer["PageTitle"]

+ + + + + +
+
@Localizer["PanelTitle"]
+
+ +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientSecretDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientSecretDelete.cshtml new file mode 100644 index 000000000..e5f574fcf --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientSecretDelete.cshtml @@ -0,0 +1,69 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ClientSecretsDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ + + +
+

@Localizer["PageTitle"]

+ + + + + + + +
+
@Localizer["PanelTitle"]
+
+ +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientSecrets.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientSecrets.cshtml new file mode 100644 index 000000000..b8a95aff5 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/ClientSecrets.cshtml @@ -0,0 +1,162 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ClientSecretsDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+ +
+

@Localizer["PageTitle"]

+ +
+ + + + + + + +
+
@Localizer["PanelTitleNew"]
+
+ +
+ +
+ +
+
+ + +
+ +
+ +
+ +
+ +
+
+ + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+
+ +
+ +
+
+
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
+
+
+ +
+
+
+
@Localizer["PanelTitle"]
+
+
+ + + + + + + + + + + + @foreach (var clientSecret in Model.ClientSecrets) + { + + + + + + + + } + +
@Localizer["TableType"]@Localizer["TableDescription"]@Localizer["TableExpiration"]@Localizer["TableCreated"]
@Localizer["TableButtonRemove"]@clientSecret.Type@clientSecret.Description@(clientSecret.Expiration.HasValue ? clientSecret.Expiration.Value.Date.ToShortDateString() : string.Empty)@clientSecret.Created.Date.ToShortDateString()
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "ClientSecrets", PageSize = Model.PageSize, TotalCount = Model.TotalCount }) +
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Clients.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Clients.cshtml new file mode 100644 index 000000000..e55730959 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/Clients.cshtml @@ -0,0 +1,59 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.ClientsDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+

@Localizer["PageTitle"]

+
+ + + +
+ @await Html.PartialAsync("Common/Search", new Search() { Action = "Clients", Controller = "Configuration" }) +
+
+
+
+
+ + + + + + + + + + + @foreach (var client in Model.Clients) + { + + + + + + + } + +
@Localizer["TableClientId"]@Localizer["TableClientName"]
@Localizer["TableButtonEdit"]@client.ClientId@client.ClientName + +
+
+
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "Clients", PageSize = Model.PageSize, TotalCount = Model.TotalCount, Search = ViewBag.Search, EnableSearch = true }) +
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResource.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResource.cshtml new file mode 100644 index 000000000..e70510620 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResource.cshtml @@ -0,0 +1,173 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.IdentityResourceDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+

@Localizer["PageTitle"]

+
+
+ +
+ +
+ + + + +
+
@Localizer["PanelTitle"]
+
+ +
+ +
+ + +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + +
+
+ + @if (Model.Id != 0) + { + +
+ + +
+ } + + +
+ +
+ + @if (Model.Id != 0) + { + @Localizer["ButtonDelete"] + } +
+
+
+
+ +
+ +@section scripts + { + +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin/Views/Identity/Role/Section/Label.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResource/Section/Label.cshtml similarity index 100% rename from src/Skoruba.IdentityServer4.Admin/Views/Identity/Role/Section/Label.cshtml rename to src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResource/Section/Label.cshtml diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResourceDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResourceDelete.cshtml new file mode 100644 index 000000000..7c1f844c8 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResourceDelete.cshtml @@ -0,0 +1,55 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.IdentityResourceDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+

@Localizer["PageTitle"]

+
+
+ +
+ + + +
+
@Localizer["PanelTitle"]
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResourceProperties.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResourceProperties.cshtml new file mode 100644 index 000000000..d10e18685 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResourceProperties.cshtml @@ -0,0 +1,112 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.IdentityResourcePropertiesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+ +
+ +

@Localizer["PageTitle"]

+ +
+ + + + + + + +
+
@Localizer["PanelTitleNew"]
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+
+
+
+
+
+ +
+
+
+
@Localizer["PanelTitle"]
+
+
+ + + + + + + + + + @foreach (var identityResourceProperty in Model.IdentityResourceProperties) + { + + + + + + } + +
@Localizer["TableKey"]@Localizer["TableValue"]
@identityResourceProperty.Key@identityResourceProperty.Value@Localizer["TableButtonRemove"]
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "IdentityResourceProperties", PageSize = Model.PageSize, TotalCount = Model.TotalCount }) +
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResourcePropertyDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResourcePropertyDelete.cshtml new file mode 100644 index 000000000..cb837597c --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResourcePropertyDelete.cshtml @@ -0,0 +1,67 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.IdentityResourcePropertiesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ + + +
+

@Localizer["PageTitle"]

+ + + + + +
+
@Localizer["PanelTitle"]
+
+ +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResources.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResources.cshtml new file mode 100644 index 000000000..248a0b937 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Configuration/IdentityResources.cshtml @@ -0,0 +1,58 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Configuration.IdentityResourcesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+

@Localizer["PageTitle"]

+
+ + + +
+ @await Html.PartialAsync("Common/Search", new Search { Action = "IdentityResources", Controller = "Configuration" }) +
+
+ +
+
+
+ + + + + + + + + + @foreach (var identity in Model.IdentityResources) + { + + + + + + } + +
@Localizer["TableName"]
@Localizer["TableButtonEdit"]@identity.Name + +
+
+
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "IdentityResources", PageSize = Model.PageSize, TotalCount = Model.TotalCount, EnableSearch = true, Search = ViewBag.Search }) +
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Grant/PersistedGrant.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Grant/PersistedGrant.cshtml new file mode 100644 index 000000000..9275eee36 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Grant/PersistedGrant.cshtml @@ -0,0 +1,100 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Grant +@using Skoruba.IdentityServer4.Admin.UI.Helpers +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model PersistedGrantsDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+

@Localizer["PageTitle"]

+
+
+ +
+ + @Localizer["ButtonDeleteAll"] + + + + +
+
+ + + + + + + + + + + + + + + + + + + @foreach (var persistedGrant in Model.PersistedGrants) + { + + + + + + + + + + + + + } + +
@Localizer["TableSubjectId"]@Localizer["TableType"]@Localizer["TableExpiration"]@Localizer["TableData"]@Localizer["TableClient"]@Localizer["TableDescription"]@Localizer["TableSessionId"]@Localizer["TableCreationTime"]@Localizer["TableConsumedTime"]
@persistedGrant.SubjectId@persistedGrant.Type@persistedGrant.Expiration@persistedGrant.Data@persistedGrant.ClientId@persistedGrant.Description@persistedGrant.SessionId@persistedGrant.ConsumedTime@persistedGrant.CreationTime
+
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "PersistedGrant", PageSize = Model.PageSize, TotalCount = Model.TotalCount }) +
+
+ + + +
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Grant/PersistedGrantDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Grant/PersistedGrantDelete.cshtml new file mode 100644 index 000000000..4bf10b47a --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Grant/PersistedGrantDelete.cshtml @@ -0,0 +1,63 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Grant +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model PersistedGrantDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+

@Localizer["PageTitle"]

+
+
+ +
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +
@Localizer["TableSubjectId"]@Localizer["TableType"]@Localizer["TableExpiration"]@Localizer["TableData"]@Localizer["TableClient"]
@Model.SubjectId@Model.Type@Model.Expiration@Model.Data@Model.ClientId
+
+
+ +
+
+ +
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Grant/PersistedGrants.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Grant/PersistedGrants.cshtml new file mode 100644 index 000000000..e01ee9e71 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Grant/PersistedGrants.cshtml @@ -0,0 +1,54 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Grant +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model PersistedGrantsDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+

@Localizer["PageTitle"]

+
+
+ +
+
+ @await Html.PartialAsync("Common/Search", new Search { Action = "PersistedGrants", Controller = "Grant" }) +
+
+ +
+
+ + + + + + + + + + + @foreach (var persistedGrant in Model.PersistedGrants) + { + + + + + + } + +
@Localizer["TableSubjectId"]@Localizer["TableSubjectName"]
@Localizer["TableButtonDetail"]@persistedGrant.SubjectId@persistedGrant.SubjectName
+
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager() { Action = "PersistedGrants", PageSize = Model.PageSize, TotalCount = Model.TotalCount }) +
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin/Views/Home/Error.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Home/Error.cshtml similarity index 100% rename from src/Skoruba.IdentityServer4.Admin/Views/Home/Error.cshtml rename to src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Home/Error.cshtml diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Home/Index.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Home/Index.cshtml new file mode 100644 index 000000000..21028237e --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Home/Index.cshtml @@ -0,0 +1,122 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@inject AdminConfiguration AdminConfiguration +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = AdminConfiguration.PageTitle; + Layout = "_Layout"; +} + +
+

@AdminConfiguration.PageTitle

+

@Localizer["PageSubTitle"]

+
+ + +
+ +
+
+

@Localizer["ButtonClients"]

+
+ +
+ +
+
+

@Localizer["ButtonIdentityClients"]

+
+ +
+ +
+
+

@Localizer["ButtonApiResources"]

+
+ +
+ + +
+
+

@Localizer["ButtonApiScopes"]

+
+ +
+
+ + +
+ +
+
+

@Localizer["ButtonPersistedGrants"]

+
+ +
+ +
+
+

@Localizer["ButtonUsers"]

+
+ +
+ +
+
+

@Localizer["ButtonRoles"]

+
+ +
+ + +
+
+

@Localizer["ButtonAuditLogs"]

+
+ +
+
+ diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/Role.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/Role.cshtml new file mode 100644 index 000000000..944c6e9e7 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/Role.cshtml @@ -0,0 +1,70 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IRoleDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["Title"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+

@Localizer["Title"]

+
+
+ + +
+ +
+ + @if (!Model.IsDefaultId()) + { + + + } + + + +
+
@Localizer["Title"]
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin/Views/Identity/User/Section/Label.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/Role/Section/Label.cshtml similarity index 100% rename from src/Skoruba.IdentityServer4.Admin/Views/Identity/User/Section/Label.cshtml rename to src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/Role/Section/Label.cshtml diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/RoleClaims.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/RoleClaims.cshtml new file mode 100644 index 000000000..25eb3a1fe --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/RoleClaims.cshtml @@ -0,0 +1,134 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IRoleClaimsDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + + + +
+
+ +
+ +
+ +
+

@Localizer["PageTitle"]

+ +
+ + + +
+
@Localizer["PanelTitleNew"]
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+
+
+ +
+
+
+ +
+
+
+
@Localizer["PanelTitle"]
+
+ +
+ + + + + + + + + + @foreach (var client in Model.Claims) + { + + + + + + } + +
@Localizer["TableType"]@Localizer["TableValue"]
@client.ClaimType@client.ClaimValue@Localizer["TableButtonRemove"]
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "RoleClaims", PageSize = Model.PageSize, TotalCount = Model.TotalCount }) +
+
+
+
+
+
+ +@section scripts + { + +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/RoleClaimsDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/RoleClaimsDelete.cshtml new file mode 100644 index 000000000..6a6f6431f --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/RoleClaimsDelete.cshtml @@ -0,0 +1,69 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IRoleClaimsDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ + + +
+

@Localizer["PageTitle"]

+ + + + + + +
+
@Localizer["PanelTitle"]
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/RoleDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/RoleDelete.cshtml new file mode 100644 index 000000000..67289be13 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/RoleDelete.cshtml @@ -0,0 +1,56 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IRoleDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+

@Localizer["PageTitle"]

+
+
+ +
+ + + + +
+
@Localizer["PageTitle"]
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/RoleUsers.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/RoleUsers.cshtml new file mode 100644 index 000000000..66b30f65a --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/RoleUsers.cshtml @@ -0,0 +1,86 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IUsersDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["Title"]; + Layout = "_Layout"; + var roleId = Context.Request.Query["roleId"]; +} + +
+
+ +
+ +
+

@Localizer["Title"] (@ViewData["RoleName"])

+
+
+ +
+
+
+
+
+ + +
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+ + + + + + + + + + + + + @foreach (var user in Model.Users) + { + + + + + + + + } + +
@Localizer["UserId"]@Localizer["UserName"]@Localizer["Email"]
+ + @user.Id@user.UserName@user.Email + +
+
+
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "RoleUsers", PageSize = Model.PageSize, TotalCount = Model.TotalCount, EnableSearch = true, Search = ViewBag.Search }) +
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/Roles.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/Roles.cshtml new file mode 100644 index 000000000..c62291282 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/Roles.cshtml @@ -0,0 +1,65 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IRolesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+

@Localizer["PageTitle"]

+
+
+ + + +
+
+ @await Html.PartialAsync("Common/Search", new Search { Action = "Roles", Controller = "Identity" }) +
+
+ +
+
+
+ + + + + + + + + + @foreach (var role in Model.Roles) + { + + + + + + } + +
@Localizer["TableName"]
+ @Localizer["TableButtonEdit"] + @Localizer["TableButtonUsers"] + @role.Name + +
+
+
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "Roles", PageSize = Model.PageSize, TotalCount = Model.TotalCount }) +
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/User/Section/Label.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/User/Section/Label.cshtml new file mode 100644 index 000000000..c5be5ac23 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/User/Section/Label.cshtml @@ -0,0 +1,7 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@model string +@inject IViewLocalizer Localizer + + +@Localizer[$"{Model}_Label"] + \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserChangePassword.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserChangePassword.cshtml new file mode 100644 index 000000000..f200b297a --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserChangePassword.cshtml @@ -0,0 +1,81 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IUserChangePasswordDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+ +
+

@Localizer["PageTitle"]

+ +
+ + + + +
+
@Localizer["PanelTitle"]
+
+ + +
+ +
+ +

@Model.UserName

+
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserClaims.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserClaims.cshtml new file mode 100644 index 000000000..604866221 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserClaims.cshtml @@ -0,0 +1,133 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IUserClaimsDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+ +
+

@Localizer["PageTitle"]

+ +
+ + + + +
+
@Localizer["PanelTitleNew"]
+
+ + +
+ +
+ + + + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+
+
+ +
+
+
+ +
+
+
+
@Localizer["PanelTitle"]
+
+ +
+ + + + + + + + + + @foreach (var client in Model.Claims) + { + + + + + + } + +
@Localizer["TableType"]@Localizer["TableValue"]
@client.ClaimType@client.ClaimValue@Localizer["TableButtonRemove"]
+
+
+
+ @await Html.PartialAsync("Common/Pager", new Pager {Action = "UserClaims", PageSize = Model.PageSize, TotalCount = Model.TotalCount}) +
+
+
+
+
+
+ +@section scripts + { + +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserClaimsDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserClaimsDelete.cshtml new file mode 100644 index 000000000..314981d04 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserClaimsDelete.cshtml @@ -0,0 +1,69 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IUserClaimsDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ + + +
+

@Localizer["PageTitle"]

+ + + + + + + +
+
@Localizer["PanelTitle"]
+
+ +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserDelete.cshtml new file mode 100644 index 000000000..f9b82386f --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserDelete.cshtml @@ -0,0 +1,53 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IUserDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+
+ +
+ +

@Localizer["PageTitle"]

+ + + +
+
@Localizer["PageTitle"]
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserProfile.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserProfile.cshtml new file mode 100644 index 000000000..7996098d0 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserProfile.cshtml @@ -0,0 +1,183 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IUserDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+

@Localizer["PageTitle"]

+
+
+ +
+ +
+ + @if (!Model.IsDefaultId()) + { + + + } + + + + +
+
@Localizer["PanelTitle"]
+
+ +
+
+ +
+
+ +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ +
+
+ + +
+ +
+
+ +
+
+
+
+
+
+ + +
+ +
+ +
+
+
+
+
+
+
+ +@section scripts + { + +} \ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserProviders.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserProviders.cshtml new file mode 100644 index 000000000..70e87bbbe --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserProviders.cshtml @@ -0,0 +1,50 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IUserProvidersDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+ +
+ +
+ +
+

@Localizer["PageTitle"]

+ +
+ + + + + + + + + + + @foreach (var provider in Model.Providers) + { + + + + + + + } + +
@Localizer["TableLoginProvider"]@Localizer["TableProviderDisplayName"]@Localizer["TableProviderKey"]
@provider.LoginProvider@provider.ProviderDisplayName@provider.ProviderKey@Localizer["TableButtonRemove"]
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserProvidersDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserProvidersDelete.cshtml new file mode 100644 index 000000000..2bf9d089c --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserProvidersDelete.cshtml @@ -0,0 +1,81 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IUserProviderDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["PageTitle"]; + Layout = "_Layout"; +} + +
+
+ + + +
+

@Localizer["PageTitle"]

+ + + + +
+
@Localizer["PanelTitle"]
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserRoles.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserRoles.cshtml new file mode 100644 index 000000000..7ea14fbe5 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserRoles.cshtml @@ -0,0 +1,96 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IUserRolesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["Title"]; + Layout = "_Layout"; +} + +
+
+ +
+ +
+ +
+

@Localizer["Title"]

+ +
+ + + + +
+
@Localizer["SubTitle"]
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+ +
+
+
+ +
+
+
+
@Localizer["TitleRoles"]
+
+ +
+ + + + + + + + + @foreach (var role in Model.Roles) + { + + + + + } + +
@Localizer["RoleName"]
@role.Name@Localizer["ActionRemoveRole"]
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "UserRoles", PageSize = Model.PageSize, TotalCount = Model.TotalCount }) +
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserRolesDelete.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserRolesDelete.cshtml new file mode 100644 index 000000000..38046eb2e --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/UserRolesDelete.cshtml @@ -0,0 +1,62 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IUserRolesDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["Title"]; + Layout = "_Layout"; +} + +
+
+ + + + +
+ +

@Localizer["Title"]

+ + + + + + + +
+
@Localizer["SubTitle"]
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/Users.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/Users.cshtml new file mode 100644 index 000000000..554f80130 --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Identity/Users.cshtml @@ -0,0 +1,73 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Identity.Dtos.Identity.Interfaces.IUsersDto +@inject IViewLocalizer Localizer + +@{ + ViewBag.Title = Localizer["Title"]; + Layout = "_Layout"; +} + +
+
+

@Localizer["Title"]

+
+
+ + + +
+
+ @await Html.PartialAsync("Common/Search", new Search() { Action = "Users", Controller = "Identity" }) +
+
+ +
+
+
+ + + + + + + + + + + + + + @foreach (var user in Model.Users) + { + + + + + + + + + } + +
@Localizer["UserId"]@Localizer["UserName"]@Localizer["Email"]
+ @Localizer["ActionEditUser"] + + + @user.Id@user.UserName@user.Email + +
+
+
+
+ +
+
+ @await Html.PartialAsync("Common/Pager", new Pager { Action = "Users", PageSize = Model.PageSize, TotalCount = Model.TotalCount, EnableSearch = true, Search = ViewBag.Search }) +
+
\ No newline at end of file diff --git a/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Log/AuditLog.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Log/AuditLog.cshtml new file mode 100644 index 000000000..5b482b74a --- /dev/null +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Log/AuditLog.cshtml @@ -0,0 +1,147 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Log.AuditLogsDto +@inject IViewLocalizer Localizer +@{ + ViewData["Title"] = Localizer["Audit Log"]; +} + +
+ +
+
+

@ViewData["Title"]

+
+
+ +
+ + + + +
+ +
+
+
+
+
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+ + + + + + + + + + + + + @foreach (var auditLog in Model.Logs) + { + + + + + + + + + + + + } + +
@Localizer["Event"]@Localizer["Source"]@Localizer["Subject"]@Localizer["Action"]@Localizer["Created"]
@Localizer["Detail"]@auditLog.Event@auditLog.Source + @auditLog.Created +
+
+
+
+ +
+
+ @await Html.PartialAsync("Common/PagerDynamic", new Pager { Action = Url.Action("AuditLog", "Log", new { Area = CommonConsts.AdminUIArea }), PageSize = Model.PageSize, TotalCount = Model.TotalCount, EnableSearch = true, Search = ViewBag.Search }) +
+
+ + +
diff --git a/src/Skoruba.IdentityServer4.Admin/Views/Log/ErrorsLog.cshtml b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Log/ErrorsLog.cshtml similarity index 90% rename from src/Skoruba.IdentityServer4.Admin/Views/Log/ErrorsLog.cshtml rename to src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Log/ErrorsLog.cshtml index d7fff1d4c..14700cbfc 100644 --- a/src/Skoruba.IdentityServer4.Admin/Views/Log/ErrorsLog.cshtml +++ b/src/Skoruba.IdentityServer4.Admin.UI/Areas/AdminUI/Views/Log/ErrorsLog.cshtml @@ -1,6 +1,7 @@ @using Microsoft.AspNetCore.Mvc.Localization @using Skoruba.IdentityServer4.Admin.BusinessLogic.Shared.Dtos.Common -@using Skoruba.IdentityServer4.Admin.Helpers +@using Skoruba.IdentityServer4.Admin.UI.Configuration.Constants +@using Skoruba.IdentityServer4.Admin.UI.Helpers @model Skoruba.IdentityServer4.Admin.BusinessLogic.Dtos.Log.LogsDto @inject IViewLocalizer Localizer @@ -9,13 +10,18 @@ Layout = "_Layout"; } -

@Localizer["PageTitle"]

+
+
+

@Localizer["PageTitle"]

+
+
+
-
+ - +