diff --git a/.github/workflows/check-dependencies.yml b/.github/workflows/check-dependencies.yml index 3862920ff..9dee36876 100644 --- a/.github/workflows/check-dependencies.yml +++ b/.github/workflows/check-dependencies.yml @@ -33,7 +33,7 @@ jobs: - name: Setup .NET Core SDK uses: actions/setup-dotnet@v1.7.2 with: - dotnet-version: '5.0.103' + dotnet-version: '5.0.200' # Run update depencies script - name: Update dependencies run: ./update-dependencies.ps1 diff --git a/.github/workflows/maintain-2.0.0.yml b/.github/workflows/maintain-2.0.0.yml deleted file mode 100644 index 6bc5f5910..000000000 --- a/.github/workflows/maintain-2.0.0.yml +++ /dev/null @@ -1,44 +0,0 @@ -# Update all depencies each days if needed - -name: Release 2.0 Dependencies - -# Controls when the action will run. -on: - # Triggers the workflow at 02:00 each days - schedule: - - cron: '0 2 * * *' - # allow to launch the job manually - workflow_dispatch: - -jobs: - # This workflow contains a single job called "build" - build: - # The type of runner that the job will run on - runs-on: windows-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checkout the branch fix/dependencies with the PAT - - uses: actions/checkout@v2 - with: - ref: maintain/1.0.0 - token: ${{ secrets.PAT }} - fetch-depth: 0 - - name: Merge preview/1.0.0 - continue-on-error: true - run: | - git config user.name github-actions - git config user.email github-actions@github.com - git merge origin/preview/2.0.0 --allow-unrelated-histories - # Setup .NET Core SDK - - name: Setup .NET Core SDK - uses: actions/setup-dotnet@v1.7.2 - with: - dotnet-version: '5.0.103' - # Run update depencies script - - name: Update dependencies - run: ./update-dependencies.ps1 - env: - SRC_BRANCH: maintain/1.0.0 - DEST_BRANCH: preview/2.0.0 - GITHUB_TOKEN: ${{ secrets.PAT }} diff --git a/.sonarlint/TheIdServer.slconfig b/.sonarlint/TheIdServer.slconfig new file mode 100644 index 000000000..23c72844b --- /dev/null +++ b/.sonarlint/TheIdServer.slconfig @@ -0,0 +1,15 @@ +{ + "ServerUri": "https://sonarcloud.io/", + "Organization": { + "Key": "aguacongas", + "Name": "Olivier Lefebvre" + }, + "ProjectKey": "aguacongas_TheIdServer", + "ProjectName": "TheIdServer", + "Profiles": { + "CSharp": { + "ProfileKey": "AW8e9NVJZPoDbtkGSYCm", + "ProfileTimestamp": "2021-03-03T08:15:42Z" + } + } +} \ No newline at end of file diff --git a/.sonarlint/aguacongas_theidserver/CSharp/SonarLint.xml b/.sonarlint/aguacongas_theidserver/CSharp/SonarLint.xml new file mode 100644 index 000000000..21acd70e2 --- /dev/null +++ b/.sonarlint/aguacongas_theidserver/CSharp/SonarLint.xml @@ -0,0 +1,89 @@ + + + + + sonar.cs.analyzeGeneratedCode + false + + + sonar.cs.file.suffixes + .cs + + + sonar.cs.ignoreHeaderComments + true + + + sonar.cs.roslyn.ignoreIssues + false + + + + + S107 + + + max + 7 + + + + + S110 + + + max + 5 + + + + + S1479 + + + maximum + 30 + + + + + S2342 + + + flagsAttributeFormat + ^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?s$ + + + format + ^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$ + + + + + S2436 + + + max + 2 + + + maxMethod + 3 + + + + + S3776 + + + propertyThreshold + 3 + + + threshold + 15 + + + + + \ No newline at end of file diff --git a/.sonarlint/aguacongas_theidservercsharp.ruleset b/.sonarlint/aguacongas_theidservercsharp.ruleset new file mode 100644 index 000000000..4df530fd8 --- /dev/null +++ b/.sonarlint/aguacongas_theidservercsharp.ruleset @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 45690fe62..bc2e22559 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,47 @@ +# [2.2.0](https://github.com/Aguafrommars/TheIdServer/compare/2.1.0...2.2.0) (2021-03-26) + + +### Bug Fixes + +* remove obsolets packages ([4429976](https://github.com/Aguafrommars/TheIdServer/commit/44299760e1422b654e4cc21c2be32abdda3b4327)) +* set valid audience ([86191d7](https://github.com/Aguafrommars/TheIdServer/commit/86191d7d17ffec066fa66264d1feaad76f082560)), closes [#388](https://github.com/Aguafrommars/TheIdServer/issues/388) +* switch to Azure package ([baf95bf](https://github.com/Aguafrommars/TheIdServer/commit/baf95bf68a798d22f975a9e27c4fcea0fb9aa809)) +* update packages ([f7ffd29](https://github.com/Aguafrommars/TheIdServer/commit/f7ffd29a3b97462cdf1d7a74a9b1432ae7ecc764)) +* update packages ([e1803f6](https://github.com/Aguafrommars/TheIdServer/commit/e1803f6c1dee112e9a8ab294c64ab97d8e92fb6b)) +* update packages ([7e5ac1e](https://github.com/Aguafrommars/TheIdServer/commit/7e5ac1e14325c6dbe8fed71bb57c49a27c3a4608)) +* update packages ([b32882d](https://github.com/Aguafrommars/TheIdServer/commit/b32882d0f686eb6982c48ce562fb273970e8e5f4)) +* update packages ([a5e0441](https://github.com/Aguafrommars/TheIdServer/commit/a5e0441f3ae78a6fb0662b46ca547d50fbb39b34)) +* update packages ([3389cfc](https://github.com/Aguafrommars/TheIdServer/commit/3389cfc4ed60fc06df2b5362729cccfe01ef01d0)) +* update packages ([ef04e93](https://github.com/Aguafrommars/TheIdServer/commit/ef04e9345ab3b5c4a2822431cbf04fbd2da932fd)) +* update packages ([10b328a](https://github.com/Aguafrommars/TheIdServer/commit/10b328ad11df6c9b5500481996c8573c61f5d4c4)) +* update packages ([41594b1](https://github.com/Aguafrommars/TheIdServer/commit/41594b1fbe22eecdfd604cf0db9455d2f5ea4578)) +* update packages ([2ed76e8](https://github.com/Aguafrommars/TheIdServer/commit/2ed76e8268af630c004fa7f0fc283d2056905bd9)) +* update packages ([7bcb601](https://github.com/Aguafrommars/TheIdServer/commit/7bcb601679cb29dbc39e961f4ddc29a56fc5f7d5)) +* update packages ([0d5fd4c](https://github.com/Aguafrommars/TheIdServer/commit/0d5fd4c7bd83c1db4bc96d3ccaf572f5edd53727)) +* update packages ([e1d3a71](https://github.com/Aguafrommars/TheIdServer/commit/e1d3a71613a0925bfc921632a04e16d8c8b85bce)) +* update packages ([f95dc02](https://github.com/Aguafrommars/TheIdServer/commit/f95dc023021cd3b03cfd8e7f64551fac22df8751)) +* update packages ([4eb238a](https://github.com/Aguafrommars/TheIdServer/commit/4eb238ae29fe92a8a500701ce356dbf031b6a248)) +* update packages ([e6357c5](https://github.com/Aguafrommars/TheIdServer/commit/e6357c552318ae5afbafa03a0a8636cb1877abc1)) +* update packages ([50da361](https://github.com/Aguafrommars/TheIdServer/commit/50da361318032672373e445854dcded449b7942c)) +* update packages ([87c81c9](https://github.com/Aguafrommars/TheIdServer/commit/87c81c915c2076b40843566e6953b5ea5689fd08)) +* update packages ([6f1f2aa](https://github.com/Aguafrommars/TheIdServer/commit/6f1f2aa085b2c305f9c13ab145f5b6da131d25e1)) +* update packages ([5032108](https://github.com/Aguafrommars/TheIdServer/commit/503210829eb1d09d8ed36f66651f5b72162af2f8)) +* update packages ([5d13a7a](https://github.com/Aguafrommars/TheIdServer/commit/5d13a7a6149fe5ed031283bcaf977dabf8bbb3c7)) +* update packages ([83aba78](https://github.com/Aguafrommars/TheIdServer/commit/83aba78a0df12629d7993d3dc1b8d1a350901b35)) +* update packages ([5907af8](https://github.com/Aguafrommars/TheIdServer/commit/5907af8738f468cb577c04030f161b799235abc5)) +* update packages ([05dfb21](https://github.com/Aguafrommars/TheIdServer/commit/05dfb21616951e6a25523ce91752d5e85f41dc8d)) +* update packages ([6950511](https://github.com/Aguafrommars/TheIdServer/commit/6950511e1cc74b70e5dab478a1163650a51698db)) +* update packages ([c912af1](https://github.com/Aguafrommars/TheIdServer/commit/c912af195a5f9c3c7865bca0260073966c0b29f3)) +* update packages ([153175d](https://github.com/Aguafrommars/TheIdServer/commit/153175de8d4aa49bf610ed62c5cb146138a717cc)) +* update packages ([4ef29fb](https://github.com/Aguafrommars/TheIdServer/commit/4ef29fb9f888dbcc9274f746228a7fb6b36da686)) +* update packages ([2837ba1](https://github.com/Aguafrommars/TheIdServer/commit/2837ba184add421b48be970bb9d6d695289434ca)) +* update packages ([42258f7](https://github.com/Aguafrommars/TheIdServer/commit/42258f796984bbc1236ca7ec8bee783c6892a62d)) + + +### Features + +* log user name ([32fabc2](https://github.com/Aguafrommars/TheIdServer/commit/32fabc2020f89eb2cbe66bc154b2853791383cef)) + # [2.1.0](https://github.com/Aguafrommars/TheIdServer/compare/2.0.4...2.1.0) (2020-12-18) diff --git a/TheIdServer.sln b/TheIdServer.sln index 673e0c919..e8a0148c5 100644 --- a/TheIdServer.sln +++ b/TheIdServer.sln @@ -181,6 +181,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aguacongas.TheIdServer.Blaz EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aguacongas.TheIdServer.BlazorApp.Pages.Users", "src\BlazorApp\Aguacongas.TheIdServer.BlazorApp.Pages.Users\Aguacongas.TheIdServer.BlazorApp.Pages.Users.csproj", "{E01CF9AF-CAB1-4C46-A9B8-12AB295D4A85}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aguacongas.IdentityServer.RavenDb.Store", "src\IdentityServer\Aguacongas.IdentityServer.RavenDb.Store\Aguacongas.IdentityServer.RavenDb.Store.csproj", "{D887CCE0-A999-4CE8-92B1-AE83587CDC2F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aguacongas.IdentityServer.RavenDb.Store.Test", "test\Aguacongas.IdentityServer.RavenDb.Store.Test\Aguacongas.IdentityServer.RavenDb.Store.Test.csproj", "{C1560F0F-7B46-4DF1-AC04-01AF1E884DDB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -971,6 +975,30 @@ Global {E01CF9AF-CAB1-4C46-A9B8-12AB295D4A85}.Release|x64.Build.0 = Release|Any CPU {E01CF9AF-CAB1-4C46-A9B8-12AB295D4A85}.Release|x86.ActiveCfg = Release|Any CPU {E01CF9AF-CAB1-4C46-A9B8-12AB295D4A85}.Release|x86.Build.0 = Release|Any CPU + {D887CCE0-A999-4CE8-92B1-AE83587CDC2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D887CCE0-A999-4CE8-92B1-AE83587CDC2F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D887CCE0-A999-4CE8-92B1-AE83587CDC2F}.Debug|x64.ActiveCfg = Debug|Any CPU + {D887CCE0-A999-4CE8-92B1-AE83587CDC2F}.Debug|x64.Build.0 = Debug|Any CPU + {D887CCE0-A999-4CE8-92B1-AE83587CDC2F}.Debug|x86.ActiveCfg = Debug|Any CPU + {D887CCE0-A999-4CE8-92B1-AE83587CDC2F}.Debug|x86.Build.0 = Debug|Any CPU + {D887CCE0-A999-4CE8-92B1-AE83587CDC2F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D887CCE0-A999-4CE8-92B1-AE83587CDC2F}.Release|Any CPU.Build.0 = Release|Any CPU + {D887CCE0-A999-4CE8-92B1-AE83587CDC2F}.Release|x64.ActiveCfg = Release|Any CPU + {D887CCE0-A999-4CE8-92B1-AE83587CDC2F}.Release|x64.Build.0 = Release|Any CPU + {D887CCE0-A999-4CE8-92B1-AE83587CDC2F}.Release|x86.ActiveCfg = Release|Any CPU + {D887CCE0-A999-4CE8-92B1-AE83587CDC2F}.Release|x86.Build.0 = Release|Any CPU + {C1560F0F-7B46-4DF1-AC04-01AF1E884DDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C1560F0F-7B46-4DF1-AC04-01AF1E884DDB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1560F0F-7B46-4DF1-AC04-01AF1E884DDB}.Debug|x64.ActiveCfg = Debug|Any CPU + {C1560F0F-7B46-4DF1-AC04-01AF1E884DDB}.Debug|x64.Build.0 = Debug|Any CPU + {C1560F0F-7B46-4DF1-AC04-01AF1E884DDB}.Debug|x86.ActiveCfg = Debug|Any CPU + {C1560F0F-7B46-4DF1-AC04-01AF1E884DDB}.Debug|x86.Build.0 = Debug|Any CPU + {C1560F0F-7B46-4DF1-AC04-01AF1E884DDB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C1560F0F-7B46-4DF1-AC04-01AF1E884DDB}.Release|Any CPU.Build.0 = Release|Any CPU + {C1560F0F-7B46-4DF1-AC04-01AF1E884DDB}.Release|x64.ActiveCfg = Release|Any CPU + {C1560F0F-7B46-4DF1-AC04-01AF1E884DDB}.Release|x64.Build.0 = Release|Any CPU + {C1560F0F-7B46-4DF1-AC04-01AF1E884DDB}.Release|x86.ActiveCfg = Release|Any CPU + {C1560F0F-7B46-4DF1-AC04-01AF1E884DDB}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1046,6 +1074,8 @@ Global {5C362E5C-BF03-48C4-ABEC-FEBA0F6ECAD2} = {8A3B91E5-02A3-42F0-B2E7-E419B5086FFA} {36AAF482-3FAE-4633-80AA-B7525A158760} = {8A3B91E5-02A3-42F0-B2E7-E419B5086FFA} {E01CF9AF-CAB1-4C46-A9B8-12AB295D4A85} = {8A3B91E5-02A3-42F0-B2E7-E419B5086FFA} + {D887CCE0-A999-4CE8-92B1-AE83587CDC2F} = {DF368D6C-D11F-49F9-BF41-090AE1D10C6D} + {C1560F0F-7B46-4DF1-AC04-01AF1E884DDB} = {DE50F426-4409-4573-8502-93364ED12E0C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5283BE0B-F6F2-4458-B12F-64C78CFF8CBA} diff --git a/appveyor.yml b/appveyor.yml index 0655a0d09..e5dc8853c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,7 +12,7 @@ image: environment: GH_TOKEN: secure: 0NJdORJRFjpB0dwUYv7bVNsbkldkoBhnvWik/CTOwAF/k9kP+/uTWMFnDcpEpt8E - donetsdk: 5.0.103 + donetsdk: 5.0.200 JAVA_HOME: C:\Program Files\Java\jdk14 PATH: $(JAVA_HOME)\bin;$(PATH) init: diff --git a/build.ps1 b/build.ps1 index bacbcd19d..b376d49c7 100644 --- a/build.ps1 +++ b/build.ps1 @@ -22,7 +22,7 @@ Write-Host "dotnet sonarscanner begin /k:aguacongas_TheIdServer -o:aguacongas -d dotnet sonarscanner begin /k:aguacongas_TheIdServer -o:aguacongas -d:sonar.host.url=https://sonarcloud.io -d:sonar.login=$env:sonarqube -d:sonar.coverageReportPaths=coverage\SonarQube.xml $prArgs -v:$env:Version Write-Host "dotnet test -c Release --settings coverletArgs.runsettings --filter FullyQualifiedName!~Pages & FullyQualifiedName!~UserStore" -dotnet test -c Release --settings coverletArgs.runsettings --filter "FullyQualifiedName!~UserStore" +dotnet test -c Release --collect:"XPlat Code Coverage" --settings coverletArgs.runsettings --filter "FullyQualifiedName!~Aguacongas.TheIdServer.Identity.IntegrationTest" -v q if ($LASTEXITCODE -ne 0) { $result = $LASTEXITCODE diff --git a/global.json b/global.json index ed8ca68ff..29cf2c4d2 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "5.0.100" + "version": "5.0.200" } - } \ No newline at end of file + } diff --git a/publish.ps1 b/publish.ps1 index a29e505eb..d75e8ef3d 100644 --- a/publish.ps1 +++ b/publish.ps1 @@ -12,12 +12,12 @@ Get-ChildItem -Path src -rec ` } } -dotnet msbuild src\Aguacongas.TheIdServer\Aguacongas.TheIdServer.csproj -t:Publish -p:Configuration=Release -p:OutputPath=$path\artifacts\Aguacongas.TheIdServer -p:Version=$env:Version -p:FileVersion=$fileversion +dotnet msbuild src\Aguacongas.TheIdServer\Aguacongas.TheIdServer.csproj -t:Publish -p:Configuration=Release -p:OutputPath=$path\artifacts\Aguacongas.TheIdServer -p:Version=$env:Version -p:FileVersion=$fileversion -noConsoleLogger -nr:false if ($LASTEXITCODE -ne 0) { throw "publis failed src/Aguacongas.TheIdServer/Aguacongas.TheIdServer.csproj" } -dotnet msbuild src\Aguacongas.TheIdServer.BlazorApp\Aguacongas.TheIdServer.BlazorApp.csproj -t:Publish -p:Configuration=Release -p:OutputPath=$path\artifacts\Aguacongas.TheIdServer.BlazorApp -p:Version=$env:Version -p:FileVersion=$fileversion +dotnet msbuild src\Aguacongas.TheIdServer.BlazorApp\Aguacongas.TheIdServer.BlazorApp.csproj -t:Publish -p:Configuration=Release -p:OutputPath=$path\artifacts\Aguacongas.TheIdServer.BlazorApp -p:Version=$env:Version -p:FileVersion=$fileversion -noConsoleLogger -nr:false if ($LASTEXITCODE -ne 0) { throw "publish failed src/Aguacongas.TheIdServer.BlazorApp/Aguacongas.TheIdServer.BlazorApp.csproj" } diff --git a/sample/Aguacongas.TheIdServer.ApiSample/Aguacongas.TheIdServer.ApiSample.csproj b/sample/Aguacongas.TheIdServer.ApiSample/Aguacongas.TheIdServer.ApiSample.csproj index c007468fb..1d523b185 100644 --- a/sample/Aguacongas.TheIdServer.ApiSample/Aguacongas.TheIdServer.ApiSample.csproj +++ b/sample/Aguacongas.TheIdServer.ApiSample/Aguacongas.TheIdServer.ApiSample.csproj @@ -19,7 +19,7 @@ - + diff --git a/sample/Aguacongas.TheIdServer.ClientCredentialSample/Aguacongas.TheIdServer.ClientCredentialSample.csproj b/sample/Aguacongas.TheIdServer.ClientCredentialSample/Aguacongas.TheIdServer.ClientCredentialSample.csproj index 12913d70b..8312eabbe 100644 --- a/sample/Aguacongas.TheIdServer.ClientCredentialSample/Aguacongas.TheIdServer.ClientCredentialSample.csproj +++ b/sample/Aguacongas.TheIdServer.ClientCredentialSample/Aguacongas.TheIdServer.ClientCredentialSample.csproj @@ -18,7 +18,7 @@ - + diff --git a/sample/Aguacongas.TheIdServer.DeviceFlowSample/Aguacongas.TheIdServer.DeviceFlowSample.csproj b/sample/Aguacongas.TheIdServer.DeviceFlowSample/Aguacongas.TheIdServer.DeviceFlowSample.csproj index ad0b0e7b9..f3c4ed82e 100644 --- a/sample/Aguacongas.TheIdServer.DeviceFlowSample/Aguacongas.TheIdServer.DeviceFlowSample.csproj +++ b/sample/Aguacongas.TheIdServer.DeviceFlowSample/Aguacongas.TheIdServer.DeviceFlowSample.csproj @@ -18,8 +18,8 @@ - - + + diff --git a/sample/Aguacongas.TheIdServer.MvcClient/Aguacongas.TheIdServer.MvcClient.csproj b/sample/Aguacongas.TheIdServer.MvcClient/Aguacongas.TheIdServer.MvcClient.csproj index 991c727c2..1d60a59f0 100644 --- a/sample/Aguacongas.TheIdServer.MvcClient/Aguacongas.TheIdServer.MvcClient.csproj +++ b/sample/Aguacongas.TheIdServer.MvcClient/Aguacongas.TheIdServer.MvcClient.csproj @@ -17,10 +17,10 @@ - - + + - + diff --git a/sample/Aguacongas.TheIdentityServer.SpaSample/Aguacongas.TheIdentityServer.SpaSample.csproj b/sample/Aguacongas.TheIdentityServer.SpaSample/Aguacongas.TheIdentityServer.SpaSample.csproj index 5ef792a52..51c929769 100644 --- a/sample/Aguacongas.TheIdentityServer.SpaSample/Aguacongas.TheIdentityServer.SpaSample.csproj +++ b/sample/Aguacongas.TheIdentityServer.SpaSample/Aguacongas.TheIdentityServer.SpaSample.csproj @@ -19,10 +19,10 @@ - - - - + + + + diff --git a/sample/Kubernetes/TheIdServer-public-configmap.yaml b/sample/Kubernetes/TheIdServer-public-configmap.yaml index 9d099baa0..ad82b0932 100644 --- a/sample/Kubernetes/TheIdServer-public-configmap.yaml +++ b/sample/Kubernetes/TheIdServer-public-configmap.yaml @@ -12,11 +12,11 @@ data: DisableStrictSsl: "true" EnableOpenApiDoc: "false" IdentityServer__Key__Type: KeysRotation - IdentityServer__Key__StorageKind: FileSytem + IdentityServer__Key__StorageKind: FileSystem IdentityServer__Key__StorageConnectionString: "/usr/local/share/keys/signing" IdentityServer__Key__KeyProtectionOptions__KeyProtectionKind: "X509" IdentityServer__Key__KeyProtectionOptions__X509CertificatePath: /usr/local/share/ca-certificates/theidserver.pfx - DataProtectionOptions__StorageKind: FileSytem + DataProtectionOptions__StorageKind: FileSystem DataProtectionOptions__StorageConnectionString: "/usr/local/share/keys/dataprotecttion" DataProtectionOptions__KeyProtectionOptions__KeyProtectionKind: "X509" DataProtectionOptions__KeyProtectionOptions__X509CertificatePath: /usr/local/share/ca-certificates/theidserver.pfx diff --git a/sample/MultiTiers/Aguacongas.TheIdServer.Api/Aguacongas.TheIdServer.Api.csproj b/sample/MultiTiers/Aguacongas.TheIdServer.Api/Aguacongas.TheIdServer.Api.csproj index 13f847aba..472a9ee93 100644 --- a/sample/MultiTiers/Aguacongas.TheIdServer.Api/Aguacongas.TheIdServer.Api.csproj +++ b/sample/MultiTiers/Aguacongas.TheIdServer.Api/Aguacongas.TheIdServer.Api.csproj @@ -18,13 +18,13 @@ - - + + - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -32,7 +32,7 @@ - + diff --git a/sample/MultiTiers/Aguacongas.TheIdServer.Private/Aguacongas.TheIdServer.Private.csproj b/sample/MultiTiers/Aguacongas.TheIdServer.Private/Aguacongas.TheIdServer.Private.csproj index ec3a5c41a..ecdddc43c 100644 --- a/sample/MultiTiers/Aguacongas.TheIdServer.Private/Aguacongas.TheIdServer.Private.csproj +++ b/sample/MultiTiers/Aguacongas.TheIdServer.Private/Aguacongas.TheIdServer.Private.csproj @@ -18,25 +18,25 @@ - - - + + + - - - - - + + + + + - - - - - - - - - + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -45,7 +45,7 @@ - + diff --git a/sample/MultiTiers/Aguacongas.TheIdServer.Public/Aguacongas.TheIdServer.Public.csproj b/sample/MultiTiers/Aguacongas.TheIdServer.Public/Aguacongas.TheIdServer.Public.csproj index 046926c84..a24cd0473 100644 --- a/sample/MultiTiers/Aguacongas.TheIdServer.Public/Aguacongas.TheIdServer.Public.csproj +++ b/sample/MultiTiers/Aguacongas.TheIdServer.Public/Aguacongas.TheIdServer.Public.csproj @@ -18,20 +18,20 @@ - - - - - + + + + + - - - - - - - - + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -40,7 +40,7 @@ - + diff --git a/src/Aguacongas.TheIdServer.Authentication/Aguacongas.TheIdServer.Authentication.csproj b/src/Aguacongas.TheIdServer.Authentication/Aguacongas.TheIdServer.Authentication.csproj index 8e8b04fdd..9d4adab53 100644 --- a/src/Aguacongas.TheIdServer.Authentication/Aguacongas.TheIdServer.Authentication.csproj +++ b/src/Aguacongas.TheIdServer.Authentication/Aguacongas.TheIdServer.Authentication.csproj @@ -1,30 +1,30 @@ - - - - netstandard2.1 - Olivier Lefebvre - Copyright (c) 2020 @Olivier Lefebvre - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/LICENSE - https://github.com/Aguafrommars/TheIdServer/tree/master/src/Aguacongas.TheIdServer.Authentication - https://github.com/Aguafrommars/TheIdServer - git - theidserver;aspnetcore;authentication;security - Aguacongas.AspNetCore.Authentication store implementation for TheIdServer API. - Full - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png - ..\..\.sonarlint\aguacongas_theidservercsharp.ruleset - - - - - - - - - - - - - - - + + + + netstandard2.1 + Olivier Lefebvre + Copyright (c) 2020 @Olivier Lefebvre + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/LICENSE + https://github.com/Aguafrommars/TheIdServer/tree/master/src/Aguacongas.TheIdServer.Authentication + https://github.com/Aguafrommars/TheIdServer + git + theidserver;aspnetcore;authentication;security + Aguacongas.AspNetCore.Authentication store implementation for TheIdServer API. + Full + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png + ..\..\.sonarlint\aguacongas_theidservercsharp.ruleset + + + + + + + + + + + + + + + diff --git a/src/Aguacongas.TheIdServer.BlazorApp/Aguacongas.TheIdServer.BlazorApp.csproj b/src/Aguacongas.TheIdServer.BlazorApp/Aguacongas.TheIdServer.BlazorApp.csproj index 12373ddab..6adb5177f 100644 --- a/src/Aguacongas.TheIdServer.BlazorApp/Aguacongas.TheIdServer.BlazorApp.csproj +++ b/src/Aguacongas.TheIdServer.BlazorApp/Aguacongas.TheIdServer.BlazorApp.csproj @@ -31,8 +31,8 @@ - - + + diff --git a/src/Aguacongas.TheIdServer.BlazorApp/README.md b/src/Aguacongas.TheIdServer.BlazorApp/README.md index 91f11013e..d9f5ac4ca 100644 --- a/src/Aguacongas.TheIdServer.BlazorApp/README.md +++ b/src/Aguacongas.TheIdServer.BlazorApp/README.md @@ -23,7 +23,7 @@ NuGet packages composing the application are available on [nuget.org](https://ww * **Aguacongas.TheIdServer.BlazorApp.Infrastructure** contains application models, services, validators and extensions * **Aguacongas.TheIdServer.BlazorApp.Components** contains application components -* **Aguacongas.TheIdServer.BlazorApp.Pages** contains application pages +* **Aguacongas.TheIdServer.BlazorApp.Pages.*** contains application pages ## Configuration diff --git a/src/Aguacongas.TheIdServer.Identity/Aguacongas.TheIdServer.Identity.csproj b/src/Aguacongas.TheIdServer.Identity/Aguacongas.TheIdServer.Identity.csproj index b09000e5e..75d9ad14a 100644 --- a/src/Aguacongas.TheIdServer.Identity/Aguacongas.TheIdServer.Identity.csproj +++ b/src/Aguacongas.TheIdServer.Identity/Aguacongas.TheIdServer.Identity.csproj @@ -10,7 +10,7 @@ git theidserver;aspnetcore;identity;security TheIdServer management application. - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png @@ -27,7 +27,7 @@ - + diff --git a/src/Aguacongas.TheIdServer/Aguacongas - Backup.TheIdServer.csproj b/src/Aguacongas.TheIdServer/Aguacongas - Backup.TheIdServer.csproj deleted file mode 100644 index 5d47196b4..000000000 --- a/src/Aguacongas.TheIdServer/Aguacongas - Backup.TheIdServer.csproj +++ /dev/null @@ -1,91 +0,0 @@ - - - - net5.0 - Olivier Lefebvre - Copyright (c) 2020 @Olivier Lefebvre - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/LICENSE - https://github.com/Aguafrommars/TheIdServer/tree/master/src/Aguacongas.TheIdServer - https://github.com/Aguafrommars/TheIdServer - git - aspnetcore;identityserver4;oidc,oauth;authentication;security - OpenID/Connect server base on IdentityServer4. - Full - f6987681-1871-440a-a6ea-a606c2c5ccf6 - ..\..\docker-compose.dcproj - Linux - ..\.. - --network agua - - - Aguacongas.TheIdServer.ruleset - - - Aguacongas.TheIdServer.ruleset - 1701;1702;CA1416 - - - - - - <_ContentIncludedByDefault Remove="compilerconfig.json" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - PreserveNewest - - - - - PreserveNewest - - - \ No newline at end of file diff --git a/src/Aguacongas.TheIdServer/Aguacongas.TheIdServer.csproj b/src/Aguacongas.TheIdServer/Aguacongas.TheIdServer.csproj index 4129623e0..3384dddb8 100644 --- a/src/Aguacongas.TheIdServer/Aguacongas.TheIdServer.csproj +++ b/src/Aguacongas.TheIdServer/Aguacongas.TheIdServer.csproj @@ -41,19 +41,19 @@ - - - - - - - + + + + + + + - + @@ -71,6 +71,7 @@ + @@ -84,6 +85,12 @@ + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/src/Aguacongas.TheIdServer/Extensions/DataProtectionBuilderExtentions.cs b/src/Aguacongas.TheIdServer/Extensions/DataProtectionBuilderExtentions.cs index 7fd072355..e88f67438 100644 --- a/src/Aguacongas.TheIdServer/Extensions/DataProtectionBuilderExtentions.cs +++ b/src/Aguacongas.TheIdServer/Extensions/DataProtectionBuilderExtentions.cs @@ -2,6 +2,7 @@ // Copyright (c) 2021 @Olivier Lefebvre using Aguacongas.IdentityServer.Admin.Configuration; using Aguacongas.IdentityServer.EntityFramework.Store; +using Aguacongas.IdentityServer.KeysRotation.RavenDb; using Aguacongas.TheIdServer.Models; using Azure.Identity; using Microsoft.AspNetCore.DataProtection; @@ -9,6 +10,9 @@ using Microsoft.AspNetCore.DataProtection.KeyManagement; using Microsoft.AspNetCore.DataProtection.XmlEncryption; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Clients.ActiveDirectory; using Microsoft.Win32; using StackExchange.Redis; @@ -37,7 +41,10 @@ public static IDataProtectionBuilder ConfigureDataProtection(this IDataProtectio case StorageKind.EntityFramework: builder.PersistKeysToDbContext(); break; - case StorageKind.FileSytem: + case StorageKind.RavenDb: + builder.PersistKeysToRavenDb(); + break; + case StorageKind.FileSystem: builder.PersistKeysToFileSystem(new DirectoryInfo(dataProtectionsOptions.StorageConnectionString)); break; case StorageKind.Redis: diff --git a/src/Aguacongas.TheIdServer/Extensions/IdentityServerBuilderExtensions.cs b/src/Aguacongas.TheIdServer/Extensions/IdentityServerBuilderExtensions.cs index 97cc4f1b6..302dd332a 100644 --- a/src/Aguacongas.TheIdServer/Extensions/IdentityServerBuilderExtensions.cs +++ b/src/Aguacongas.TheIdServer/Extensions/IdentityServerBuilderExtensions.cs @@ -4,6 +4,7 @@ using Aguacongas.IdentityServer.EntityFramework.Store; using Aguacongas.IdentityServer.KeysRotation; using Aguacongas.IdentityServer.KeysRotation.Extentions; +using Aguacongas.IdentityServer.KeysRotation.RavenDb; using Aguacongas.TheIdServer.Models; using Microsoft.Extensions.Configuration; using StackExchange.Redis; @@ -34,7 +35,10 @@ public static IIdentityServerBuilder ConfigureKey(this IIdentityServerBuilder id case StorageKind.EntityFramework: builder.PersistKeysToDbContext(); break; - case StorageKind.FileSytem: + case StorageKind.RavenDb: + builder.PersistKeysToRavenDb(); + break; + case StorageKind.FileSystem: builder.PersistKeysToFileSystem(new DirectoryInfo(dataProtectionsOptions.StorageConnectionString)); break; case StorageKind.Redis: diff --git a/src/Aguacongas.TheIdServer/Models/DataProtectionOptions.cs b/src/Aguacongas.TheIdServer/Models/DataProtectionOptions.cs index d5a9a3697..66fdc7a98 100644 --- a/src/Aguacongas.TheIdServer/Models/DataProtectionOptions.cs +++ b/src/Aguacongas.TheIdServer/Models/DataProtectionOptions.cs @@ -10,8 +10,9 @@ public enum StorageKind EntityFramework, Redis, AzureStorage, - FileSytem, - Registry + FileSystem, + Registry, + RavenDb } public enum KeyProtectionKind diff --git a/src/Aguacongas.TheIdServer/Models/DbTypes.cs b/src/Aguacongas.TheIdServer/Models/DbTypes.cs index 4d579e133..f18c0baa2 100644 --- a/src/Aguacongas.TheIdServer/Models/DbTypes.cs +++ b/src/Aguacongas.TheIdServer/Models/DbTypes.cs @@ -10,5 +10,6 @@ public enum DbTypes MySql, Oracle, PostgreSQL, + RavenDb } } diff --git a/src/Aguacongas.TheIdServer/Models/RavenDbOptions.cs b/src/Aguacongas.TheIdServer/Models/RavenDbOptions.cs new file mode 100644 index 000000000..21f9ebaba --- /dev/null +++ b/src/Aguacongas.TheIdServer/Models/RavenDbOptions.cs @@ -0,0 +1,16 @@ +// Project: Aguafrommars/TheIdServer +// Copyright (c) 2021 @Olivier Lefebvre + +namespace Aguacongas.TheIdServer.Models +{ + public class RavenDbOptions + { + public string[] Urls { get; set; } + + public string Database { get; set; } + + public string CertificatePath { get; set; } + + public string CertificatePassword { get; set; } + } +} diff --git a/src/Aguacongas.TheIdServer/SeedData.cs b/src/Aguacongas.TheIdServer/SeedData.cs index 59d26368a..38ef08efb 100644 --- a/src/Aguacongas.TheIdServer/SeedData.cs +++ b/src/Aguacongas.TheIdServer/SeedData.cs @@ -15,33 +15,24 @@ using System.Linq; using System.Security.Claims; using System.Threading.Tasks; +using Entity = Aguacongas.IdentityServer.Store.Entity; namespace Aguacongas.TheIdServer { -#pragma warning disable S1118 // Utility classes should not have public constructors - public static class SeedData -#pragma warning restore S1118 // Utility classes should not have public constructors + static class SeedData { public static void EnsureSeedData(IConfiguration configuration) { var services = new ServiceCollection(); - services.AddLogging() - .AddDbContext(options => options.UseDatabaseFromConfiguration(configuration)) - .AddConfigurationEntityFrameworkStores(options => options.UseDatabaseFromConfiguration(configuration)) - .AddOperationalEntityFrameworkStores(options => options.UseDatabaseFromConfiguration(configuration)) - .AddIdentity() - .AddEntityFrameworkStores() - .AddDefaultTokenProviders(); - - services.AddIdentityServer() - .AddAspNetIdentity(); + var startup = new Startup(configuration, null); + startup.ConfigureServices(services); using var serviceProvider = services.BuildServiceProvider(); using var scope = serviceProvider.CreateScope(); var dbType = configuration.GetValue("DbType"); - if (dbType != DbTypes.InMemory) + if (dbType != DbTypes.InMemory && dbType != DbTypes.RavenDb) { var configContext = scope.ServiceProvider.GetRequiredService(); configContext.Database.Migrate(); @@ -59,54 +50,427 @@ public static void EnsureSeedData(IConfiguration configuration) public static void SeedConfiguration(IServiceScope scope, IConfiguration configuration) { - var provider = scope.ServiceProvider; - - var context = provider.GetRequiredService(); + var provider = scope.ServiceProvider; + SeedClients(configuration, provider); + SeedIdentities(provider); + SeedApiScopes(configuration, provider); + SeedApis(configuration, provider); + } + + private static void SeedApis(IConfiguration configuration, IServiceProvider provider) + { + var apiStore = provider.GetRequiredService>(); + var apiClaimStore = provider.GetRequiredService>(); + var apiSecretStore = provider.GetRequiredService>(); + var apiApiScopeStore = provider.GetRequiredService>(); + var apiPropertyStore = provider.GetRequiredService>(); - if (!context.Clients.Any()) + foreach (var resource in Config.GetApis(configuration)) { - foreach (var client in Config.GetClients(configuration)) - { - context.Clients.Add(client.ToEntity()); - Console.WriteLine($"Add client {client.ClientName}"); + if (apiStore.GetAsync(resource.Name, null).GetAwaiter().GetResult() != null) + { + continue; } - } - if (!context.Identities.Any()) - { - foreach (var resource in Config.GetIdentityResources()) - { - context.Identities.Add(resource.ToEntity()); - Console.WriteLine($"Add identity resource {resource.DisplayName}"); - } + apiStore.CreateAsync(new Entity.ProtectResource + { + Description = resource.Description, + DisplayName = resource.DisplayName, + Enabled = resource.Enabled, + Id = resource.Name, + }).GetAwaiter().GetResult(); + SeedApiClaims(apiClaimStore, resource); + SeedApiSecrets(apiSecretStore, resource); + SeedApiApiScopes(apiApiScopeStore, resource); + SeedApiProperties(apiPropertyStore, resource); + + Console.WriteLine($"Add api resource {resource.DisplayName}"); } + } + + private static void SeedApiProperties(IAdminStore apiPropertyStore, IdentityServer4.Models.ApiResource resource) + { + foreach (var property in resource.Properties) + { + apiPropertyStore.CreateAsync(new Entity.ApiProperty + { + ApiId = resource.Name, + Id = Guid.NewGuid().ToString(), + Key = property.Key, + Value = property.Value + }).GetAwaiter().GetResult(); + } + } + + private static void SeedApiApiScopes(IAdminStore apiApiScopeStore, IdentityServer4.Models.ApiResource resource) + { + foreach (var apiScope in resource.Scopes) + { + apiApiScopeStore.CreateAsync(new Entity.ApiApiScope + { + ApiId = resource.Name, + ApiScopeId = apiScope, + Id = Guid.NewGuid().ToString() + }).GetAwaiter().GetResult(); + } + } + + private static void SeedApiSecrets(IAdminStore apiSecretStore, IdentityServer4.Models.ApiResource resource) + { + foreach (var secret in resource.ApiSecrets) + { + apiSecretStore.CreateAsync(new Entity.ApiSecret + { + ApiId = resource.Name, + Expiration = secret.Expiration, + Description = secret.Description, + Id = Guid.NewGuid().ToString(), + Type = secret.Type, + Value = secret.Value + }).GetAwaiter().GetResult(); + } + } + + private static void SeedApiClaims(IAdminStore apiClaimStore, IdentityServer4.Models.ApiResource resource) + { + foreach (var claim in resource.UserClaims) + { + apiClaimStore.CreateAsync(new Entity.ApiClaim + { + ApiId = resource.Name, + Id = Guid.NewGuid().ToString(), + Type = claim + }).GetAwaiter().GetResult(); + } + } - if (!context.ApiScopes.Any()) + private static void SeedApiScopes(IConfiguration configuration, IServiceProvider provider) + { + var apiScopeStore = provider.GetRequiredService>(); + var apiScopeClaimStore = provider.GetRequiredService>(); + var apiScopePropertyStore = provider.GetRequiredService>(); + foreach (var resource in Config.GetApiScopes(configuration)) { - foreach (var resource in Config.GetApiScopes(configuration)) - { - context.ApiScopes.Add(resource.ToEntity()); - Console.WriteLine($"Add api scope resource {resource.DisplayName}"); + if (apiScopeStore.GetAsync(resource.Name, null).GetAwaiter().GetResult() != null) + { + continue; } - } - if (!context.Apis.Any()) + apiScopeStore.CreateAsync(new Entity.ApiScope + { + Description = resource.Description, + DisplayName = resource.DisplayName, + Emphasize = resource.Emphasize, + Enabled = resource.Enabled, + Id = resource.Name, + Required = resource.Required, + ShowInDiscoveryDocument = resource.ShowInDiscoveryDocument + }).GetAwaiter().GetResult(); + + SeedApiScopeClaims(apiScopeClaimStore, resource); + SeedApiScopeProperties(apiScopePropertyStore, resource); + + Console.WriteLine($"Add api scope resource {resource.DisplayName}"); + } + } + + private static void SeedApiScopeProperties(IAdminStore apiScopePropertyStore, IdentityServer4.Models.ApiScope resource) + { + foreach (var property in resource.Properties) + { + apiScopePropertyStore.CreateAsync(new Entity.ApiScopeProperty + { + ApiScopeId = resource.Name, + Id = Guid.NewGuid().ToString(), + Key = property.Key, + Value = property.Value + }).GetAwaiter().GetResult(); + } + } + + private static void SeedApiScopeClaims(IAdminStore apiScopeClaimStore, IdentityServer4.Models.ApiScope resource) + { + foreach (var claim in resource.UserClaims) + { + apiScopeClaimStore.CreateAsync(new Entity.ApiScopeClaim + { + ApiScopeId = resource.Name, + Id = Guid.NewGuid().ToString(), + Type = claim + }).GetAwaiter().GetResult(); + } + } + + private static void SeedIdentities(IServiceProvider provider) + { + var identityStore = provider.GetRequiredService>(); + var identityClaimStore = provider.GetRequiredService>(); + var identityPropertyStore = provider.GetRequiredService>(); + foreach (var resource in Config.GetIdentityResources()) { - foreach (var resource in Config.GetApis(configuration)) - { - context.Apis.Add(resource.ToEntity()); - Console.WriteLine($"Add api resource {resource.DisplayName}"); + if (identityStore.GetAsync(resource.Name, null).GetAwaiter().GetResult() != null) + { + continue; } - } - context.SaveChanges(); - } + identityStore.CreateAsync(new Entity.IdentityResource + { + Description = resource.Description, + DisplayName = resource.DisplayName, + Emphasize = resource.Emphasize, + Enabled = resource.Enabled, + Id = resource.Name, + Required = resource.Required, + ShowInDiscoveryDocument = resource.ShowInDiscoveryDocument + }).GetAwaiter().GetResult(); + SeedIdentityClaims(identityClaimStore, resource); + SeedIdentityProperties(identityPropertyStore, resource); + + Console.WriteLine($"Add identity resource {resource.DisplayName}"); + } + } + + private static void SeedIdentityProperties(IAdminStore identityPropertyStore, IdentityServer4.Models.IdentityResource resource) + { + foreach (var property in resource.Properties) + { + identityPropertyStore.CreateAsync(new Entity.IdentityProperty + { + Id = Guid.NewGuid().ToString(), + IdentityId = resource.Name, + Key = property.Key, + Value = property.Value + }).GetAwaiter().GetResult(); + } + } + + private static void SeedIdentityClaims(IAdminStore identityClaimStore, IdentityServer4.Models.IdentityResource resource) + { + foreach (var claim in resource.UserClaims) + { + identityClaimStore.CreateAsync(new Entity.IdentityClaim + { + Id = Guid.NewGuid().ToString(), + IdentityId = resource.Name, + Type = claim + }).GetAwaiter().GetResult(); + } + } + + private static void SeedClients(IConfiguration configuration, IServiceProvider provider) + { + var clientStore = provider.GetRequiredService>(); + var clientGrantTypeStore = provider.GetRequiredService>(); + var clientScopeStore = provider.GetRequiredService>(); + var clientClaimStore = provider.GetRequiredService>(); + var clientSecretStore = provider.GetRequiredService>(); + var clientIdpRestrictionStore = provider.GetRequiredService>(); + var clientUriStore = provider.GetRequiredService>(); + var clientPropertyStore = provider.GetRequiredService>(); + foreach (var client in Config.GetClients(configuration)) + { + if (clientStore.GetAsync(client.ClientId, null).GetAwaiter().GetResult() != null) + { + continue; + } + + clientStore.CreateAsync(new Entity.Client + { + AbsoluteRefreshTokenLifetime = client.AbsoluteRefreshTokenLifetime, + AccessTokenLifetime = client.AccessTokenLifetime, + AccessTokenType = (int)client.AccessTokenType, + AllowAccessTokensViaBrowser = client.AllowAccessTokensViaBrowser, + AllowOfflineAccess = client.AllowOfflineAccess, + AllowPlainTextPkce = client.AllowPlainTextPkce, + AllowRememberConsent = client.AllowRememberConsent, + AlwaysIncludeUserClaimsInIdToken = client.AlwaysIncludeUserClaimsInIdToken, + AlwaysSendClientClaims = client.AlwaysSendClientClaims, + AuthorizationCodeLifetime = client.AuthorizationCodeLifetime, + BackChannelLogoutSessionRequired = client.BackChannelLogoutSessionRequired, + BackChannelLogoutUri = client.BackChannelLogoutUri, + ClientClaimsPrefix = client.ClientClaimsPrefix, + ClientName = client.ClientName, + ClientUri = client.ClientUri, + ConsentLifetime = client.ConsentLifetime, + Description = client.Description, + DeviceCodeLifetime = client.DeviceCodeLifetime, + Enabled = client.Enabled, + EnableLocalLogin = client.EnableLocalLogin, + FrontChannelLogoutSessionRequired = client.FrontChannelLogoutSessionRequired, + FrontChannelLogoutUri = client.FrontChannelLogoutUri, + Id = client.ClientId, + IdentityTokenLifetime = client.IdentityTokenLifetime, + IncludeJwtId = client.IncludeJwtId, + LogoUri = client.LogoUri, + PairWiseSubjectSalt = client.PairWiseSubjectSalt, + ProtocolType = client.ProtocolType, + RefreshTokenExpiration = (int)client.RefreshTokenExpiration, + RefreshTokenUsage = (int)client.RefreshTokenUsage, + RequireClientSecret = client.RequireClientSecret, + RequireConsent = client.RequireConsent, + RequirePkce = client.RequirePkce, + SlidingRefreshTokenLifetime = client.SlidingRefreshTokenLifetime, + UpdateAccessTokenClaimsOnRefresh = client.UpdateAccessTokenClaimsOnRefresh, + UserCodeType = client.UserCodeType, + UserSsoLifetime = client.UserSsoLifetime + }).GetAwaiter().GetResult(); + SeedClientGrantType(clientGrantTypeStore, client); + SeedClientScopes(clientScopeStore, client); + SeedClientClaims(clientClaimStore, client); + SeedClientSecrets(clientSecretStore, client); + SeedClientRestrictions(clientIdpRestrictionStore, client); + SeedClientProperties(clientPropertyStore, client); + SeedClientUris(clientUriStore, client); + + Console.WriteLine($"Add client {client.ClientName}"); + } + } + + private static void SeedClientUris(IAdminStore clientUriStore, IdentityServer4.Models.Client client) + { + var uris = client.RedirectUris.Select(o => new Entity.ClientUri + { + Id = Guid.NewGuid().ToString(), + ClientId = client.ClientId, + Uri = o + }).ToList(); + + foreach (var origin in client.AllowedCorsOrigins) + { + var cors = new Uri(origin); + var uri = uris.FirstOrDefault(u => cors.CorsMatch(u.Uri)); + var corsUri = new Uri(origin); + var sanetized = $"{corsUri.Scheme.ToUpperInvariant()}://{corsUri.Host.ToUpperInvariant()}:{corsUri.Port}"; + + if (uri == null) + { + + uris.Add(new Entity.ClientUri + { + Id = Guid.NewGuid().ToString(), + ClientId = client.ClientId, + Uri = origin, + Kind = Entity.UriKinds.Cors, + SanetizedCorsUri = sanetized + }); + continue; + } + + uri.SanetizedCorsUri = sanetized; + uri.Kind = Entity.UriKinds.Redirect | Entity.UriKinds.Cors; + } + + foreach (var postLogout in client.PostLogoutRedirectUris) + { + var uri = uris.FirstOrDefault(u => u.Uri == postLogout); + if (uri == null) + { + uris.Add(new Entity.ClientUri + { + Id = Guid.NewGuid().ToString(), + ClientId = client.ClientId, + Uri = postLogout, + Kind = Entity.UriKinds.PostLogout + }); + continue; + } + + uri.Kind |= Entity.UriKinds.Redirect; + } + + foreach (var uri in uris) + { + clientUriStore.CreateAsync(uri).GetAwaiter().GetResult(); + } + } + + private static void SeedClientProperties(IAdminStore clientPropertyStore, IdentityServer4.Models.Client client) + { + foreach (var property in client.Properties) + { + clientPropertyStore.CreateAsync(new Entity.ClientProperty + { + ClientId = client.ClientId, + Id = Guid.NewGuid().ToString(), + Key = property.Key, + Value = property.Value + }).GetAwaiter().GetResult(); + } + } + + private static void SeedClientRestrictions(IAdminStore clientIdpRestrictionStore, IdentityServer4.Models.Client client) + { + foreach (var restriction in client.IdentityProviderRestrictions) + { + clientIdpRestrictionStore.CreateAsync(new Entity.ClientIdpRestriction + { + ClientId = client.ClientId, + Id = Guid.NewGuid().ToString(), + Provider = restriction + }).GetAwaiter().GetResult(); + } + } + + private static void SeedClientSecrets(IAdminStore clientSecretStore, IdentityServer4.Models.Client client) + { + foreach (var secret in client.ClientSecrets) + { + clientSecretStore.CreateAsync(new Entity.ClientSecret + { + ClientId = client.ClientId, + Description = secret.Description, + Expiration = secret.Expiration, + Id = Guid.NewGuid().ToString(), + Type = secret.Type, + Value = secret.Value + }).GetAwaiter().GetResult(); + } + } + + private static void SeedClientClaims(IAdminStore clientClaimStore, IdentityServer4.Models.Client client) + { + foreach (var claim in client.Claims) + { + clientClaimStore.CreateAsync(new Entity.ClientClaim + { + ClientId = client.ClientId, + Id = Guid.NewGuid().ToString(), + Type = claim.Type, + Value = claim.Value + }).GetAwaiter().GetResult(); + } + } + + private static void SeedClientScopes(IAdminStore clientScopeStore, IdentityServer4.Models.Client client) + { + foreach (var clientScope in client.AllowedScopes) + { + clientScopeStore.CreateAsync(new Entity.ClientScope + { + ClientId = client.ClientId, + Scope = clientScope, + Id = Guid.NewGuid().ToString() + }).GetAwaiter().GetResult(); + } + } + + private static void SeedClientGrantType(IAdminStore clientGrantTypeStore, IdentityServer4.Models.Client client) + { + foreach (var grantType in client.AllowedGrantTypes) + { + clientGrantTypeStore.CreateAsync(new Entity.ClientGrantType + { + ClientId = client.ClientId, + GrantType = grantType, + Id = Guid.NewGuid().ToString() + }).GetAwaiter().GetResult(); + } + } + public static void SeedUsers(IServiceScope scope, IConfiguration configuration) { var provider = scope.ServiceProvider; - - var context = provider.GetService(); var roleMgr = provider.GetRequiredService>(); @@ -156,8 +520,6 @@ public static void SeedUsers(IServiceScope scope, IConfiguration configuration) index++; } - - context.SaveChanges(); } [SuppressMessage("Major Code Smell", "S112:General exceptions should never be thrown", Justification = "Seeding")] @@ -168,7 +530,6 @@ private static async Task ExcuteAndCheckResult(Func> action { throw new Exception(result.Errors.First().Description); } - } } } diff --git a/src/Aguacongas.TheIdServer/Services/PreRenderStringLocalizer.cs b/src/Aguacongas.TheIdServer/Services/PreRenderStringLocalizer.cs index 90f511055..121900216 100644 --- a/src/Aguacongas.TheIdServer/Services/PreRenderStringLocalizer.cs +++ b/src/Aguacongas.TheIdServer/Services/PreRenderStringLocalizer.cs @@ -1,7 +1,5 @@ // Project: Aguafrommars/TheIdServer // Copyright (c) 2021 @Olivier Lefebvre -using Aguacongas.IdentityServer.Store; -using Aguacongas.IdentityServer.Store.Entity; using Aguacongas.TheIdServer.BlazorApp.Infrastructure.Services; using Aguacongas.TheIdServer.BlazorApp.Services; using Microsoft.Extensions.Localization; @@ -11,7 +9,7 @@ namespace Aguacongas.TheIdServer.Services { public class PreRenderStringLocalizer : StringLocalizer { - public PreRenderStringLocalizer(IAdminStore store, IReadOnlyCultureStore cultureStore, ILogger logger) : base(store, cultureStore, logger) + public PreRenderStringLocalizer(IReadOnlyLocalizedResourceStore store, IReadOnlyCultureStore cultureStore, ILogger logger) : base(store, cultureStore, logger) { GetSupportedCulturesAsync().GetAwaiter().GetResult(); } diff --git a/src/Aguacongas.TheIdServer/Startup.cs b/src/Aguacongas.TheIdServer/Startup.cs index 31b11a01a..8603cd8e3 100644 --- a/src/Aguacongas.TheIdServer/Startup.cs +++ b/src/Aguacongas.TheIdServer/Startup.cs @@ -1,52 +1,55 @@ -// Project: Aguafrommars/TheIdServer -// Copyright (c) 2021 @Olivier Lefebvre -using Aguacongas.IdentityServer; -using Aguacongas.IdentityServer.Abstractions; -using Aguacongas.IdentityServer.Admin.Http.Store; -using Aguacongas.IdentityServer.Admin.Options; -using Aguacongas.IdentityServer.Admin.Services; -using Aguacongas.IdentityServer.EntityFramework.Store; -using Aguacongas.IdentityServer.Store; -using Aguacongas.TheIdServer.Admin.Hubs; -using Aguacongas.TheIdServer.BlazorApp.Infrastructure.Services; -using Aguacongas.TheIdServer.BlazorApp.Models; -using Aguacongas.TheIdServer.BlazorApp.Services; +// Project: Aguafrommars/TheIdServer +// Copyright (c) 2021 @Olivier Lefebvre +using Aguacongas.IdentityServer; +using Aguacongas.IdentityServer.Abstractions; +using Aguacongas.IdentityServer.Admin.Http.Store; +using Aguacongas.IdentityServer.Admin.Options; +using Aguacongas.IdentityServer.Admin.Services; +using Aguacongas.IdentityServer.EntityFramework.Store; +using Aguacongas.IdentityServer.Store; +using Aguacongas.TheIdServer.Admin.Hubs; +using Aguacongas.TheIdServer.BlazorApp.Infrastructure.Services; +using Aguacongas.TheIdServer.BlazorApp.Models; +using Aguacongas.TheIdServer.BlazorApp.Services; using Aguacongas.TheIdServer.Data; -using Aguacongas.TheIdServer.Models; -using Aguacongas.TheIdServer.Services; -using IdentityModel.AspNetCore.OAuth2Introspection; -using IdentityServer4.Quickstart.UI; -using IdentityServer4.Services; -using Microsoft.AspNetCore.Authentication.JwtBearer; +using Aguacongas.TheIdServer.Models; +using Aguacongas.TheIdServer.Services; +using IdentityModel.AspNetCore.OAuth2Introspection; +using IdentityServer4.Quickstart.UI; +using IdentityServer4.Services; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Components.Authorization; -using Microsoft.AspNetCore.Components.WebAssembly.Authentication; -using Microsoft.AspNetCore.Components.WebAssembly.Hosting; -using Microsoft.AspNetCore.Components.WebAssembly.Services; +using Microsoft.AspNetCore.Components.Authorization; +using Microsoft.AspNetCore.Components.WebAssembly.Authentication; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +using Microsoft.AspNetCore.Components.WebAssembly.Services; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Localization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Localization; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Microsoft.IdentityModel.Tokens; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; +using Raven.Client.Documents; using Serilog; -using System; -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; using Auth = Aguacongas.TheIdServer.Authentication; - +using RavenDbStore = Aguacongas.IdentityServer.RavenDb.Store; + namespace Aguacongas.TheIdServer { public class Startup @@ -54,144 +57,153 @@ public class Startup public IConfiguration Configuration { get; } public IWebHostEnvironment Environment { get; } + public DbTypes DbType { get; } + public Startup(IConfiguration configuration, IWebHostEnvironment environment) { Configuration = configuration; + DbType = Configuration.GetValue("DbType"); Environment = environment; } public void ConfigureServices(IServiceCollection services) - { - var isProxy = Configuration.GetValue("Proxy"); - - void configureOptions(IdentityServerOptions options) - => Configuration.GetSection("PrivateServerAuthentication").Bind(options); - - services.AddConfigurationHttpStores(configureOptions); - - if (isProxy) - { - AddProxyServices(services, configureOptions); - } - else - { - AddDefaultServices(services); - } - - ConfigureDataProtection(services); - - var identityBuilder = services.AddClaimsProviders(Configuration) - .Configure(Configuration.GetSection(nameof(ForwardedHeadersOptions))) - .Configure(Configuration.GetSection(nameof(AccountOptions))) - .Configure(Configuration.GetSection(nameof(DynamicClientRegistrationOptions))) - .Configure(Configuration.GetSection(nameof(TokenValidationParameters))) - .Configure(Configuration.GetSection(nameof(SiteOptions))) - .ConfigureNonBreakingSameSiteCookies() - .AddOidcStateDataFormatterCache() - .AddIdentityServer(Configuration.GetSection(nameof(IdentityServerOptions))) - .AddAspNetIdentity() - .AddDynamicClientRegistration() - .ConfigureKey(Configuration.GetSection("IdentityServer:Key")); - - identityBuilder.AddJwtRequestUriHttpClient(); - - if (isProxy) - { - identityBuilder.Services.AddTransient(p => - { - var options = p.GetRequiredService>().Value; - var httpClient = p.GetRequiredService().CreateClient(options.HttpClientName); - return new ProxyProfilService(httpClient, - p.GetRequiredService>(), - p.GetRequiredService>(), - p.GetRequiredService>(), - p.GetRequiredService>>()); - }); - } - else - { - identityBuilder.AddProfileService>(); - if (!Configuration.GetValue("DisableTokenCleanup")) - { - identityBuilder.AddTokenCleaner(Configuration.GetValue("TokenCleanupInterval") ?? TimeSpan.FromMinutes(1)); - } - } - - services.AddTransient(p => - { - var handler = new HttpClientHandler(); - if (Configuration.GetValue("DisableStrictSsl")) - { -#pragma warning disable S4830 // Server certificates should be verified during SSL/TLS connections - handler.ServerCertificateCustomValidationCallback = (message, cert, chain, policy) => true; -#pragma warning restore S4830 // Server certificates should be verified during SSL/TLS connections - } - return handler; - }) - .AddHttpClient(OAuth2IntrospectionDefaults.BackChannelHttpClientName) - .ConfigurePrimaryHttpMessageHandler(p => p.GetRequiredService()); - + { + var isProxy = Configuration.GetValue("Proxy"); + + void configureOptions(IdentityServerOptions options) + => Configuration.GetSection("PrivateServerAuthentication").Bind(options); + + services.AddConfigurationHttpStores(configureOptions); + + if (isProxy) + { + AddProxyServices(services, configureOptions); + } + else + { + AddDefaultServices(services); + } + + ConfigureDataProtection(services); + + var identityBuilder = services.AddClaimsProviders(Configuration) + .Configure(Configuration.GetSection(nameof(ForwardedHeadersOptions))) + .Configure(Configuration.GetSection(nameof(AccountOptions))) + .Configure(Configuration.GetSection(nameof(DynamicClientRegistrationOptions))) + .Configure(Configuration.GetSection(nameof(TokenValidationParameters))) + .Configure(Configuration.GetSection(nameof(SiteOptions))) + .ConfigureNonBreakingSameSiteCookies() + .AddOidcStateDataFormatterCache() + .AddIdentityServer(Configuration.GetSection(nameof(IdentityServerOptions))) + .AddAspNetIdentity() + .AddDynamicClientRegistration() + .ConfigureKey(Configuration.GetSection("IdentityServer:Key")); + + identityBuilder.AddJwtRequestUriHttpClient(); + + if (isProxy) + { + identityBuilder.Services.AddTransient(p => + { + var options = p.GetRequiredService>().Value; + var httpClient = p.GetRequiredService().CreateClient(options.HttpClientName); + return new ProxyProfilService(httpClient, + p.GetRequiredService>(), + p.GetRequiredService>(), + p.GetRequiredService>(), + p.GetRequiredService>>()); + }); + } + else + { + identityBuilder.AddProfileService>(); + if (!Configuration.GetValue("DisableTokenCleanup")) + { + identityBuilder.AddTokenCleaner(Configuration.GetValue("TokenCleanupInterval") ?? TimeSpan.FromMinutes(1)); + } + } + + services.AddTransient(p => + { + var handler = new HttpClientHandler(); + if (Configuration.GetValue("DisableStrictSsl")) + { +#pragma warning disable S4830 // Server certificates should be verified during SSL/TLS connections + handler.ServerCertificateCustomValidationCallback = (message, cert, chain, policy) => true; +#pragma warning restore S4830 // Server certificates should be verified during SSL/TLS connections + } + return handler; + }) + .AddHttpClient(OAuth2IntrospectionDefaults.BackChannelHttpClientName) + .ConfigurePrimaryHttpMessageHandler(p => p.GetRequiredService()); + services.Configure(Configuration.GetSection("Google")) .AddAuthorization(options => options.AddIdentityServerPolicies()) .AddAuthentication() - .AddJwtBearer("Bearer", options => ConfigureIdentityServerAuthenticationOptions(options)) - // reference tokens - .AddOAuth2Introspection("introspection", options => ConfigureIdentityServerAuthenticationOptions(options)); - - + .AddJwtBearer("Bearer", options => ConfigureIdentityServerAuthenticationOptions(options)) + // reference tokens + .AddOAuth2Introspection("introspection", options => ConfigureIdentityServerAuthenticationOptions(options)); + + var mvcBuilder = services.Configure(Configuration) .AddLocalization() .AddControllersWithViews(options => options.AddIdentityServerAdminFilters()) - .AddViewLocalization() + .AddViewLocalization() .AddDataAnnotationsLocalization() .AddNewtonsoftJson(options => { var settings = options.SerializerSettings; settings.NullValueHandling = NullValueHandling.Ignore; settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; - }); - - if (isProxy) - { - mvcBuilder.AddIdentityServerAdmin() - .AddTheIdServerHttpStore(); + }); + + if (isProxy) + { + mvcBuilder.AddIdentityServerAdmin() + .AddTheIdServerHttpStore(); + } + else if (DbType == DbTypes.RavenDb) + { + mvcBuilder.AddIdentityServerAdmin() + .AddRavenDbStore(); } - else - { - mvcBuilder.AddIdentityServerAdmin() - .AddEntityFrameworkStore(); - } - - services.AddRemoteAuthentication(); - services.AddScoped() - .AddScoped() - .AddScoped() - .AddScoped() - .AddTransient() - .AddTransient() - .AddTransient() - .AddTransient>(p => new KeyStore(p.CreateApiHttpClient(p.GetRequiredService>().Value), - p.GetRequiredService>>())) - .AddTransient>(p => new KeyStore(p.CreateApiHttpClient(p.GetRequiredService>().Value), - p.GetRequiredService>>())) - .AddAdminApplication(new Settings()) - .AddDatabaseDeveloperPageExceptionFilter() + else + { + mvcBuilder.AddIdentityServerAdmin() + .AddEntityFrameworkStore(); + } + + services.AddRemoteAuthentication(); + services.AddScoped() + .AddScoped() + .AddScoped() + .AddScoped() + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient>(p => new KeyStore(p.CreateApiHttpClient(p.GetRequiredService>().Value), + p.GetRequiredService>>())) + .AddTransient>(p => new KeyStore(p.CreateApiHttpClient(p.GetRequiredService>().Value), + p.GetRequiredService>>())) + .AddAdminApplication(new Settings()) + .AddDatabaseDeveloperPageExceptionFilter() .AddRazorPages(options => options.Conventions.AuthorizeAreaFolder("Identity", "/Account")); - } - + } + [SuppressMessage("Usage", "ASP0001:Authorization middleware is incorrectly configured.", Justification = "")] public void Configure(IApplicationBuilder app) { var isProxy = Configuration.GetValue("Proxy"); var disableHttps = Configuration.GetValue("DisableHttps"); - app.UseForwardedHeaders(); + app.UseForwardedHeaders(); AddForceHttpsSchemeMiddleware(app); - if (!isProxy) - { + if (!isProxy) + { ConfigureInitialData(app); } @@ -207,20 +219,20 @@ public void Configure(IApplicationBuilder app) { app.UseHsts(); } - } - + } + var scope = app.ApplicationServices.CreateScope(); var scopedProvider = scope.ServiceProvider; - var supportedCulture = scopedProvider.GetRequiredService().CulturesNames.ToArray(); - - - app.UseRequestLocalization(options => - { - options.DefaultRequestCulture = new RequestCulture("en"); - options.SupportedCultures = supportedCulture.Select(c => new CultureInfo(c)).ToList(); - options.SupportedUICultures = options.SupportedCultures; - options.FallBackToParentCultures = true; - options.AddInitialRequestCultureProvider(new SetCookieFromQueryStringRequestCultureProvider()); + var supportedCulture = scopedProvider.GetRequiredService().CulturesNames.ToArray(); + + + app.UseRequestLocalization(options => + { + options.DefaultRequestCulture = new RequestCulture("en"); + options.SupportedCultures = supportedCulture.Select(c => new CultureInfo(c)).ToList(); + options.SupportedUICultures = options.SupportedCultures; + options.FallBackToParentCultures = true; + options.AddInitialRequestCultureProvider(new SetCookieFromQueryStringRequestCultureProvider()); }) .UseSerilogRequestLogging(); @@ -229,246 +241,282 @@ public void Configure(IApplicationBuilder app) app.UseHttpsRedirection(); } - app.UseIdentityServerAdminApi("/api", child => - { - if (Configuration.GetValue("EnableOpenApiDoc")) - { - child.UseOpenApi() - .UseSwaggerUi3(options => - { - var settings = Configuration.GetSection("SwaggerUiSettings").Get(); - options.OAuth2Client = settings.OAuth2Client; - }); - } - var allowedOrigin = Configuration.GetSection("CorsAllowedOrigin").Get>(); - if (allowedOrigin != null) - { - child.UseCors(configure => - { - configure.SetIsOriginAllowed(origin => allowedOrigin.Any(o => o == origin)) - .AllowAnyMethod() - .AllowAnyHeader() - .AllowCredentials(); - }); - } + app.UseIdentityServerAdminApi("/api", child => + { + if (Configuration.GetValue("EnableOpenApiDoc")) + { + child.UseOpenApi() + .UseSwaggerUi3(options => + { + var settings = Configuration.GetSection("SwaggerUiSettings").Get(); + options.OAuth2Client = settings.OAuth2Client; + }); + } + var allowedOrigin = Configuration.GetSection("CorsAllowedOrigin").Get>(); + if (allowedOrigin != null) + { + child.UseCors(configure => + { + configure.SetIsOriginAllowed(origin => allowedOrigin.Any(o => o == origin)) + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials(); + }); + } }) .UseBlazorFrameworkFiles() .UseStaticFiles() .UseRouting() - .UseIdentityServer(); - - if (!isProxy) - { - app.UseIdentityServerAdminAuthentication("/providerhub", JwtBearerDefaults.AuthenticationScheme); - } + .UseIdentityServer(); + + if (!isProxy) + { + app.UseIdentityServerAdminAuthentication("/providerhub", JwtBearerDefaults.AuthenticationScheme); + } app .UseAuthorization() - .Use((context, next) => - { - var service = context.RequestServices; - var settings = service.GetRequiredService(); - var request = context.Request; - settings.WelcomeContenUrl = $"{request.Scheme}://{request.Host}/api/welcomefragment"; - var remotePathOptions = service.GetRequiredService>().Value; - remotePathOptions.RemoteProfilePath = $"{request.Scheme}://{request.Host}/identity/account/manage"; - remotePathOptions.RemoteRegisterPath = $"{request.Scheme}://{request.Host}/identity/account/register"; - return next(); + .Use((context, next) => + { + var service = context.RequestServices; + var settings = service.GetRequiredService(); + var request = context.Request; + settings.WelcomeContenUrl = $"{request.Scheme}://{request.Host}/api/welcomefragment"; + var remotePathOptions = service.GetRequiredService>().Value; + remotePathOptions.RemoteProfilePath = $"{request.Scheme}://{request.Host}/identity/account/manage"; + remotePathOptions.RemoteRegisterPath = $"{request.Scheme}://{request.Host}/identity/account/register"; + return next(); }) .UseEndpoints(endpoints => { endpoints.MapRazorPages(); endpoints.MapDefaultControllerRoute(); - if (!isProxy) - { - endpoints.MapHub("/providerhub"); - } - + if (!isProxy) + { + endpoints.MapHub("/providerhub"); + } + endpoints.MapFallbackToPage("/_Host"); }); - if (isProxy) - { - app.LoadDynamicAuthenticationConfiguration(); + if (isProxy) + { + app.LoadDynamicAuthenticationConfiguration(); + return; } - else - { - app.LoadDynamicAuthenticationConfiguration(); - } - } - - private void AddForceHttpsSchemeMiddleware(IApplicationBuilder app) - { + if (DbType == DbTypes.RavenDb) + { + app.LoadDynamicAuthenticationConfiguration(); + return; + } + app.LoadDynamicAuthenticationConfiguration(); + } + + private void AddForceHttpsSchemeMiddleware(IApplicationBuilder app) + { var forceHttpsScheme = Configuration.GetValue("ForceHttpsScheme"); - if (forceHttpsScheme) - { - app.Use((context, next) => - { - context.Request.Scheme = "https"; - return next(); - }); - } - } - - private void ConfigureIdentityServerAuthenticationOptions(JwtBearerOptions options) - { - Configuration.GetSection("ApiAuthentication").Bind(options); - if (Configuration.GetValue("DisableStrictSsl")) - { - options.BackchannelHttpHandler = new HttpClientHandler - { -#pragma warning disable S4830 // Server certificates should be verified during SSL/TLS connections - ServerCertificateCustomValidationCallback = (message, cert, chain, policy) => true -#pragma warning restore S4830 // Server certificates should be verified during SSL/TLS connections - }; - } - - options.Events = new JwtBearerEvents - { - OnMessageReceived = context => - { - var request = context.HttpContext.Request; - var path = request.Path; - var accessToken = TokenRetrieval.FromQueryString()(request); - if (path.StartsWithSegments("/providerhub") && !string.IsNullOrEmpty(accessToken)) - { - context.Token = accessToken; - return Task.CompletedTask; - } - var oneTimeToken = TokenRetrieval.FromQueryString("otk")(request); - if (!string.IsNullOrEmpty(oneTimeToken)) - { - context.Token = request.HttpContext - .RequestServices - .GetRequiredService() - .GetOneTimeToken(oneTimeToken); - } - return Task.CompletedTask; - } - }; - - options.ForwardDefaultSelector = context => - { - var authHeader = context.Request.Headers[HttpRequestHeader.Authorization.ToString()]; - if (string.IsNullOrEmpty(authHeader)) - { - return null; - } - - var parts = authHeader.First().Split(' ', StringSplitOptions.RemoveEmptyEntries); - if (parts.Length != 2) - { - return null; - } - - if (!parts[1].Contains(".")) - { - return "introspection"; - } - - return null; - }; - } - - private void ConfigureIdentityServerAuthenticationOptions(OAuth2IntrospectionOptions options) - { - Configuration.GetSection("ApiAuthentication").Bind(options); - options.ClientId = Configuration.GetValue("ApiAuthentication:ApiName"); - options.ClientSecret = Configuration.GetValue("ApiAuthentication:ApiSecret"); - static string tokenRetriever(HttpRequest request) - { - var path = request.Path; - var accessToken = TokenRetrieval.FromQueryString()(request); - if (path.StartsWithSegments("/providerhub") && !string.IsNullOrEmpty(accessToken)) - { - return accessToken; - } - var oneTimeToken = TokenRetrieval.FromQueryString("otk")(request); - if (!string.IsNullOrEmpty(oneTimeToken)) - { - return request.HttpContext - .RequestServices - .GetRequiredService() - .GetOneTimeToken(oneTimeToken); - } - return TokenRetrieval.FromAuthorizationHeader()(request); - } - - options.TokenRetriever = tokenRetriever; - } - - private void AddDefaultServices(IServiceCollection services) - { - services.Configure(options => Configuration.GetSection("ApiAuthentication").Bind(options)) - .AddTransient>() - .AddDbContext(options => options.UseDatabaseFromConfiguration(Configuration)) - .AddIdentityServer4AdminEntityFrameworkStores() - .AddConfigurationEntityFrameworkStores(options => options.UseDatabaseFromConfiguration(Configuration)) - .AddOperationalEntityFrameworkStores(options => options.UseDatabaseFromConfiguration(Configuration)) - .AddIdentityProviderStore(); - - services.AddIdentity( - options => Configuration.GetSection(nameof(IdentityOptions)).Bind(options)) - .AddEntityFrameworkStores() - .AddDefaultTokenProviders(); - - var signalRBuilder = services.AddSignalR(options => Configuration.GetSection("SignalR:HubOptions").Bind(options)); - if (Configuration.GetValue("SignalR:UseMessagePack")) - { - signalRBuilder.AddMessagePackProtocol(); - } - - var redisConnectionString = Configuration.GetValue("SignalR:RedisConnectionString"); - if (!string.IsNullOrEmpty(redisConnectionString)) - { - signalRBuilder.AddStackExchangeRedis(redisConnectionString, options => Configuration.GetSection("SignalR:RedisOptions").Bind(options)); - } - } - - private void AddProxyServices(IServiceCollection services, Action configureOptions) - { - services.AddTransient>() - .AddIdentityProviderStore() - .AddOperationalHttpStores() - .AddIdentity( - options => Configuration.GetSection(nameof(IdentityOptions)).Bind(options)) - .AddTheIdServerStores(configureOptions) - .AddDefaultTokenProviders(); - } - - private void ConfigureInitialData(IApplicationBuilder app) - { - var dbType = Configuration.GetValue("DbType"); - if (Configuration.GetValue("Migrate") && - dbType != DbTypes.InMemory) - { - using var scope = app.ApplicationServices.CreateScope(); - var configContext = scope.ServiceProvider.GetRequiredService(); - configContext.Database.Migrate(); - - var opContext = scope.ServiceProvider.GetRequiredService(); - opContext.Database.Migrate(); - - var appcontext = scope.ServiceProvider.GetService(); - appcontext.Database.Migrate(); - } - - if (Configuration.GetValue("Seed")) - { - using var scope = app.ApplicationServices.CreateScope(); - SeedData.SeedConfiguration(scope, Configuration); - SeedData.SeedUsers(scope, Configuration); - } - - } - private void ConfigureDataProtection(IServiceCollection services) - { - var dataprotectionSection = Configuration.GetSection(nameof(DataProtectionOptions)); - if (dataprotectionSection != null) - { - services.AddDataProtection(options => dataprotectionSection.Bind(options)).ConfigureDataProtection(Configuration.GetSection(nameof(DataProtectionOptions))); - } - } + if (forceHttpsScheme) + { + app.Use((context, next) => + { + context.Request.Scheme = "https"; + return next(); + }); + } + } + + private void ConfigureIdentityServerAuthenticationOptions(JwtBearerOptions options) + { + Configuration.GetSection("ApiAuthentication").Bind(options); + if (Configuration.GetValue("DisableStrictSsl")) + { + options.BackchannelHttpHandler = new HttpClientHandler + { +#pragma warning disable S4830 // Server certificates should be verified during SSL/TLS connections + ServerCertificateCustomValidationCallback = (message, cert, chain, policy) => true +#pragma warning restore S4830 // Server certificates should be verified during SSL/TLS connections + }; + } + options.Audience = Configuration["ApiAuthentication:ApiName"]; + options.Events = new JwtBearerEvents + { + OnMessageReceived = context => + { + var request = context.HttpContext.Request; + var path = request.Path; + var accessToken = TokenRetrieval.FromQueryString()(request); + if (path.StartsWithSegments("/providerhub") && !string.IsNullOrEmpty(accessToken)) + { + context.Token = accessToken; + return Task.CompletedTask; + } + var oneTimeToken = TokenRetrieval.FromQueryString("otk")(request); + if (!string.IsNullOrEmpty(oneTimeToken)) + { + context.Token = request.HttpContext + .RequestServices + .GetRequiredService() + .GetOneTimeToken(oneTimeToken); + return Task.CompletedTask; + } + context.Token = TokenRetrieval.FromAuthorizationHeader()(request); + return Task.CompletedTask; + } + }; + + options.ForwardDefaultSelector = context => + { + var authHeader = context.Request.Headers[HttpRequestHeader.Authorization.ToString()]; + if (string.IsNullOrEmpty(authHeader)) + { + return null; + } + + var parts = authHeader.First().Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (parts.Length != 2) + { + return null; + } + + if (!parts[1].Contains(".")) + { + return "introspection"; + } + + return null; + }; + } + + private void ConfigureIdentityServerAuthenticationOptions(OAuth2IntrospectionOptions options) + { + Configuration.GetSection("ApiAuthentication").Bind(options); + options.ClientId = Configuration.GetValue("ApiAuthentication:ApiName"); + options.ClientSecret = Configuration.GetValue("ApiAuthentication:ApiSecret"); + static string tokenRetriever(HttpRequest request) + { + var path = request.Path; + var accessToken = TokenRetrieval.FromQueryString()(request); + if (path.StartsWithSegments("/providerhub") && !string.IsNullOrEmpty(accessToken)) + { + return accessToken; + } + var oneTimeToken = TokenRetrieval.FromQueryString("otk")(request); + if (!string.IsNullOrEmpty(oneTimeToken)) + { + return request.HttpContext + .RequestServices + .GetRequiredService() + .GetOneTimeToken(oneTimeToken); + } + return TokenRetrieval.FromAuthorizationHeader()(request); + } + + options.TokenRetriever = tokenRetriever; + } + + private void AddDefaultServices(IServiceCollection services) + { + services.Configure(options => Configuration.GetSection("ApiAuthentication").Bind(options)) + .AddIdentityProviderStore(); + + var identityBuilder = services.AddIdentity( + options => Configuration.GetSection(nameof(IdentityOptions)).Bind(options)) + .AddDefaultTokenProviders(); + + if (DbType == DbTypes.RavenDb) + { + services.Configure(options => Configuration.GetSection(nameof(RavenDbOptions)).Bind(options)) + .AddSingleton(p => + { + var options = p.GetRequiredService>().Value; + var documentStore = new DocumentStore + { + Urls = options.Urls, + Database = options.Database, + }; + if (!string.IsNullOrWhiteSpace(options.CertificatePath)) + { + documentStore.Certificate = new X509Certificate2(options.CertificatePath, options.CertificatePassword); + } + documentStore.SetFindIdentityPropertyForIdentityServerStores(); + return documentStore.Initialize(); + }) + .AddTransient>() + .AddIdentityServer4AdminRavenDbkStores() + .AddConfigurationRavenDbkStores() + .AddOperationalRavenDbStores(); + + identityBuilder.AddRavenDbStores(); + } + else + { + services.AddTransient>() + .AddDbContext(options => options.UseDatabaseFromConfiguration(Configuration)) + .AddIdentityServer4AdminEntityFrameworkStores() + .AddConfigurationEntityFrameworkStores(options => options.UseDatabaseFromConfiguration(Configuration)) + .AddOperationalEntityFrameworkStores(options => options.UseDatabaseFromConfiguration(Configuration)); + + identityBuilder.AddEntityFrameworkStores(); + } + + + var signalRBuilder = services.AddSignalR(options => Configuration.GetSection("SignalR:HubOptions").Bind(options)); + if (Configuration.GetValue("SignalR:UseMessagePack")) + { + signalRBuilder.AddMessagePackProtocol(); + } + + var redisConnectionString = Configuration.GetValue("SignalR:RedisConnectionString"); + if (!string.IsNullOrEmpty(redisConnectionString)) + { + signalRBuilder.AddStackExchangeRedis(redisConnectionString, options => Configuration.GetSection("SignalR:RedisOptions").Bind(options)); + } + } + + private void AddProxyServices(IServiceCollection services, Action configureOptions) + { + services.AddTransient>() + .AddIdentityProviderStore() + .AddOperationalHttpStores() + .AddIdentity( + options => Configuration.GetSection(nameof(IdentityOptions)).Bind(options)) + .AddTheIdServerStores(configureOptions) + .AddDefaultTokenProviders(); + } + + private void ConfigureInitialData(IApplicationBuilder app) + { + var dbType = Configuration.GetValue("DbType"); + if (Configuration.GetValue("Migrate") && + dbType != DbTypes.InMemory && dbType != DbTypes.RavenDb) + { + using var scope = app.ApplicationServices.CreateScope(); + var configContext = scope.ServiceProvider.GetRequiredService(); + configContext.Database.Migrate(); + + var opContext = scope.ServiceProvider.GetRequiredService(); + opContext.Database.Migrate(); + + var appcontext = scope.ServiceProvider.GetService(); + appcontext.Database.Migrate(); + } + + if (Configuration.GetValue("Seed")) + { + using var scope = app.ApplicationServices.CreateScope(); + SeedData.SeedConfiguration(scope, Configuration); + SeedData.SeedUsers(scope, Configuration); + } + + } + private void ConfigureDataProtection(IServiceCollection services) + { + var dataprotectionSection = Configuration.GetSection(nameof(DataProtectionOptions)); + if (dataprotectionSection != null) + { + services.AddDataProtection(options => dataprotectionSection.Bind(options)).ConfigureDataProtection(Configuration.GetSection(nameof(DataProtectionOptions))); + } + } } -} \ No newline at end of file +} diff --git a/src/Aguacongas.TheIdServer/appsettings.Development.json b/src/Aguacongas.TheIdServer/appsettings.Development.json index 84cf9f0ef..a06bbf568 100644 --- a/src/Aguacongas.TheIdServer/appsettings.Development.json +++ b/src/Aguacongas.TheIdServer/appsettings.Development.json @@ -1,10 +1,15 @@ -{ +{ + "DbType": "RavenDb", "IdentityServer": { "Key": { "KeyRotationOptions": { "NewKeyLifetime": "14.00:00:00", "KeyPropagationWindow": "30.00:00:00" - } + }, + "StorageKind": "RavenDb" } + }, + "DataProtectionOptions": { + "StorageKind": "RavenDb" } } \ No newline at end of file diff --git a/src/Aguacongas.TheIdServer/appsettings.json b/src/Aguacongas.TheIdServer/appsettings.json index f859da307..7f25f4d2b 100644 --- a/src/Aguacongas.TheIdServer/appsettings.json +++ b/src/Aguacongas.TheIdServer/appsettings.json @@ -2,6 +2,16 @@ "ConnectionStrings": { "DefaultConnection": "Data Source=(LocalDb)\\MSSQLLocalDB;database=TheIdServer;trusted_connection=yes;" }, + "RavenDbOptions": { + "Urls": [ + "https://a.ravendb.local", + "https://b.ravendb.local", + "https://c.ravendb.local" + ], + "Database": "TheIdServer", + "CertificatePath": "TheIdServer.pfx", + "CertificatePassword": "TheIdServer" + }, "SiteOptions": { "Name": "TheIdServer" }, diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Components/Aguacongas.TheIdServer.BlazorApp.Components.csproj b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Components/Aguacongas.TheIdServer.BlazorApp.Components.csproj index a2e8dd05b..7e3862788 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Components/Aguacongas.TheIdServer.BlazorApp.Components.csproj +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Components/Aguacongas.TheIdServer.BlazorApp.Components.csproj @@ -11,7 +11,7 @@ theidserver;identityserver4;oidc;oauth;identity,authentication;security TheIdServer administration application components. Full - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png ..\..\..\.sonarlint\aguacongas_theidservercsharp.ruleset @@ -20,8 +20,8 @@ - - + + diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Components/EntitesGridModel.cs b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Components/EntitesGridModel.cs index a38bd7c26..e2cbb8478 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Components/EntitesGridModel.cs +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Components/EntitesGridModel.cs @@ -52,7 +52,7 @@ protected virtual void OnStort(SortEventArgs arg) private void HandleModificationState_OnStateChange(ModificationKind kind, object entity) { - if (entity is T) + if (entity is T && (kind == ModificationKind.Add || kind == ModificationKind.Delete)) { StateHasChanged(); } diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Aguacongas.TheIdServer.BlazorApp.Infrastructure.csproj b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Aguacongas.TheIdServer.BlazorApp.Infrastructure.csproj index 31324e5cb..72cbf928f 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Aguacongas.TheIdServer.BlazorApp.Infrastructure.csproj +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Aguacongas.TheIdServer.BlazorApp.Infrastructure.csproj @@ -12,7 +12,7 @@ TheIdServer administration application models, services, validators and extensions. Full Aguacongas.TheIdServer.BlazorApp - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png ..\..\..\.sonarlint\aguacongas_theidservercsharp.ruleset @@ -21,13 +21,13 @@ - - - + + + - - - + + + diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Extensions/WebAssemblyHostBuilderExtensions.cs b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Extensions/WebAssemblyHostBuilderExtensions.cs index a30de9cfa..8cb3eeb24 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Extensions/WebAssemblyHostBuilderExtensions.cs +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Extensions/WebAssemblyHostBuilderExtensions.cs @@ -77,10 +77,10 @@ public static void ConfigureServices(IServiceCollection services, IConfiguration .AddHttpMessageHandler(); services.AddScoped() - .AddTransient>(p => + .AddTransient(p => { var factory = p.GetRequiredService(); - return new AdminStore(Task.FromResult(factory.CreateClient("localizer")), p.GetRequiredService>>()); + return new ReadOnlyLocalizedResourceStore(new AdminStore(Task.FromResult(factory.CreateClient("localizer")), p.GetRequiredService>>())); }).AddTransient(p => { var factory = p.GetRequiredService(); diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Services/IReadOnlyLocalizedResourceStore.cs b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Services/IReadOnlyLocalizedResourceStore.cs new file mode 100644 index 000000000..136a1fffe --- /dev/null +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Services/IReadOnlyLocalizedResourceStore.cs @@ -0,0 +1,14 @@ +// Project: Aguafrommars/TheIdServer +// Copyright (c) 2021 @Olivier Lefebvre +using Aguacongas.IdentityServer.Store; +using Aguacongas.IdentityServer.Store.Entity; +using System.Threading; +using System.Threading.Tasks; + +namespace Aguacongas.TheIdServer.BlazorApp.Services +{ + public interface IReadOnlyLocalizedResourceStore + { + Task> GetAsync(PageRequest pageRequest, CancellationToken cancellationToken = default); + } +} diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Services/ReadOnlyLocalizedResourceStore.cs b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Services/ReadOnlyLocalizedResourceStore.cs new file mode 100644 index 000000000..e3ff67f77 --- /dev/null +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Services/ReadOnlyLocalizedResourceStore.cs @@ -0,0 +1,23 @@ +// Project: Aguafrommars/TheIdServer +// Copyright (c) 2021 @Olivier Lefebvre +using Aguacongas.IdentityServer.Store; +using Aguacongas.IdentityServer.Store.Entity; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Aguacongas.TheIdServer.BlazorApp.Services +{ + public class ReadOnlyLocalizedResourceStore : IReadOnlyLocalizedResourceStore + { + private readonly IAdminStore _adminStore; + + public ReadOnlyLocalizedResourceStore(IAdminStore adminStore) + { + _adminStore = adminStore ?? throw new ArgumentNullException(nameof(adminStore)); + } + + public Task> GetAsync(PageRequest pageRequest, CancellationToken cancellationToken = default) + => _adminStore.GetAsync(pageRequest, cancellationToken); + } +} diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Services/StringLocalizer.cs b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Services/StringLocalizer.cs index 7e6bca509..27aa83958 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Services/StringLocalizer.cs +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/Services/StringLocalizer.cs @@ -16,7 +16,7 @@ namespace Aguacongas.TheIdServer.BlazorApp.Infrastructure.Services { public class StringLocalizer : ISharedStringLocalizerAsync { - private readonly IAdminStore _store; + private readonly IReadOnlyLocalizedResourceStore _store; private readonly IReadOnlyCultureStore _cultureStore; private IEnumerable _resources; private IEnumerable _cultureList; @@ -28,7 +28,7 @@ public class StringLocalizer : ISharedStringLocalizerAsync public event Action ResourceReady; - public StringLocalizer(IAdminStore store, + public StringLocalizer(IReadOnlyLocalizedResourceStore store, IReadOnlyCultureStore cultureStore, ILogger logger) { @@ -219,7 +219,7 @@ public void Dispose() [SuppressMessage("Major Code Smell", "S2326:Unused type parameters should be removed", Justification = "Create an instance by T")] public class SharedStringLocalizer : StringLocalizer { - public SharedStringLocalizer(IAdminStore store, + public SharedStringLocalizer(IReadOnlyLocalizedResourceStore store, IReadOnlyCultureStore cultureStore, ILogger> logger) : base(store, cultureStore, logger) diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/wwwroot/TheIdServerInterop.js b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/wwwroot/TheIdServerInterop.js index d4d7c64d3..80f483192 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/wwwroot/TheIdServerInterop.js +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Infrastructure/wwwroot/TheIdServerInterop.js @@ -3,7 +3,7 @@ const query = `#${id}`; $(query).on('hidden.bs.toast', function () { dotnetHelper.invokeMethodAsync('ToastClosed', id) - .then(_ => { }); + .then(_ => { /* invoke it */ }); }); $(query).toast('show'); }, @@ -34,7 +34,7 @@ window.browserInteropt = { if (key === 13) { e.preventDefault(); dotnetHelper.invokeMethodAsync('EnterKeyPressed', id) - .then(_ => { }); + .then(_ => { /* invoke it */ }); } }; }, diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Api/Aguacongas.TheIdServer.BlazorApp.Pages.Api.csproj b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Api/Aguacongas.TheIdServer.BlazorApp.Pages.Api.csproj index 40763effa..0a93ca78b 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Api/Aguacongas.TheIdServer.BlazorApp.Pages.Api.csproj +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Api/Aguacongas.TheIdServer.BlazorApp.Pages.Api.csproj @@ -11,7 +11,7 @@ theidserver;identityserver4;oidc;oauth;identity,authentication;security TheIdServer administration application api page and components. Full - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png ..\..\..\.sonarlint\aguacongas_theidservercsharp.ruleset @@ -25,7 +25,7 @@ - + diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScope/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScope.csproj b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScope/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScope.csproj index 3668c1c89..4749dda59 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScope/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScope.csproj +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScope/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScope.csproj @@ -11,7 +11,7 @@ theidserver;identityserver4;oidc;oauth;identity,authentication;security TheIdServer administration application api scope page and components. Full - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png ..\..\..\.sonarlint\aguacongas_theidservercsharp.ruleset @@ -25,7 +25,7 @@ - + diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScopes/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScopes.csproj b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScopes/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScopes.csproj index fcb7431e8..4c0ebf6bc 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScopes/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScopes.csproj +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScopes/Aguacongas.TheIdServer.BlazorApp.Pages.ApiScopes.csproj @@ -11,7 +11,7 @@ theidserver;identityserver4;oidc;oauth;identity,authentication;security TheIdServer administration application api scope list page. Full - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png ..\..\..\.sonarlint\aguacongas_theidservercsharp.ruleset @@ -25,7 +25,7 @@ - + diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Apis/Aguacongas.TheIdServer.BlazorApp.Pages.Apis.csproj b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Apis/Aguacongas.TheIdServer.BlazorApp.Pages.Apis.csproj index 0d6805c4f..a146c0a7f 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Apis/Aguacongas.TheIdServer.BlazorApp.Pages.Apis.csproj +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Apis/Aguacongas.TheIdServer.BlazorApp.Pages.Apis.csproj @@ -11,7 +11,7 @@ theidserver;identityserver4;oidc;oauth;identity,authentication;security TheIdServer administration application api list page. Full - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png ..\..\..\.sonarlint\aguacongas_theidservercsharp.ruleset @@ -25,7 +25,7 @@ - + diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Aguacongas.TheIdServer.BlazorApp.Pages.Client.csproj b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Aguacongas.TheIdServer.BlazorApp.Pages.Client.csproj index e3feebf5a..10eb14767 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Aguacongas.TheIdServer.BlazorApp.Pages.Client.csproj +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Aguacongas.TheIdServer.BlazorApp.Pages.Client.csproj @@ -11,7 +11,7 @@ theidserver;identityserver4;oidc;oauth;identity,authentication;security TheIdServer administration application client page and components. Full - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png ..\..\..\.sonarlint\aguacongas_theidservercsharp.ruleset @@ -25,7 +25,7 @@ - + diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Client.razor b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Client.razor index d1db9ecda..2efad63f3 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Client.razor +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Client.razor @@ -156,14 +156,7 @@ else -
-
- -
-
- -
-
+
diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Client.razor.cs b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Client.razor.cs index c6ee5ffd4..a68b6babf 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Client.razor.cs +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Client.razor.cs @@ -127,9 +127,6 @@ private static Entity.ClientSecret CreateSecret() Type = "SharedSecret" }; - private static Entity.ClientUri CreateRedirectUri() - => new(); - private static Entity.ClientClaim CreateClaim() => new(); diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientScope.razor b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientScope.razor index 2fea6fedd..2d7d16c26 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientScope.razor +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientScope.razor @@ -31,13 +31,11 @@ else @scope.Value @if (scope.IsIdentity) { - @Localizer["identity"] +  @Localizer["identity"] } else { - - @Localizer["api"] - +  @Localizer["api"] }
@scope.Description diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientScope.razor.cs b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientScope.razor.cs index 1eb59b5a3..dbc263466 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientScope.razor.cs +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientScope.razor.cs @@ -48,27 +48,25 @@ protected override async Task> GetFilteredValues(string term { _idPageRequest.Filter = $"contains({nameof(entity.IdentityResource.Id)},'{term}') or contains({nameof(entity.IdentityResource.DisplayName)},'{term}')"; _scopeRequest.Filter = $"contains({nameof(entity.ApiScope.Id)},'{term}') or contains({nameof(entity.ApiScope.DisplayName)},'{term}')"; - var identityResponse = _identityStore.GetAsync(_idPageRequest); - var apiScopeResponse = _apiScopeStore.GetAsync(_scopeRequest); + var identityResponse = await _identityStore.GetAsync(_idPageRequest).ConfigureAwait(false); + var apiScopeResponse = await _apiScopeStore.GetAsync(_scopeRequest).ConfigureAwait(false); - await Task.WhenAll(identityResponse, apiScopeResponse) - .ConfigureAwait(false); var culture = CultureInfo.CurrentCulture.Name; - _filterScopes = identityResponse.Result.Items.Select(i => new Scope - { - Value = i.Id, - Description = i.Resources.FirstOrDefault(r => r.ResourceKind == entity.EntityResourceKind.DisplayName && r.CultureId == culture)?.Value - ?? i.DisplayName, - IsIdentity = true - }) - .Union(apiScopeResponse.Result.Items.Select(s => new Scope + _filterScopes = identityResponse.Items.Select(i => new Scope + { + Value = i.Id, + Description = i.Resources.FirstOrDefault(r => r.ResourceKind == entity.EntityResourceKind.DisplayName && r.CultureId == culture)?.Value + ?? i.DisplayName, + IsIdentity = true + }) + .Union(apiScopeResponse.Items.Select(s => new Scope { Value = s.Id, Description = s.Resources.FirstOrDefault(r => r.ResourceKind == entity.EntityResourceKind.DisplayName && r.CultureId == culture)?.Value ?? s.DisplayName })) .Distinct(_comparer) - .Where(s => !Model.AllowedScopes.Any(cs => cs.Id != null && s.Value == cs.Scope)) + .Where(s => Model.AllowedScopes != null && !Model.AllowedScopes.Any(cs => cs.Id != null && s.Value == cs.Scope)) .Take(5) .OrderBy(r => r.Value); diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientUris.razor.cs b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientUris.razor.cs index 97343eb66..3c8ec68e5 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientUris.razor.cs +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientUris.razor.cs @@ -1,6 +1,7 @@ // Project: Aguafrommars/TheIdServer // Copyright (c) 2021 @Olivier Lefebvre using Aguacongas.TheIdServer.BlazorApp.Models; +using Aguacongas.TheIdServer.BlazorApp.Services; using Microsoft.AspNetCore.Components; using System; using System.Collections.Generic; @@ -15,13 +16,12 @@ public partial class ClientUris [Parameter] public Entity.Client Model { get; set; } - + protected override void OnInitialized() { base.OnInitialized(); Collection = Collection.OrderBy(u => u.Uri).ToList(); } - protected override void OnStort(SortEventArgs arg) { if (arg.OrderBy.StartsWith(nameof(Entity.ClientUri.Uri))) diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientUrisPanel.razor b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientUrisPanel.razor new file mode 100644 index 000000000..5f0fc69c8 --- /dev/null +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientUrisPanel.razor @@ -0,0 +1,8 @@ +
+
+ +
+
+ +
+
\ No newline at end of file diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientUrisPanel.razor.cs b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientUrisPanel.razor.cs new file mode 100644 index 000000000..e983253cb --- /dev/null +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/ClientUrisPanel.razor.cs @@ -0,0 +1,33 @@ +// Project: Aguafrommars/TheIdServer +// Copyright (c) 2021 @Olivier Lefebvre +using Aguacongas.TheIdServer.BlazorApp.Services; +using Microsoft.AspNetCore.Components; +using Entity = Aguacongas.IdentityServer.Store.Entity; + +namespace Aguacongas.TheIdServer.BlazorApp.Pages.Client.Components +{ + public partial class ClientUrisPanel + { + [Parameter] + public Entity.Client Model { get; set; } + + [CascadingParameter] + public HandleModificationState HandleModificationState { get; set; } + + protected override void OnInitialized() + { + HandleModificationState.OnStateChange += HandleModificationState_OnStateChange; + } + + private void HandleModificationState_OnStateChange(ModificationKind kind, object entity) + { + if (kind == ModificationKind.Add && entity is Entity.ClientUri) + { + StateHasChanged(); + } + } + + private static Entity.ClientUri CreateRedirectUri() + => new(); + } +} diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/IdentityProvider.razor b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/IdentityProvider.razor index 6f4136dcc..54779f704 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/IdentityProvider.razor +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/IdentityProvider.razor @@ -9,8 +9,7 @@
-
- +
} else { diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/IdentityProvider.razor.cs b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/IdentityProvider.razor.cs index 70220b311..7f9700d38 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/IdentityProvider.razor.cs +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Client/Components/IdentityProvider.razor.cs @@ -41,13 +41,14 @@ protected override async Task> GetFilteredValues(string term .ConfigureAwait(false); _filteredProviders = response.Items; - StateHasChanged(); return null; } protected override void SetValue(string inputValue) { - _providerName = _filteredProviders?.FirstOrDefault(p => p.Id == inputValue)?.DisplayName ?? inputValue; + var selected = _filteredProviders?.FirstOrDefault(p => p.Id == inputValue); + _providerName = selected?.DisplayName ?? inputValue; + Entity.Provider = selected?.Id ?? inputValue; } private async Task GetProviderName(string id) diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Clients/Aguacongas.TheIdServer.BlazorApp.Pages.Clients.csproj b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Clients/Aguacongas.TheIdServer.BlazorApp.Pages.Clients.csproj index cca82bd7a..21e24af65 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Clients/Aguacongas.TheIdServer.BlazorApp.Pages.Clients.csproj +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Clients/Aguacongas.TheIdServer.BlazorApp.Pages.Clients.csproj @@ -11,7 +11,7 @@ theidserver;identityserver4;oidc;oauth;identity,authentication;security TheIdServer administration application client list page. Full - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png ..\..\..\.sonarlint\aguacongas_theidservercsharp.ruleset @@ -25,7 +25,7 @@ - + diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Culture/Aguacongas.TheIdServer.BlazorApp.Pages.Culture.csproj b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Culture/Aguacongas.TheIdServer.BlazorApp.Pages.Culture.csproj index 3953df1bb..094e2377f 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Culture/Aguacongas.TheIdServer.BlazorApp.Pages.Culture.csproj +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Culture/Aguacongas.TheIdServer.BlazorApp.Pages.Culture.csproj @@ -11,7 +11,7 @@ theidserver;identityserver4;oidc;oauth;identity,authentication;security TheIdServer administration application culture page and components. Full - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png ..\..\..\.sonarlint\aguacongas_theidservercsharp.ruleset @@ -25,7 +25,7 @@ - + diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Cultures/Aguacongas.TheIdServer.BlazorApp.Pages.Cultures.csproj b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Cultures/Aguacongas.TheIdServer.BlazorApp.Pages.Cultures.csproj index c08b9e9d2..ff56876f2 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Cultures/Aguacongas.TheIdServer.BlazorApp.Pages.Cultures.csproj +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.Cultures/Aguacongas.TheIdServer.BlazorApp.Pages.Cultures.csproj @@ -11,7 +11,7 @@ theidserver;identityserver4;oidc;oauth;identity,authentication;security TheIdServer administration application culture list page. Full - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png ..\..\..\.sonarlint\aguacongas_theidservercsharp.ruleset @@ -25,7 +25,7 @@ - + diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ExternalProvider/Aguacongas.TheIdServer.BlazorApp.Pages.ExternalProvider.csproj b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ExternalProvider/Aguacongas.TheIdServer.BlazorApp.Pages.ExternalProvider.csproj index 813a6aac9..da8913948 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ExternalProvider/Aguacongas.TheIdServer.BlazorApp.Pages.ExternalProvider.csproj +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ExternalProvider/Aguacongas.TheIdServer.BlazorApp.Pages.ExternalProvider.csproj @@ -11,7 +11,7 @@ theidserver;identityserver4;oidc;oauth;identity,authentication;security TheIdServer administration application external provider page and components. Full - https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png + https://raw.githubusercontent.com/Aguafrommars/TheIdServer/master/package-icon.png ..\..\..\.sonarlint\aguacongas_theidservercsharp.ruleset @@ -25,7 +25,7 @@ - + diff --git a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ExternalProvider/Components/OpenIdConnectOptionsComponent.razor b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ExternalProvider/Components/OpenIdConnectOptionsComponent.razor index 4a2153643..841740318 100644 --- a/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ExternalProvider/Components/OpenIdConnectOptionsComponent.razor +++ b/src/BlazorApp/Aguacongas.TheIdServer.BlazorApp.Pages.ExternalProvider/Components/OpenIdConnectOptionsComponent.razor @@ -72,6 +72,22 @@
+
+ +
+ +
+
+
+ +
+ +
+