diff --git a/Directory.Build.props b/Directory.Build.props index a58bedbbc..f8915f986 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 5.0.0 + 5.0.1 SimpleIdServer SimpleIdServer diff --git a/SimpleIdServer.CredentialIssuer.Host.sln b/SimpleIdServer.CredentialIssuer.Host.sln index 3293cc48b..da7abdd20 100644 --- a/SimpleIdServer.CredentialIssuer.Host.sln +++ b/SimpleIdServer.CredentialIssuer.Host.sln @@ -35,6 +35,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.CredentialIs EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "json-ld.net", "json-ld.net\src\json-ld.net\json-ld.net.csproj", "{B51DC1D9-4A57-4D36-B61C-F93D61878321}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleIdServer.CredentialIssuer.Console", "src\CredentialIssuer\SimpleIdServer.CredentialIssuer.Console\SimpleIdServer.CredentialIssuer.Console.csproj", "{DAB56B5C-8F1B-4B56-90A0-DB19332D8630}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -89,6 +91,10 @@ Global {B51DC1D9-4A57-4D36-B61C-F93D61878321}.Debug|Any CPU.Build.0 = Debug|Any CPU {B51DC1D9-4A57-4D36-B61C-F93D61878321}.Release|Any CPU.ActiveCfg = Release|Any CPU {B51DC1D9-4A57-4D36-B61C-F93D61878321}.Release|Any CPU.Build.0 = Release|Any CPU + {DAB56B5C-8F1B-4B56-90A0-DB19332D8630}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DAB56B5C-8F1B-4B56-90A0-DB19332D8630}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DAB56B5C-8F1B-4B56-90A0-DB19332D8630}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DAB56B5C-8F1B-4B56-90A0-DB19332D8630}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -107,6 +113,7 @@ Global {6B7D2058-4163-4D5B-B002-FBBCD26C80FB} = {E81A364B-F1A9-4BAB-95F9-8163AF8A0FD9} {651DAE84-AB36-4D05-B604-3B4A6C885B05} = {E2AE7484-8B8A-4B03-A5E8-93E65905E3DF} {B51DC1D9-4A57-4D36-B61C-F93D61878321} = {CAD5C508-21EA-441F-843E-0E5B6CB9A102} + {DAB56B5C-8F1B-4B56-90A0-DB19332D8630} = {E2AE7484-8B8A-4B03-A5E8-93E65905E3DF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AEF94609-C4E0-43B5-ACF8-6EE13FDD5804} diff --git a/SimpleIdServer.Federation.sln b/SimpleIdServer.Federation.sln new file mode 100644 index 000000000..3a877b475 --- /dev/null +++ b/SimpleIdServer.Federation.sln @@ -0,0 +1,88 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32328.378 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "02. Startup", "02. Startup", "{A783A4AE-2E11-4A5D-AECE-0FD34981264A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.Federation.Ta.Startup", "src\Federation\SimpleIdServer.Federation.Ta.Startup\SimpleIdServer.Federation.Ta.Startup.csproj", "{38943163-054D-479F-BFC6-828838889307}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "01. Core", "01. Core", "{EAD61669-BE54-4AB9-AEE1-79C2384CC41F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.Authority.Federation", "src\IdServer\SimpleIdServer.Authority.Federation\SimpleIdServer.Authority.Federation.csproj", "{9B2AEBC5-7914-4F93-8AF7-706A99879005}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.OpenidFederation", "src\IdServer\SimpleIdServer.OpenidFederation\SimpleIdServer.OpenidFederation.csproj", "{5F2A66AA-0A03-4651-8408-084BA13E76DE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.Rp.Federation", "src\IdServer\SimpleIdServer.Rp.Federation\SimpleIdServer.Rp.Federation.csproj", "{D9088814-07DD-4BA2-BDE2-8FBBD202EFC9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.DPoP", "src\IdServer\SimpleIdServer.DPoP\SimpleIdServer.DPoP.csproj", "{7B30E4B3-B2E4-42E3-A9AD-E3D609F2B987}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.IdServer.Helpers", "src\IdServer\SimpleIdServer.IdServer.Helpers\SimpleIdServer.IdServer.Helpers.csproj", "{DBB697EC-F7C1-477E-AFAA-BCC4E4D1B64B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.OpenidFederation.Store.EF", "src\IdServer\SimpleIdServer.OpenidFederation.Store.EF\SimpleIdServer.OpenidFederation.Store.EF.csproj", "{8CE25E6F-5710-4314-A89B-F355C22502C3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.Federation.Rp.Startup", "src\Federation\SimpleIdServer.Federation.Rp.Startup\SimpleIdServer.Federation.Rp.Startup.csproj", "{904B2DA2-BDC1-4A81-8B93-1C25BDF2FF35}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.OpenIdConnect", "src\IdServer\SimpleIdServer.OpenIdConnect\SimpleIdServer.OpenIdConnect.csproj", "{36BCF43C-4E39-43EE-8ED0-A5FC7C547D3A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {38943163-054D-479F-BFC6-828838889307}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {38943163-054D-479F-BFC6-828838889307}.Debug|Any CPU.Build.0 = Debug|Any CPU + {38943163-054D-479F-BFC6-828838889307}.Release|Any CPU.ActiveCfg = Release|Any CPU + {38943163-054D-479F-BFC6-828838889307}.Release|Any CPU.Build.0 = Release|Any CPU + {9B2AEBC5-7914-4F93-8AF7-706A99879005}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B2AEBC5-7914-4F93-8AF7-706A99879005}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B2AEBC5-7914-4F93-8AF7-706A99879005}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B2AEBC5-7914-4F93-8AF7-706A99879005}.Release|Any CPU.Build.0 = Release|Any CPU + {5F2A66AA-0A03-4651-8408-084BA13E76DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F2A66AA-0A03-4651-8408-084BA13E76DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F2A66AA-0A03-4651-8408-084BA13E76DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F2A66AA-0A03-4651-8408-084BA13E76DE}.Release|Any CPU.Build.0 = Release|Any CPU + {D9088814-07DD-4BA2-BDE2-8FBBD202EFC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D9088814-07DD-4BA2-BDE2-8FBBD202EFC9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D9088814-07DD-4BA2-BDE2-8FBBD202EFC9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D9088814-07DD-4BA2-BDE2-8FBBD202EFC9}.Release|Any CPU.Build.0 = Release|Any CPU + {7B30E4B3-B2E4-42E3-A9AD-E3D609F2B987}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B30E4B3-B2E4-42E3-A9AD-E3D609F2B987}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B30E4B3-B2E4-42E3-A9AD-E3D609F2B987}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B30E4B3-B2E4-42E3-A9AD-E3D609F2B987}.Release|Any CPU.Build.0 = Release|Any CPU + {DBB697EC-F7C1-477E-AFAA-BCC4E4D1B64B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DBB697EC-F7C1-477E-AFAA-BCC4E4D1B64B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DBB697EC-F7C1-477E-AFAA-BCC4E4D1B64B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DBB697EC-F7C1-477E-AFAA-BCC4E4D1B64B}.Release|Any CPU.Build.0 = Release|Any CPU + {8CE25E6F-5710-4314-A89B-F355C22502C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8CE25E6F-5710-4314-A89B-F355C22502C3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8CE25E6F-5710-4314-A89B-F355C22502C3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8CE25E6F-5710-4314-A89B-F355C22502C3}.Release|Any CPU.Build.0 = Release|Any CPU + {904B2DA2-BDC1-4A81-8B93-1C25BDF2FF35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {904B2DA2-BDC1-4A81-8B93-1C25BDF2FF35}.Debug|Any CPU.Build.0 = Debug|Any CPU + {904B2DA2-BDC1-4A81-8B93-1C25BDF2FF35}.Release|Any CPU.ActiveCfg = Release|Any CPU + {904B2DA2-BDC1-4A81-8B93-1C25BDF2FF35}.Release|Any CPU.Build.0 = Release|Any CPU + {36BCF43C-4E39-43EE-8ED0-A5FC7C547D3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {36BCF43C-4E39-43EE-8ED0-A5FC7C547D3A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {36BCF43C-4E39-43EE-8ED0-A5FC7C547D3A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {36BCF43C-4E39-43EE-8ED0-A5FC7C547D3A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {38943163-054D-479F-BFC6-828838889307} = {A783A4AE-2E11-4A5D-AECE-0FD34981264A} + {9B2AEBC5-7914-4F93-8AF7-706A99879005} = {EAD61669-BE54-4AB9-AEE1-79C2384CC41F} + {5F2A66AA-0A03-4651-8408-084BA13E76DE} = {EAD61669-BE54-4AB9-AEE1-79C2384CC41F} + {D9088814-07DD-4BA2-BDE2-8FBBD202EFC9} = {EAD61669-BE54-4AB9-AEE1-79C2384CC41F} + {7B30E4B3-B2E4-42E3-A9AD-E3D609F2B987} = {EAD61669-BE54-4AB9-AEE1-79C2384CC41F} + {DBB697EC-F7C1-477E-AFAA-BCC4E4D1B64B} = {EAD61669-BE54-4AB9-AEE1-79C2384CC41F} + {8CE25E6F-5710-4314-A89B-F355C22502C3} = {EAD61669-BE54-4AB9-AEE1-79C2384CC41F} + {904B2DA2-BDC1-4A81-8B93-1C25BDF2FF35} = {A783A4AE-2E11-4A5D-AECE-0FD34981264A} + {36BCF43C-4E39-43EE-8ED0-A5FC7C547D3A} = {EAD61669-BE54-4AB9-AEE1-79C2384CC41F} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {48A4817A-3DC6-4471-9D97-4B71EFA432F9} + EndGlobalSection +EndGlobal diff --git a/SimpleIdServer.IdServer.Host.sln b/SimpleIdServer.IdServer.Host.sln index 4cdd47866..3d90b5b37 100644 --- a/SimpleIdServer.IdServer.Host.sln +++ b/SimpleIdServer.IdServer.Host.sln @@ -113,6 +113,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.IdServer.Sto EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.IdServer.SqlSugar.Startup", "src\IdServer\SimpleIdServer.IdServer.SqlSugar.Startup\SimpleIdServer.IdServer.SqlSugar.Startup.csproj", "{0D76EB63-29B1-4878-84D1-2D35897EE1FA}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.SelfIdServer.Host.Acceptance.Tests", "tests\SimpleIdServer.SelfIssuedIdServer.Host.Acceptance.Tests\SimpleIdServer.SelfIdServer.Host.Acceptance.Tests.csproj", "{467B3D10-E6C9-427F-A29F-373AE95ECF69}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "07. OpenidFederation", "07. OpenidFederation", "{0473E3F7-F4CB-4305-A980-174A953CF0DB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.IdServer.Federation", "src\IdServer\SimpleIdServer.IdServer.Federation\SimpleIdServer.IdServer.Federation.csproj", "{4A7E1AFE-98FB-4B40-B41B-A912C448D020}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.OpenidFederation", "src\IdServer\SimpleIdServer.OpenidFederation\SimpleIdServer.OpenidFederation.csproj", "{4D3F4A42-8997-4F4E-AD5D-1A26D25E94B0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.OpenidFederation.Tests", "tests\SimpleIdServer.OpenidFederation.Tests\SimpleIdServer.OpenidFederation.Tests.csproj", "{7B4FB0E4-2B43-4EC4-B978-99E225FBC368}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.Rp.Federation", "src\IdServer\SimpleIdServer.Rp.Federation\SimpleIdServer.Rp.Federation.csproj", "{DC1EBA7B-7458-4AC5-80D4-56E20541C4F4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleIdServer.Authority.Federation", "src\IdServer\SimpleIdServer.Authority.Federation\SimpleIdServer.Authority.Federation.csproj", "{687CFA3C-D027-424A-A15C-B2BF18B58607}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -299,6 +313,30 @@ Global {0D76EB63-29B1-4878-84D1-2D35897EE1FA}.Debug|Any CPU.Build.0 = Debug|Any CPU {0D76EB63-29B1-4878-84D1-2D35897EE1FA}.Release|Any CPU.ActiveCfg = Release|Any CPU {0D76EB63-29B1-4878-84D1-2D35897EE1FA}.Release|Any CPU.Build.0 = Release|Any CPU + {467B3D10-E6C9-427F-A29F-373AE95ECF69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {467B3D10-E6C9-427F-A29F-373AE95ECF69}.Debug|Any CPU.Build.0 = Debug|Any CPU + {467B3D10-E6C9-427F-A29F-373AE95ECF69}.Release|Any CPU.ActiveCfg = Release|Any CPU + {467B3D10-E6C9-427F-A29F-373AE95ECF69}.Release|Any CPU.Build.0 = Release|Any CPU + {4A7E1AFE-98FB-4B40-B41B-A912C448D020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4A7E1AFE-98FB-4B40-B41B-A912C448D020}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4A7E1AFE-98FB-4B40-B41B-A912C448D020}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4A7E1AFE-98FB-4B40-B41B-A912C448D020}.Release|Any CPU.Build.0 = Release|Any CPU + {4D3F4A42-8997-4F4E-AD5D-1A26D25E94B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D3F4A42-8997-4F4E-AD5D-1A26D25E94B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D3F4A42-8997-4F4E-AD5D-1A26D25E94B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D3F4A42-8997-4F4E-AD5D-1A26D25E94B0}.Release|Any CPU.Build.0 = Release|Any CPU + {7B4FB0E4-2B43-4EC4-B978-99E225FBC368}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B4FB0E4-2B43-4EC4-B978-99E225FBC368}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B4FB0E4-2B43-4EC4-B978-99E225FBC368}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B4FB0E4-2B43-4EC4-B978-99E225FBC368}.Release|Any CPU.Build.0 = Release|Any CPU + {DC1EBA7B-7458-4AC5-80D4-56E20541C4F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DC1EBA7B-7458-4AC5-80D4-56E20541C4F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DC1EBA7B-7458-4AC5-80D4-56E20541C4F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DC1EBA7B-7458-4AC5-80D4-56E20541C4F4}.Release|Any CPU.Build.0 = Release|Any CPU + {687CFA3C-D027-424A-A15C-B2BF18B58607}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {687CFA3C-D027-424A-A15C-B2BF18B58607}.Debug|Any CPU.Build.0 = Debug|Any CPU + {687CFA3C-D027-424A-A15C-B2BF18B58607}.Release|Any CPU.ActiveCfg = Release|Any CPU + {687CFA3C-D027-424A-A15C-B2BF18B58607}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -311,7 +349,7 @@ Global {2A0AB899-B02E-449F-B0EA-8BEA4D2FB18A} = {033E4EF3-2FB5-450A-9B35-616D9B0D6EAA} {CE9CED43-D3D4-4711-A8C1-D0E35D4EB2BD} = {E5886E09-671E-4B3E-AA8F-824C39DF94E4} {DE396E1F-F734-4835-9557-65D559C2953A} = {E5886E09-671E-4B3E-AA8F-824C39DF94E4} - {15CD3447-BC21-4D46-AD8A-E76685376077} = {4796A22B-91A9-42AF-87CA-F69392696B0A} + {15CD3447-BC21-4D46-AD8A-E76685376077} = {654E3738-8074-4079-AE56-8B2C31BE6781} {25E98779-29F9-4C74-A935-15D20D9F0E0E} = {15CD3447-BC21-4D46-AD8A-E76685376077} {EA9F6F0A-5F8A-454D-A682-7CADD6704C44} = {033E4EF3-2FB5-450A-9B35-616D9B0D6EAA} {83A19793-668C-46B6-B1D7-134DFED8B430} = {4796A22B-91A9-42AF-87CA-F69392696B0A} @@ -355,6 +393,13 @@ Global {06BF894C-69D7-406A-A97F-BD990A3D59ED} = {4796A22B-91A9-42AF-87CA-F69392696B0A} {BE501B31-2CF6-4218-AA74-F536C11AD9D7} = {06BF894C-69D7-406A-A97F-BD990A3D59ED} {0D76EB63-29B1-4878-84D1-2D35897EE1FA} = {68306EFF-55D9-497B-9482-FEB81C485914} + {467B3D10-E6C9-427F-A29F-373AE95ECF69} = {033E4EF3-2FB5-450A-9B35-616D9B0D6EAA} + {0473E3F7-F4CB-4305-A980-174A953CF0DB} = {4796A22B-91A9-42AF-87CA-F69392696B0A} + {4A7E1AFE-98FB-4B40-B41B-A912C448D020} = {0473E3F7-F4CB-4305-A980-174A953CF0DB} + {4D3F4A42-8997-4F4E-AD5D-1A26D25E94B0} = {0473E3F7-F4CB-4305-A980-174A953CF0DB} + {7B4FB0E4-2B43-4EC4-B978-99E225FBC368} = {033E4EF3-2FB5-450A-9B35-616D9B0D6EAA} + {DC1EBA7B-7458-4AC5-80D4-56E20541C4F4} = {0473E3F7-F4CB-4305-A980-174A953CF0DB} + {687CFA3C-D027-424A-A15C-B2BF18B58607} = {0473E3F7-F4CB-4305-A980-174A953CF0DB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1FE1E2C8-475E-4592-8609-D331B1D01730} diff --git a/TODO.txt b/TODO.txt index b510902ed..b5061ed90 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,9 +1,9 @@ -Install OPENLDAP server - -docker run --name openldap-server -p 389:389 -p 636:636 --env LDAP_ORGANISATION="sid" --env LDAP_DOMAIN="sid.com" --env LDAP_BASE_DN="dc=sid,dc=com" --env LDAP_ADMIN_PASSWORD="password" osixia/openldap:latest - -Quand un utilisateur est reçu de "SCIM" ou "LDAP", un utilisateur est créé, nous pouvons lui envoyer un mot de passe temporaire par email. - -Comprendre l'utilité d'utiliser un workflow pour cela. - -Découvrir comment les autres applications gèrent les concepts d'IAM. \ No newline at end of file +=> corriger problème avec credential issuer : OK +=> mettre à jour fichier de configuration docker : OK +=> publier version 5.0.0 du site : OK +=> mettre à jour les templates : OK +=> vérifier les tests unitaires du credential issuer : TODO +=> essayer de migrer l'application mobile vers DOTNET8 : TODO +=> publier les nuget packages : TODO +=> vérifier si les templates fonctionnent : TODO +=> publier les projets DOCKER : TODO \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 5aeec62cd..77c7fb439 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,12 +25,10 @@ deploy: secure: kSru0/Mz8HMao/s+D3eNoTjOdwYRKMESn144kSw8tWrIKZGNCWDKL5Zh57ca9LwP on: branch: master - appveyor_repo_tag: true - provider: GitHub auth_token: secure: FJAvb5bFQzM98phfQ2/dLL7I10Hvof/fdHorRLuDId8PyjAxcdkfWYf5fZ0/0g+e artifact: /.*\.zip/ on: branch: master - appveyor_repo_tag: true \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1a9debd4d..f519a34a6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -86,7 +86,7 @@ steps: inputs: command: 'publish' publishWebProjects: false - arguments: '-f net7.0-android -c Release -p:AndroidKeyStore=true -p:AndroidSigningKeyStore=sidmobile.keystore -p:AndroidSigningKeyAlias=sidkey -p:AndroidSigningKeyPass=password -p:AndroidSigningStorePass=password' + arguments: '-f net8.0-android -c Release -p:AndroidKeyStore=true -p:AndroidSigningKeyStore=sidmobile.keystore -p:AndroidSigningKeyAlias=sidkey -p:AndroidSigningKeyPass=password -p:AndroidSigningStorePass=password' zipAfterPublish: false modifyOutputPath: false workingDirectory: '$(Build.Repository.LocalPath)\src\Mobile\SimpleIdServer.Mobile' @@ -101,35 +101,35 @@ steps: - task: CopyFiles@2 displayName: 'Copy SimpleIdServer' inputs: - SourceFolder: '$(Build.Repository.LocalPath)\src\IdServer\SimpleIdServer.IdServer.Startup\bin\Debug\net7.0\publish' + SourceFolder: '$(Build.Repository.LocalPath)\src\IdServer\SimpleIdServer.IdServer.Startup\bin\Release\net8.0\publish' Contents: '**' TargetFolder: '$(Build.ArtifactStagingDirectory)\simpleidserver' - task: CopyFiles@2 displayName: 'Copy SimpleIdServer website' inputs: - SourceFolder: '$(Build.Repository.LocalPath)\src\IdServer\SimpleIdServer.IdServer.Website.Startup\bin\Debug\net7.0\publish' + SourceFolder: '$(Build.Repository.LocalPath)\src\IdServer\SimpleIdServer.IdServer.Website.Startup\bin\Release\net8.0\publish' Contents: '**' TargetFolder: '$(Build.ArtifactStagingDirectory)\simpleidserverwebsite' - task: CopyFiles@2 displayName: 'Copy SCIM' inputs: - SourceFolder: '$(Build.Repository.LocalPath)\src\Scim\SimpleIdServer.Scim.Startup\bin\Debug\net7.0\publish' + SourceFolder: '$(Build.Repository.LocalPath)\src\Scim\SimpleIdServer.Scim.Startup\bin\Release\net8.0\publish' Contents: '**' TargetFolder: '$(Build.ArtifactStagingDirectory)\scim' - task: CopyFiles@2 displayName: 'Copy Credential Issuer' inputs: - SourceFolder: '$(Build.Repository.LocalPath)\src\CredentialIssuer\SimpleIdServer.CredentialIssuer.Startup\bin\Debug\net7.0\publish' + SourceFolder: '$(Build.Repository.LocalPath)\src\CredentialIssuer\SimpleIdServer.CredentialIssuer.Startup\bin\Release\net8.0\publish' Contents: '**' TargetFolder: '$(Build.ArtifactStagingDirectory)\credentialissuer' - task: CopyFiles@2 displayName: 'Copy Credential issuer website' inputs: - SourceFolder: '$(Build.Repository.LocalPath)\src\CredentialIssuer\SimpleIdServer.CredentialIssuer.Website.Startup\bin\Debug\net7.0\publish' + SourceFolder: '$(Build.Repository.LocalPath)\src\CredentialIssuer\SimpleIdServer.CredentialIssuer.Website.Startup\bin\Release\net8.0\publish' Contents: '**' TargetFolder: '$(Build.ArtifactStagingDirectory)\credentialissuerwebsite' @@ -178,6 +178,6 @@ steps: - task: PublishBuildArtifacts@1 displayName: 'Publish Mobile application' inputs: - PathtoPublish: '$(Build.Repository.LocalPath)\src\Mobile\SimpleIdServer.Mobile\bin\Release\net7.0-android\publish' + PathtoPublish: '$(Build.Repository.LocalPath)\src\Mobile\SimpleIdServer.Mobile\bin\Release\net8.0-android\publish' ArtifactName: 'mobileApp' publishLocation: 'Container' \ No newline at end of file diff --git a/default.ps1 b/default.ps1 index e5f3a546b..0217e21d2 100644 --- a/default.ps1 +++ b/default.ps1 @@ -165,6 +165,7 @@ task compile -depends clean { exec { dotnet build .\SimpleIdServer.Scim.Host.sln -c $config --version-suffix=$buildSuffix } exec { dotnet build .\SimpleIdServer.Did.sln -c $config --version-suffix=$buildSuffix } exec { dotnet build .\SimpleIdServer.CredentialIssuer.Host.sln -c $config --version-suffix=$buildSuffix } + exec { dotnet build .\SimpleIdServer.Federation.sln -c $config --version-suffix=$buildSuffix } exec { dotnet build "$source_dir/Templates/SimpleIdServer.Templates.csproj" -c $config --version-suffix=$buildSuffix } } @@ -204,7 +205,6 @@ task pack -depends release, compile, buildTemplate { exec { dotnet pack $source_dir\IdServer\SimpleIdServer.DPoP\SimpleIdServer.DPoP.csproj -c $config --no-build $versionSuffix --output $result_dir } exec { dotnet pack $source_dir\IdServer\SimpleIdServer.Configuration\SimpleIdServer.Configuration.csproj -c $config --no-build $versionSuffix --output $result_dir } exec { dotnet pack $source_dir\IdServer\SimpleIdServer.Configuration.Redis\SimpleIdServer.Configuration.Redis.csproj -c $config --no-build $versionSuffix --output $result_dir } - exec { dotnet pack $source_dir\IdServer\SimpleIdServer.IdServer.Store\SimpleIdServer.IdServer.Store.csproj -c $config --no-build $versionSuffix --output $result_dir } exec { dotnet pack $source_dir\IdServer\SimpleIdServer.IdServer.Store.EF\SimpleIdServer.IdServer.Store.EF.csproj -c $config --no-build $versionSuffix --output $result_dir } exec { dotnet pack $source_dir\IdServer\SimpleIdServer.IdServer.Store.SqlSugar\SimpleIdServer.IdServer.Store.SqlSugar.csproj -c $config --no-build $versionSuffix --output $result_dir } exec { dotnet pack $source_dir\IdServer\SimpleIdServer.IdServer.Website\SimpleIdServer.IdServer.Website.csproj -c $config --no-build $versionSuffix --output $result_dir } @@ -220,6 +220,11 @@ task pack -depends release, compile, buildTemplate { exec { dotnet pack $source_dir\IdServer\SimpleIdServer.OpenIdConnect\SimpleIdServer.OpenIdConnect.csproj -c $config --no-build $versionSuffix --output $result_dir } exec { dotnet pack $source_dir\IdServer\SimpleIdServer.IdServer.Notification.Fcm\SimpleIdServer.IdServer.Notification.Fcm.csproj -c $config --no-build $versionSuffix --output $result_dir } exec { dotnet pack $source_dir\IdServer\SimpleIdServer.IdServer.Notification.Gotify\SimpleIdServer.IdServer.Notification.Gotify.csproj -c $config --no-build $versionSuffix --output $result_dir } + exec { dotnet pack $source_dir\IdServer\SimpleIdServer.OpenidFederation\SimpleIdServer.OpenidFederation.csproj -c $config --no-build $versionSuffix --output $result_dir } + exec { dotnet pack $source_dir\IdServer\SimpleIdServer.OpenidFederation.Store.EF\SimpleIdServer.OpenidFederation.Store.EF.csproj -c $config --no-build $versionSuffix --output $result_dir } + exec { dotnet pack $source_dir\IdServer\SimpleIdServer.IdServer.Federation\SimpleIdServer.IdServer.Federation.csproj -c $config --no-build $versionSuffix --output $result_dir } + exec { dotnet pack $source_dir\IdServer\SimpleIdServer.Authority.Federation\SimpleIdServer.Authority.Federation.csproj -c $config --no-build $versionSuffix --output $result_dir } + exec { dotnet pack $source_dir\IdServer\SimpleIdServer.Rp.Federation\SimpleIdServer.Rp.Federation.csproj -c $config --no-build $versionSuffix --output $result_dir } exec { dotnet pack $source_dir\Scim\SimpleIdServer.Scim\SimpleIdServer.Scim.csproj -c $config --no-build $versionSuffix --output $result_dir } exec { dotnet pack $source_dir\Scim\SimpleIdServer.Scim.Domains\SimpleIdServer.Scim.Domains.csproj -c $config --no-build $versionSuffix --output $result_dir } exec { dotnet pack $source_dir\Scim\SimpleIdServer.Scim.Parser\SimpleIdServer.Scim.Parser.csproj -c $config --no-build $versionSuffix --output $result_dir } @@ -244,47 +249,54 @@ task pack -depends release, compile, buildTemplate { } task test { - Push-Location -Path $base_dir\tests\SimpleIdServer.Configuration.Tests - - try { - exec { & dotnet test -c $config --no-build --no-restore } - } finally { - Pop-Location - } + Push-Location -Path $base_dir\tests\SimpleIdServer.Configuration.Tests - Push-Location -Path $base_dir\tests\SimpleIdServer.CredentialIssuer.Host.Acceptance.Tests - - try { - exec { & dotnet test -c $config --no-build --no-restore } - } finally { - Pop-Location - } + try { + exec { & dotnet test -c $config --no-build --no-restore } + } finally { + Pop-Location + } - Push-Location -Path $base_dir\tests\SimpleIdServer.Did.Ethr.Tests - - try { - exec { & dotnet test -c $config --no-build --no-restore } - } finally { - Pop-Location - } + Push-Location -Path $base_dir\tests\SimpleIdServer.CredentialIssuer.Host.Acceptance.Tests - Push-Location -Path $base_dir\tests\SimpleIdServer.Did.Key.Tests - - try { - exec { & dotnet test -c $config --no-build --no-restore } - } finally { - Pop-Location - } + try { + exec { & dotnet test -c $config --no-build --no-restore } + } finally { + Pop-Location + } + + Push-Location -Path $base_dir\tests\SimpleIdServer.Did.Ethr.Tests + + try { + exec { & dotnet test -c $config --no-build --no-restore } + } finally { + Pop-Location + } + + Push-Location -Path $base_dir\tests\SimpleIdServer.Did.Key.Tests + + try { + exec { & dotnet test -c $config --no-build --no-restore } + } finally { + Pop-Location + } + + Push-Location -Path $base_dir\tests\SimpleIdServer.DID.Tests + + try { + exec { & dotnet test -c $config --no-build --no-restore } + } finally { + Pop-Location + } - Push-Location -Path $base_dir\tests\SimpleIdServer.DID.Tests + Push-Location -Path $base_dir\tests\SimpleIdServer.IdServer.Host.Acceptance.Tests try { exec { & dotnet test -c $config --no-build --no-restore } } finally { Pop-Location } - - Push-Location -Path $base_dir\tests\SimpleIdServer.IdServer.Host.Acceptance.Tests + Push-Location -Path $base_dir\tests\SimpleIdServer.IdServer.Tests try { exec { & dotnet test -c $config --no-build --no-restore } @@ -292,7 +304,7 @@ task test { Pop-Location } - Push-Location -Path $base_dir\tests\SimpleIdServer.IdServer.Tests + Push-Location -Path $base_dir\tests\SimpleIdServer.Scim.Host.Acceptance.Tests try { exec { & dotnet test -c $config --no-build --no-restore } @@ -300,7 +312,7 @@ task test { Pop-Location } - Push-Location -Path $base_dir\tests\SimpleIdServer.Scim.Host.Acceptance.Tests + Push-Location -Path $base_dir\tests\SimpleIdServer.Scim.Tests try { exec { & dotnet test -c $config --no-build --no-restore } @@ -308,7 +320,7 @@ task test { Pop-Location } - Push-Location -Path $base_dir\tests\SimpleIdServer.Scim.Tests + Push-Location -Path $base_dir\tests\SimpleIdServer.Vc.Tests try { exec { & dotnet test -c $config --no-build --no-restore } @@ -316,7 +328,7 @@ task test { Pop-Location } - Push-Location -Path $base_dir\tests\SimpleIdServer.Vc.Tests + Push-Location -Path $base_dir\tests\SimpleIdServer.OpenidFederation.Tests try { exec { & dotnet test -c $config --no-build --no-restore } diff --git a/docker-compose.yml b/docker-compose.yml index 9f2f8ae73..cbeeb64f7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,7 +28,7 @@ services: networks: proxy_net: null scim: - image: simpleidserver/scim:4.0.8 + image: simpleidserver/scim:5.0.1 environment: VIRTUAL_HOST: "scim.localhost.com" ASPNETCORE_URLS : "http://*:80" @@ -40,7 +40,7 @@ services: networks: proxy_net: null idserver: - image: simpleidserver/idserver:4.0.8 + image: simpleidserver/idserver:5.0.1 environment: VIRTUAL_HOST: "idserver.localhost.com" ASPNETCORE_URLS : "http://*:80" @@ -58,12 +58,12 @@ services: networks: proxy_net: null website: - image: simpleidserver/website:4.0.8 + image: simpleidserver/website:5.0.1 environment: VIRTUAL_HOST: "website.localhost.com" ASPNETCORE_URLS : "http://*:80" ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" - DefaultSecurityOptions__Issuer: "https://idserver.localhost.com/master" + DefaultSecurityOptions__Issuer: "https://idserver.localhost.com" DefaultSecurityOptions__IgnoreCertificateError: "true" IdServerBaseUrl: "https://idserver.localhost.com" ScimBaseUrl: "https://scim.localhost.com" @@ -73,7 +73,7 @@ services: networks: proxy_net: null credentialissuer: - image: simpleidserver/credentialissuer:4.0.8 + image: simpleidserver/credentialissuer:5.0.1 environment: VIRTUAL_HOST: "credentialissuer.localhost.com" ASPNETCORE_URLS : "http://*:80" @@ -85,7 +85,7 @@ services: networks: proxy_net: null credentialissuerwebsite: - image: simpleidserver/credentialissuerwebsite:4.0.8 + image: simpleidserver/credentialissuerwebsite:5.0.1 environment: VIRTUAL_HOST: "credentialissuerwebsite.localhost.com" ASPNETCORE_URLS : "http://*:80" diff --git a/local-docker-compose.yml b/local-docker-compose.yml index 1aa31503d..e9e488b9e 100644 --- a/local-docker-compose.yml +++ b/local-docker-compose.yml @@ -72,7 +72,7 @@ services: VIRTUAL_HOST: "website.localhost.com" ASPNETCORE_URLS : "http://*:80" ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" - DefaultSecurityOptions__Issuer: "https://idserver.localhost.com/master" + DefaultSecurityOptions__Issuer: "https://idserver.localhost.com" DefaultSecurityOptions__IgnoreCertificateError: "true" IdServerBaseUrl: "https://idserver.localhost.com" ScimBaseUrl: "https://scim.localhost.com" diff --git a/samples/OpenidFederation/OpenidFederation.sln b/samples/OpenidFederation/OpenidFederation.sln new file mode 100644 index 000000000..9fa10e3f1 --- /dev/null +++ b/samples/OpenidFederation/OpenidFederation.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{7F9A3D8D-4217-4B6B-A18C-44E1CDC2CF82}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TaApi", "src\TaApi\TaApi.csproj", "{10C9ADF1-A71F-453D-95EE-8A37E2832D86}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RpApi", "src\RpApi\RpApi.csproj", "{0EE90864-7273-4218-93C9-412607723BE5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {10C9ADF1-A71F-453D-95EE-8A37E2832D86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {10C9ADF1-A71F-453D-95EE-8A37E2832D86}.Debug|Any CPU.Build.0 = Debug|Any CPU + {10C9ADF1-A71F-453D-95EE-8A37E2832D86}.Release|Any CPU.ActiveCfg = Release|Any CPU + {10C9ADF1-A71F-453D-95EE-8A37E2832D86}.Release|Any CPU.Build.0 = Release|Any CPU + {0EE90864-7273-4218-93C9-412607723BE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0EE90864-7273-4218-93C9-412607723BE5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0EE90864-7273-4218-93C9-412607723BE5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0EE90864-7273-4218-93C9-412607723BE5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {10C9ADF1-A71F-453D-95EE-8A37E2832D86} = {7F9A3D8D-4217-4B6B-A18C-44E1CDC2CF82} + {0EE90864-7273-4218-93C9-412607723BE5} = {7F9A3D8D-4217-4B6B-A18C-44E1CDC2CF82} + EndGlobalSection +EndGlobal diff --git a/samples/OpenidFederation/src/RpApi/Controllers/ClaimsController.cs b/samples/OpenidFederation/src/RpApi/Controllers/ClaimsController.cs new file mode 100644 index 000000000..1fb6eeece --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Controllers/ClaimsController.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using RpApi.ViewModels; + +namespace RpApi.Controllers +{ + public class ClaimsController : Controller + { + [Authorize] + public async Task Index() + { + var accessToken = await HttpContext.GetTokenAsync("access_token"); + return View(new ClaimsViewModel + { + AccessToken = accessToken + }); + } + } +} diff --git a/samples/OpenidFederation/src/RpApi/Controllers/HomeController.cs b/samples/OpenidFederation/src/RpApi/Controllers/HomeController.cs new file mode 100644 index 000000000..16db19730 --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Controllers/HomeController.cs @@ -0,0 +1,31 @@ +using System.Diagnostics; +using Microsoft.AspNetCore.Mvc; +using RpApi.Models; + +namespace RpApi.Controllers; + +public class HomeController : Controller +{ + private readonly ILogger _logger; + + public HomeController(ILogger logger) + { + _logger = logger; + } + + public IActionResult Index() + { + return View(); + } + + public IActionResult Privacy() + { + return View(); + } + + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] + public IActionResult Error() + { + return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); + } +} diff --git a/samples/OpenidFederation/src/RpApi/Models/ErrorViewModel.cs b/samples/OpenidFederation/src/RpApi/Models/ErrorViewModel.cs new file mode 100644 index 000000000..9fcdf78ab --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Models/ErrorViewModel.cs @@ -0,0 +1,8 @@ +namespace RpApi.Models; + +public class ErrorViewModel +{ + public string? RequestId { get; set; } + + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); +} diff --git a/samples/OpenidFederation/src/RpApi/Program.cs b/samples/OpenidFederation/src/RpApi/Program.cs new file mode 100644 index 000000000..d648872a3 --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Program.cs @@ -0,0 +1,102 @@ +using Microsoft.IdentityModel.Tokens; +using SimpleIdServer.IdServer.Domains; +using SimpleIdServer.OpenidFederation.Domains; +using SimpleIdServer.OpenidFederation.Store.EF; +using System.Security.Cryptography; + +var builder = WebApplication.CreateBuilder(args); +var signatureCredentials = new SigningCredentials(new RsaSecurityKey(RSA.Create()) { KeyId = "raId" }, SecurityAlgorithms.RsaSha256); + +var jsonWebKey = signatureCredentials.SerializePublicJWK(); +jsonWebKey.Alg = SecurityAlgorithms.RsaSha256; +jsonWebKey.Use = "sig"; + +builder.Services.AddDistributedMemoryCache(); +builder.Services.AddRpFederation(r => +{ + r.Client = new SimpleIdServer.IdServer.Domains.Client + { + ClientId = "http://localhost:7001", + RedirectionUrls = new List + { + "http://localhost:7001/signin-oidc" + }, + ClientRegistrationTypesSupported = new List + { + "automatic" + }, + RequestObjectSigningAlg = SecurityAlgorithms.RsaSha256, + Scopes = new List + { + new Scope + { + Name = "openid" + }, + new Scope + { + Name = "profile" + } + }, + ResponseTypes = new List + { + "code" + }, + GrantTypes = new List + { + "authorization_code" + }, + TokenEndPointAuthMethod = "private_key_jwt" + }; + r.Client.Add(jsonWebKey.Kid, jsonWebKey, "sig", SecurityKeyTypes.RSA); + r.SigningCredentials = signatureCredentials; +}); +builder.Services.AddOpenidFederationStore(); +builder.Services.AddControllersWithViews(); +builder.Services.AddAuthentication(options => +{ + options.DefaultScheme = "Cookies"; + options.DefaultChallengeScheme = "sid"; +}) + .AddCookie("Cookies") + .AddCustomOpenIdConnect("sid", options => + { + + options.SignInScheme = "Cookies"; + options.ResponseType = "code"; + options.Authority = "https://localhost:5001/master"; + options.RequireHttpsMetadata = false; + options.ClientId = "http://localhost:7001"; + options.GetClaimsFromUserInfoEndpoint = true; + options.SaveTokens = true; + options.UseFederationAutomaticRegistration(signatureCredentials); + }); + +var app = builder.Build(); +AddTrustedEntities(app.Services); +app.UseHttpsRedirection(); +app.UseStaticFiles(); +app.UseRouting(); +app.UseAuthorization(); +app.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + +app.Run(); +static void AddTrustedEntities(IServiceProvider services) +{ + using (var scope = services.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.FederationEntities.AddRange(new List + { + new FederationEntity + { + Id = Guid.NewGuid().ToString(), + Sub = "http://localhost:7000", + Realm = string.Empty, + IsSubordinate = false + } + }); + dbContext.SaveChanges(); + } +} \ No newline at end of file diff --git a/samples/OpenidFederation/src/RpApi/Properties/launchSettings.json b/samples/OpenidFederation/src/RpApi/Properties/launchSettings.json new file mode 100644 index 000000000..433d90d9d --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Properties/launchSettings.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:65068", + "sslPort": 44355 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:5272", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7200;http://localhost:5272", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/samples/OpenidFederation/src/RpApi/RpApi.csproj b/samples/OpenidFederation/src/RpApi/RpApi.csproj new file mode 100644 index 000000000..2dba4eeb3 --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/RpApi.csproj @@ -0,0 +1,15 @@ + + + + net8.0 + enable + enable + + + + + + + + + diff --git a/samples/OpenidFederation/src/RpApi/ViewModels/ClaimsViewModel.cs b/samples/OpenidFederation/src/RpApi/ViewModels/ClaimsViewModel.cs new file mode 100644 index 000000000..9d784888d --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/ViewModels/ClaimsViewModel.cs @@ -0,0 +1,7 @@ +namespace RpApi.ViewModels +{ + public class ClaimsViewModel + { + public string AccessToken { get; set; } + } +} diff --git a/samples/OpenidFederation/src/RpApi/Views/Claims/Index.cshtml b/samples/OpenidFederation/src/RpApi/Views/Claims/Index.cshtml new file mode 100644 index 000000000..2310ca501 --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Views/Claims/Index.cshtml @@ -0,0 +1,13 @@ +@model RpApi.ViewModels.ClaimsViewModel + +
    + @foreach (var claim in User.Claims) + { +
  • @claim.Type : @claim.Value
  • + } +
+ +
+

Access token

+

@Model.AccessToken

+
\ No newline at end of file diff --git a/samples/OpenidFederation/src/RpApi/Views/Home/Index.cshtml b/samples/OpenidFederation/src/RpApi/Views/Home/Index.cshtml new file mode 100644 index 000000000..bcfd79a52 --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Views/Home/Index.cshtml @@ -0,0 +1,8 @@ +@{ + ViewData["Title"] = "Home Page"; +} + +
+

Welcome

+

Learn about building Web apps with ASP.NET Core.

+
diff --git a/samples/OpenidFederation/src/RpApi/Views/Home/Privacy.cshtml b/samples/OpenidFederation/src/RpApi/Views/Home/Privacy.cshtml new file mode 100644 index 000000000..af4fb195a --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Views/Home/Privacy.cshtml @@ -0,0 +1,6 @@ +@{ + ViewData["Title"] = "Privacy Policy"; +} +

@ViewData["Title"]

+ +

Use this page to detail your site's privacy policy.

diff --git a/samples/OpenidFederation/src/RpApi/Views/Shared/Error.cshtml b/samples/OpenidFederation/src/RpApi/Views/Shared/Error.cshtml new file mode 100644 index 000000000..a1e04783c --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Views/Shared/Error.cshtml @@ -0,0 +1,25 @@ +@model ErrorViewModel +@{ + ViewData["Title"] = "Error"; +} + +

Error.

+

An error occurred while processing your request.

+ +@if (Model.ShowRequestId) +{ +

+ Request ID: @Model.RequestId +

+} + +

Development Mode

+

+ Swapping to Development environment will display more detailed information about the error that occurred. +

+

+ The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app. +

diff --git a/samples/OpenidFederation/src/RpApi/Views/Shared/_Layout.cshtml b/samples/OpenidFederation/src/RpApi/Views/Shared/_Layout.cshtml new file mode 100644 index 000000000..eff13f01b --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Views/Shared/_Layout.cshtml @@ -0,0 +1,49 @@ + + + + + + @ViewData["Title"] - RpApi + + + + + +
+ +
+
+
+ @RenderBody() +
+
+ +
+
+ © 2024 - RpApi - Privacy +
+
+ + + + @await RenderSectionAsync("Scripts", required: false) + + diff --git a/samples/OpenidFederation/src/RpApi/Views/Shared/_Layout.cshtml.css b/samples/OpenidFederation/src/RpApi/Views/Shared/_Layout.cshtml.css new file mode 100644 index 000000000..c187c02e0 --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Views/Shared/_Layout.cshtml.css @@ -0,0 +1,48 @@ +/* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification +for details on configuring this project to bundle and minify static web assets. */ + +a.navbar-brand { + white-space: normal; + text-align: center; + word-break: break-all; +} + +a { + color: #0077cc; +} + +.btn-primary { + color: #fff; + background-color: #1b6ec2; + border-color: #1861ac; +} + +.nav-pills .nav-link.active, .nav-pills .show > .nav-link { + color: #fff; + background-color: #1b6ec2; + border-color: #1861ac; +} + +.border-top { + border-top: 1px solid #e5e5e5; +} +.border-bottom { + border-bottom: 1px solid #e5e5e5; +} + +.box-shadow { + box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); +} + +button.accept-policy { + font-size: 1rem; + line-height: inherit; +} + +.footer { + position: absolute; + bottom: 0; + width: 100%; + white-space: nowrap; + line-height: 60px; +} diff --git a/samples/OpenidFederation/src/RpApi/Views/Shared/_ValidationScriptsPartial.cshtml b/samples/OpenidFederation/src/RpApi/Views/Shared/_ValidationScriptsPartial.cshtml new file mode 100644 index 000000000..5a16d80a9 --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Views/Shared/_ValidationScriptsPartial.cshtml @@ -0,0 +1,2 @@ + + diff --git a/samples/OpenidFederation/src/RpApi/Views/_ViewImports.cshtml b/samples/OpenidFederation/src/RpApi/Views/_ViewImports.cshtml new file mode 100644 index 000000000..7bc1cc130 --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Views/_ViewImports.cshtml @@ -0,0 +1,3 @@ +@using RpApi +@using RpApi.Models +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/samples/OpenidFederation/src/RpApi/Views/_ViewStart.cshtml b/samples/OpenidFederation/src/RpApi/Views/_ViewStart.cshtml new file mode 100644 index 000000000..a5f10045d --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/Views/_ViewStart.cshtml @@ -0,0 +1,3 @@ +@{ + Layout = "_Layout"; +} diff --git a/samples/OpenidFederation/src/RpApi/appsettings.Development.json b/samples/OpenidFederation/src/RpApi/appsettings.Development.json new file mode 100644 index 000000000..0c208ae91 --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/samples/OpenidFederation/src/RpApi/appsettings.json b/samples/OpenidFederation/src/RpApi/appsettings.json new file mode 100644 index 000000000..10f68b8c8 --- /dev/null +++ b/samples/OpenidFederation/src/RpApi/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/samples/OpenidFederation/src/TaApi/Program.cs b/samples/OpenidFederation/src/TaApi/Program.cs new file mode 100644 index 000000000..e16a822e1 --- /dev/null +++ b/samples/OpenidFederation/src/TaApi/Program.cs @@ -0,0 +1,38 @@ +using Microsoft.IdentityModel.Tokens; +using SimpleIdServer.OpenidFederation.Domains; +using SimpleIdServer.OpenidFederation.Store.EF; +using System.Security.Cryptography; + +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddControllers(); +builder.Services.AddDistributedMemoryCache(); +builder.Services.AddAuthorityFederation(o => +{ + o.OrganizationName = "Trust anchor"; + o.SigningCredentials = new SigningCredentials(new RsaSecurityKey(RSA.Create()) { KeyId = "taId" }, SecurityAlgorithms.RsaSha256); +}); +builder.Services.AddOpenidFederationStore(); + +var app = builder.Build(); +AddTrustedEntities(app.Services); +app.MapControllers(); +app.Run(); + +static void AddTrustedEntities(IServiceProvider services) +{ + using (var scope = services.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.FederationEntities.AddRange(new List + { + new FederationEntity + { + Id = Guid.NewGuid().ToString(), + Sub = "http://localhost:7001", + Realm = string.Empty, + IsSubordinate = true + } + }); + dbContext.SaveChanges(); + } +} \ No newline at end of file diff --git a/samples/OpenidFederation/src/TaApi/Properties/launchSettings.json b/samples/OpenidFederation/src/TaApi/Properties/launchSettings.json new file mode 100644 index 000000000..b2c2764d3 --- /dev/null +++ b/samples/OpenidFederation/src/TaApi/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:63942", + "sslPort": 44397 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5189", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7136;http://localhost:5189", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/samples/OpenidFederation/src/TaApi/TaApi.csproj b/samples/OpenidFederation/src/TaApi/TaApi.csproj new file mode 100644 index 000000000..64ecfae8d --- /dev/null +++ b/samples/OpenidFederation/src/TaApi/TaApi.csproj @@ -0,0 +1,16 @@ + + + + net8.0 + enable + enable + + + + + + + + + + diff --git a/samples/OpenidFederation/src/TaApi/TaApi.http b/samples/OpenidFederation/src/TaApi/TaApi.http new file mode 100644 index 000000000..9804b72e5 --- /dev/null +++ b/samples/OpenidFederation/src/TaApi/TaApi.http @@ -0,0 +1,6 @@ +@TaApi_HostAddress = http://localhost:5189 + +GET {{TaApi_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/samples/OpenidFederation/src/TaApi/appsettings.Development.json b/samples/OpenidFederation/src/TaApi/appsettings.Development.json new file mode 100644 index 000000000..0c208ae91 --- /dev/null +++ b/samples/OpenidFederation/src/TaApi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/samples/OpenidFederation/src/TaApi/appsettings.json b/samples/OpenidFederation/src/TaApi/appsettings.json new file mode 100644 index 000000000..10f68b8c8 --- /dev/null +++ b/samples/OpenidFederation/src/TaApi/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/samples/ProtectWebsiteServersideACR/src/Website/Program.cs b/samples/ProtectWebsiteServersideACR/src/Website/Program.cs index f1938e475..8c951d0ab 100644 --- a/samples/ProtectWebsiteServersideACR/src/Website/Program.cs +++ b/samples/ProtectWebsiteServersideACR/src/Website/Program.cs @@ -16,7 +16,7 @@ if(context.Properties.Items.ContainsKey("acr")) { context.ProtocolMessage.AcrValues = context.Properties.Items["acr"]; - context.ProtocolMessage.Prompt = "login"; + // context.ProtocolMessage.Prompt = "login"; } return Task.CompletedTask; diff --git a/sid-kubernetes.yaml b/sid-kubernetes.yaml index 3a4c90abc..90237d279 100644 --- a/sid-kubernetes.yaml +++ b/sid-kubernetes.yaml @@ -229,7 +229,7 @@ spec: subdomain: localhost containers: - name: scim-deploy - image: simpleidserver/scim:4.0.8 + image: simpleidserver/scim:5.0.1 ports: - containerPort: 80 env: @@ -266,7 +266,7 @@ spec: subdomain: localhost containers: - name: idserver-deploy - image: simpleidserver/idserver:4.0.8 + image: simpleidserver/idserver:5.0.1 ports: - containerPort: 80 env: @@ -309,7 +309,7 @@ spec: subdomain: localhost containers: - name: website-deploy - image: simpleidserver/website:4.0.8 + image: simpleidserver/website:5.0.1 ports: - containerPort: 80 env: @@ -350,7 +350,7 @@ spec: subdomain: localhost containers: - name: credentialissuer-deploy - image: simpleidserver/credentialissuer:4.0.8 + image: simpleidserver/credentialissuer:5.0.1 ports: - containerPort: 80 env: @@ -385,7 +385,7 @@ spec: subdomain: localhost containers: - name: credentialissuerwebsite-deploy - image: simpleidserver/credentialissuerwebsite:4.0.8 + image: simpleidserver/credentialissuerwebsite:5.0.1 ports: - containerPort: 80 env: diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Console/EsbiWallet.cs b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Console/EsbiWallet.cs new file mode 100644 index 000000000..c1719cc62 --- /dev/null +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Console/EsbiWallet.cs @@ -0,0 +1,234 @@ +// Copyright (c) SimpleIdServer. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.Tokens; +using SimpleIdServer.CredentialIssuer.Api.CredentialIssuer; +using SimpleIdServer.Did.Crypto; +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Web; + +namespace SimpleIdServer.CredentialIssuer.Console; + +public class EsbiWallet +{ + private const string url = "https://api-conformance.ebsi.eu/conformance/v3/issuer-mock/.well-known/openid-credential-issuer"; + private const string publicKey = "z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbpMAoXtZtunruYnM4gCV65AKAUX2AwEReRhEaf3BRQNJArZPwQdmf9ENZcF8VT13a58WsHeVjJtvAKKPYEibaEfdUxvU7sgxEUTJpjEkq6BJKrRV1JQ1CqhYvGbmJ1WyoUQ"; + private const string did = $"did:key:{publicKey}"; + private const string refDid = $"{did}#{publicKey}"; + + public static async Task RegisterEsbiWalletForConformance() + { + using (var httpClient = new HttpClient()) + { + var (challenge, verifier) = PkceGenerate(); + var openidCredentialIssuer = GetOpenidCredentialIssuer(httpClient).Result; + var configuration = GetAuthorizationEndpoint(httpClient, openidCredentialIssuer.AuthorizationServer).Result; + var parameters = ExecuteAuthorizationRequest(httpClient, configuration.authorizationEndpoint, challenge, openidCredentialIssuer.CredentialIssuer).Result; + var redirectUri = parameters["redirect_uri"]; + var nonce = parameters["nonce"]; + var state = parameters["state"]; + var postAuthResult = ExecutePostAuthorizationRequest(httpClient, redirectUri, openidCredentialIssuer.CredentialIssuer, nonce, state).Result; + var tokenResult = GetToken(httpClient, configuration.tokenEndpoint, postAuthResult["code"], verifier).Result; + GetCredential(httpClient, openidCredentialIssuer.CredentialEndpoint, openidCredentialIssuer.CredentialIssuer, tokenResult.cNonce, tokenResult.accessToken).Wait(); + } + } + + private static async Task GetOpenidCredentialIssuer(HttpClient httpClient) + { + var url = "https://api-conformance.ebsi.eu/conformance/v3/issuer-mock/.well-known/openid-credential-issuer"; + var requestMessage = new HttpRequestMessage(HttpMethod.Get, url); + var httpResult = await httpClient.SendAsync(requestMessage); + var json = await httpResult.Content.ReadAsStringAsync(); + var openidCredentialIssuer = JsonSerializer.Deserialize(json); + return openidCredentialIssuer; + } + + private static async Task<(string authorizationEndpoint, string issuer, string tokenEndpoint)> GetAuthorizationEndpoint(HttpClient httpClient, string authUrl) + { + var requestMessage = new HttpRequestMessage(HttpMethod.Get, $"{authUrl}/.well-known/openid-configuration"); + var httpResult = await httpClient.SendAsync(requestMessage); + var json = await httpResult.Content.ReadAsStringAsync(); + var jsonObj = JsonObject.Parse(json); + return (jsonObj["authorization_endpoint"].ToString(), jsonObj["issuer"].ToString(), jsonObj["token_endpoint"].ToString()); + } + + private static async Task> ExecuteAuthorizationRequest(HttpClient httpClient, string url, string challenge, string aud) + { + var uriBuilder = new UriBuilder(url); + var authorizationDetails = new JsonArray +{ + new JsonObject + { + { "type", "openid_credential" }, + { "format", "jwt_vc" }, + { "types", new JsonArray + { + "VerifiableCredential", + "VerifiableAttestation", + "CTIssueQualificationCredential" + } }, + { "locations", new JsonArray + { + aud + } } + } +}; + var clientMetadata = new JsonObject +{ + { "response_types_supported", + new JsonArray + { + "vp_token", "id_token" + } + }, + { "authorization_endpoint", "openid://"} +}; + var dic = new Dictionary +{ + { "response_type", "code" }, + { "scope", "openid" }, + // { "issuer_state", "issuer-state" }, + { "state", "client-state" }, + { "client_id", did }, + { "authorization_details", HttpUtility.UrlEncode(authorizationDetails.ToJsonString()) }, + { "redirect_uri", "openid://" }, + { "nonce", "nonce" }, + { "code_challenge", challenge }, + { "code_challenge_method", "S256" }, + { "client_metadata", HttpUtility.UrlEncode(clientMetadata.ToJsonString()) } +}; + uriBuilder.Query = string.Join("&", dic.Select(kvp => $"{kvp.Key}={kvp.Value}")); + var requestMessage = new HttpRequestMessage + { + RequestUri = uriBuilder.Uri + }; + var httpResult = await httpClient.SendAsync(requestMessage); + var result = httpResult.Headers.Location.AbsoluteUri; + uriBuilder = new UriBuilder(result); + var queryParameters = uriBuilder.Query.Trim('?').Split('&').Select(s => s.Split('=')).ToDictionary(arr => arr[0], arr => arr[1]); + return queryParameters; + } + + private static async Task> ExecutePostAuthorizationRequest(HttpClient httpClient, string url, string aud, string nonce, string state) + { + var serializedPrivateKey = System.IO.File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "privatekey.json")); + var signatureKey = SignatureKeySerializer.Deserialize(serializedPrivateKey); + var signingCredentials = signatureKey.BuildSigningCredentials(refDid); + var handler = new JsonWebTokenHandler(); + var securityTokenDescriptor = new SecurityTokenDescriptor + { + IssuedAt = DateTime.UtcNow, + SigningCredentials = signingCredentials, + Audience = aud + }; + var claims = new Dictionary +{ + { "nonce", nonce }, + { "iss", did }, + { "sub", did } +}; + securityTokenDescriptor.Claims = claims; + var token = handler.CreateToken(securityTokenDescriptor); + var requestMessage = new HttpRequestMessage + { + RequestUri = new Uri(HttpUtility.UrlDecode(url)), + Content = new FormUrlEncodedContent(new List> + { + new KeyValuePair("id_token", token), + new KeyValuePair("state", state) + }), + Method = HttpMethod.Post + }; + var httpResult = await httpClient.SendAsync(requestMessage); + var result = httpResult.Headers.Location.AbsoluteUri; + var uriBuilder = new UriBuilder(result); + var queryParameters = uriBuilder.Query.Trim('?').Split('&').Select(s => s.Split('=')).ToDictionary(arr => arr[0], arr => arr[1]); + return queryParameters; + } + + private static async Task GetCredential(HttpClient httpClient, string credentialEndpoint, string aud, string nonce, string accessToken) + { + var serializedPrivateKey = System.IO.File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "privatekey.json")); + var signatureKey = SignatureKeySerializer.Deserialize(serializedPrivateKey); + var signingCredentials = signatureKey.BuildSigningCredentials(refDid); + var handler = new JsonWebTokenHandler(); + var securityTokenDescriptor = new SecurityTokenDescriptor + { + IssuedAt = DateTime.UtcNow, + SigningCredentials = signingCredentials, + Audience = aud, + TokenType = "openid4vci-proof+jwt" + }; + var claims = new Dictionary +{ + { "iss", did }, + { "nonce", nonce } +}; + securityTokenDescriptor.Claims = claims; + var proofJwt = handler.CreateToken(securityTokenDescriptor); + var proofRequest = new JsonObject(); + proofRequest.Add("proof_type", "jwt"); + proofRequest.Add("jwt", proofJwt); + var request = new JsonObject +{ + { "types", new JsonArray + { + "VerifiableCredential", + "VerifiableAttestation", + "CTIssueQualificationCredential" + } }, + { "format", "jwt_vc" } +}; + request.Add("proof", proofRequest); + var requestMessage = new HttpRequestMessage + { + RequestUri = new Uri(HttpUtility.UrlDecode(credentialEndpoint)), + Content = new StringContent(request.ToJsonString(), Encoding.UTF8, "application/json"), + Method = HttpMethod.Post + }; + requestMessage.Headers.Add("Authorization", $"Bearer {accessToken}"); + await httpClient.SendAsync(requestMessage); + } + + private static async Task<(string accessToken, string idToken, string cNonce)> GetToken(HttpClient httpClient, string url, string authorizationCode, string codeVerifier) + { + var requestMessage = new HttpRequestMessage + { + RequestUri = new Uri(url), + Content = new FormUrlEncodedContent(new List> + { + new KeyValuePair("grant_type", "authorization_code"), + new KeyValuePair("client_id", did), + new KeyValuePair("code", authorizationCode), + new KeyValuePair("code_verifier", codeVerifier) + }), + Method = HttpMethod.Post + }; + var httpResult = await httpClient.SendAsync(requestMessage); + var content = await httpResult.Content.ReadAsStringAsync(); + var jObj = JsonObject.Parse(content); + return (jObj["access_token"].ToString(), jObj["id_token"].ToString(), jObj["c_nonce"].ToString()); + } + + private static (string codeChallenge, string verifier) PkceGenerate(int size = 32) + { + using var rng = RandomNumberGenerator.Create(); + var randomBytes = new byte[size]; + rng.GetBytes(randomBytes); + var verifier = Base64UrlEncode(randomBytes); + + var buffer = Encoding.UTF8.GetBytes(verifier); + var hash = SHA256.Create().ComputeHash(buffer); + var challenge = Base64UrlEncode(hash); + + return (challenge, verifier); + } + private static string Base64UrlEncode(byte[] data) => + Convert.ToBase64String(data) + .Replace("+", "-") + .Replace("/", "_") + .TrimEnd('='); +} diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Console/Program.cs b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Console/Program.cs new file mode 100644 index 000000000..097fe4917 --- /dev/null +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Console/Program.cs @@ -0,0 +1,5 @@ +// Copyright (c) SimpleIdServer. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. +using SimpleIdServer.CredentialIssuer.Console; + +EsbiWallet.RegisterEsbiWalletForConformance().Wait(); \ No newline at end of file diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Console/SimpleIdServer.CredentialIssuer.Console.csproj b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Console/SimpleIdServer.CredentialIssuer.Console.csproj new file mode 100644 index 000000000..d591bac62 --- /dev/null +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Console/SimpleIdServer.CredentialIssuer.Console.csproj @@ -0,0 +1,20 @@ + + + + Exe + net8.0 + enable + enable + + + + + PreserveNewest + + + + + + + + diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/Credential.cs b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/Credential.cs index db6b10f8d..2e6b9c45a 100644 --- a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/Credential.cs +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/Credential.cs @@ -25,4 +25,5 @@ public class Credential public virtual CredentialConfiguration Configuration { get; set; } [JsonPropertyName("claims")] public virtual List Claims { get; set; } + public bool IsDeferred { get; set; } = false; } diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/CredentialConfiguration.cs b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/CredentialConfiguration.cs index eba74d7c8..1a62eae4a 100644 --- a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/CredentialConfiguration.cs +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/CredentialConfiguration.cs @@ -26,10 +26,20 @@ public class CredentialConfiguration public DateTime CreateDateTime { get; set; } [JsonPropertyName("update_datetime")] public DateTime UpdateDateTime { get; set; } + [JsonIgnore] + public string? CredentialSchemaId { get; set; } = null; + [JsonIgnore] + public string? CredentialSchemaType { get; set; } = null; + [JsonIgnore] + public bool IsDeferred { get; set; } = false; [JsonPropertyName("claims")] public virtual List Claims { get; set; } = new List(); [JsonPropertyName("displays")] public virtual List Displays { get; set; } = new List(); [JsonIgnore] + public virtual List DeferredCredentials { get; set; } + [JsonIgnore] + public List AdditionalTypes { get; set; } = new List(); + [JsonIgnore] public virtual List Credentials { get; set; } } \ No newline at end of file diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/CredentialOfferRecord.cs b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/CredentialOfferRecord.cs index 91804f4f3..c52fcaccc 100644 --- a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/CredentialOfferRecord.cs +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/CredentialOfferRecord.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Text.Json.Serialization; namespace SimpleIdServer.CredentialIssuer.Domains; @@ -11,11 +10,9 @@ public class CredentialOfferRecord { public string Id { get; set; } = null!; public string Subject { get; set; } = null!; - public List GrantTypes { get; set; } = new List(); - public List CredentialConfigurationIds { get; set; } = new List(); - [JsonIgnore] public string? PreAuthorizedCode { get; set; } = null; - [JsonIgnore] public string? IssuerState { get; set; } = null; public DateTime CreateDateTime { get; set; } + public List GrantTypes { get; set; } = new List(); + public List CredentialConfigurationIds { get; set; } } \ No newline at end of file diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/DeferredCredential.cs b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/DeferredCredential.cs new file mode 100644 index 000000000..0b8b962c8 --- /dev/null +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/DeferredCredential.cs @@ -0,0 +1,49 @@ +// Copyright (c) SimpleIdServer. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace SimpleIdServer.CredentialIssuer.Domains; + +public class DeferredCredential +{ + [JsonPropertyName("transaction_id")] + public string TransactionId { get; set; } = null!; + [JsonPropertyName("credential_id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? CredentialId { get; set; } = null; + [JsonPropertyName("credential_configuration_id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? CredentialConfigurationId { get; set; } = null; + [JsonPropertyName("status")] + public DeferredCredentialStatus Status { get; set; } + [JsonPropertyName("formatter_name")] + public string FormatterName { get; set; } + [JsonPropertyName("nonce")] + public string Nonce { get; set; } + [JsonPropertyName("encryption_alg")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? EncryptionAlg { get; set; } = null; + [JsonPropertyName("encryption_enc")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? EncryptionEnc { get; set; } = null; + [JsonPropertyName("encryption_jwk")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? EncryptionJwk { get; set; } = null; + [JsonPropertyName("create_datetime")] + public DateTime CreateDateTime { get; set; } + [JsonPropertyName("configuration")] + public CredentialConfiguration Configuration { get; set; } + [JsonPropertyName("claims")] + public List Claims { get; set; } + [JsonIgnore] + public string UserDid { get; set; } +} + +public enum DeferredCredentialStatus +{ + PENDING = 0, + ISSUED = 1 +} \ No newline at end of file diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/DeferredCredentialClaim.cs b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/DeferredCredentialClaim.cs new file mode 100644 index 000000000..b1c8827c0 --- /dev/null +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Domains/DeferredCredentialClaim.cs @@ -0,0 +1,18 @@ +// Copyright (c) SimpleIdServer. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +using System.Text.Json.Serialization; + +namespace SimpleIdServer.CredentialIssuer.Domains; + +public class DeferredCredentialClaim +{ + [JsonPropertyName("id")] + public string Id { get; set; } + [JsonPropertyName("name")] + public string Name { get; set; } + [JsonPropertyName("value")] + public string Value { get; set; } + [JsonIgnore] + public string DeferredCredentialId { get; set; } +} diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/CredentialIssuerConfiguration.cs b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/CredentialIssuerConfiguration.cs index 533521fa3..5eebfc418 100644 --- a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/CredentialIssuerConfiguration.cs +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/CredentialIssuerConfiguration.cs @@ -1,10 +1,11 @@ // Copyright (c) SimpleIdServer. All rights reserved. // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. -using Org.BouncyCastle.Crypto.Agreement; using SimpleIdServer.CredentialIssuer.Builders; using SimpleIdServer.CredentialIssuer.CredentialFormats; using SimpleIdServer.CredentialIssuer.Domains; +using System; using System.Collections.Generic; +using System.Linq; namespace SimpleIdServer.CredentialIssuer.Startup; @@ -13,7 +14,7 @@ public class CredentialIssuerConfiguration public static List CredentialConfigurations => new List { CredentialConfigurationBuilder - .New(LdpVcFormatter.FORMAT, "UniversityDegree", "https://www.w3.org/2018/credentials/examples/v1", "https://www.w3.org/2018/credentials", scope: "university_degree") + .New(JwtVcJsonFormatter.FORMAT, "UniversityDegree", "https://www.w3.org/2018/credentials/examples/v1", "https://www.w3.org/2018/credentials", scope: "university_degree") .AddClaim("given_name", "GivenName", (cb) => { cb.AddTranslation("Given Name", "en-US"); @@ -31,6 +32,34 @@ public class CredentialIssuerConfiguration cb.AddTranslation("Name of degree", "en-US"); }) .AddDisplay("University Credential", "en-US", "https://img.freepik.com/premium-vector/logo-university-name-logo-company-called-university_516670-732.jpg", "A square logo of a university", null,"#12107c", "#acd2b1") + .Build(), + CredentialConfigurationBuilder + .New(JwtVcJsonFormatter.FORMAT, "CTWalletSameAuthorisedInTime", "https://www.w3.org/2018/credentials/examples/v1", "https://www.w3.org/2018/credentials", additionalTypes: new List { "VerifiableAttestation" }, isDeferred: false, scope: "ct_wallet") + .SetSchema("https://api-pilot.ebsi.eu/trusted-schemas-registry/v2/schemas/z3MgUFUkb722uq4x3dv5yAJmnNmzDFeK5UC8x83QoeLJM", "FullJsonSchemaValidator2021") + .Build(), + CredentialConfigurationBuilder + .New(JwtVcJsonFormatter.FORMAT, "CTWalletSameAuthorisedDeferred", "https://www.w3.org/2018/credentials/examples/v1", "https://www.w3.org/2018/credentials", additionalTypes: new List { "VerifiableAttestation" }, isDeferred: true, id: "6fea9437-9379-4a22-b396-461c9c510011", scope: "ct_wallet") + .SetSchema("https://api-pilot.ebsi.eu/trusted-schemas-registry/v2/schemas/z3MgUFUkb722uq4x3dv5yAJmnNmzDFeK5UC8x83QoeLJM", "FullJsonSchemaValidator2021") + .AddClaim("given_name", "GivenName", (cb) => + { + cb.AddTranslation("Given Name", "en-US"); + }) + .Build(), + CredentialConfigurationBuilder + .New(JwtVcJsonFormatter.FORMAT, "CTWalletSamePreAuthorisedInTime", "https://www.w3.org/2018/credentials/examples/v1", "https://www.w3.org/2018/credentials", additionalTypes: new List { "VerifiableAttestation" }, scope: "ct_wallet") + .SetSchema("https://api-pilot.ebsi.eu/trusted-schemas-registry/v2/schemas/z3MgUFUkb722uq4x3dv5yAJmnNmzDFeK5UC8x83QoeLJM", "FullJsonSchemaValidator2021") + .AddClaim("given_name", "GivenName", (cb) => + { + cb.AddTranslation("Given Name", "en-US"); + }) + .Build(), + CredentialConfigurationBuilder + .New(JwtVcJsonFormatter.FORMAT, "CTWalletSamePreAuthorisedDeferred", "https://www.w3.org/2018/credentials/examples/v1", "https://www.w3.org/2018/credentials", additionalTypes: new List { "VerifiableAttestation" }, isDeferred: true, scope: "ct_wallet") + .SetSchema("https://api-pilot.ebsi.eu/trusted-schemas-registry/v2/schemas/z3MgUFUkb722uq4x3dv5yAJmnNmzDFeK5UC8x83QoeLJM", "FullJsonSchemaValidator2021") + .AddClaim("given_name", "GivenName", (cb) => + { + cb.AddTranslation("Given Name", "en-US"); + }) .Build() }; @@ -39,4 +68,9 @@ public class CredentialIssuerConfiguration UserCredentialClaimBuilder.Build("administrator", "DegreeName", "Master degree"), UserCredentialClaimBuilder.Build("administrator", "GivenName", "SimpleIdServer") }; + + public static List DeferredCredentials = new List + { + new DeferredCredential { CreateDateTime = DateTime.UtcNow, CredentialConfigurationId = "6fea9437-9379-4a22-b396-461c9c510011", Status = DeferredCredentialStatus.PENDING, TransactionId = Guid.NewGuid().ToString(), FormatterName = JwtVcJsonFormatter.FORMAT } + }; } diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Program.cs b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Program.cs index 6bd434c2e..5880948a2 100644 --- a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Program.cs +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Program.cs @@ -1,15 +1,23 @@ // Copyright (c) SimpleIdServer. All rights reserved. // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using SimpleIdServer.CredentialIssuer.Startup; +using SimpleIdServer.Did.Crypto; +using SimpleIdServer.Did.Key; +using System.IO; using System.Net.Http; +using System.Threading; var builder = WebApplication.CreateBuilder(args); +// GeneratePrivateKey(); + var ignoreCertificateError = bool.Parse(builder.Configuration["Authorization:IgnoreCertificateError"]); builder.Services.AddAuthentication(o => { @@ -61,28 +69,7 @@ }); builder.Services.AddAuthorization(b => { - b.AddPolicy("WebsiteAuthenticated", p => - { - p.RequireAuthenticatedUser(); - }); - b.AddPolicy("ApiAuthenticated", p => - { - p.AuthenticationSchemes.Clear(); - p.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme); - p.RequireAuthenticatedUser(); - }); - b.AddPolicy("credconfs", p => - { - p.AuthenticationSchemes.Clear(); - p.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme); - p.RequireClaim("scope", "credconfs"); - }); - b.AddPolicy("credinstances", p => - { - p.AuthenticationSchemes.Clear(); - p.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme); - p.RequireClaim("scope", "credinstances"); - }); + b.AddDefaultCredentialIssuerAuthorization(); }); builder.Services.AddLocalization(); builder.Services.AddEndpointsApiExplorer(); @@ -92,17 +79,33 @@ builder.Services.AddCredentialIssuer(o => { + var serializedPrivateKey = System.IO.File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "privatekey.json")); + var signatureKey = SignatureKeySerializer.Deserialize(serializedPrivateKey); + var publicDid = builder.Configuration["PublicDid"]; + o.Version = SimpleIdServer.IdServer.CredentialIssuer.CredentialIssuerVersion.ESBI; o.ClientId = builder.Configuration["Authorization:ClientId"]; o.ClientSecret = builder.Configuration["Authorization:ClientSecret"]; o.AuthorizationServer = builder.Configuration["Authorization:Issuer"]; + o.DidDocument = DidKeyResolver.New().Resolve(publicDid, CancellationToken.None).Result; + o.AsymmKey = signatureKey; o.IgnoreHttpsCertificateError = ignoreCertificateError; + o.IsDeveloperModeEnabled = true; }) .UseInMemoryStore(c => { c.AddCredentialConfigurations(CredentialIssuerConfiguration.CredentialConfigurations); c.AddUserCredentialClaims(CredentialIssuerConfiguration.CredentialClaims); + c.AddDeferredCredentials(CredentialIssuerConfiguration.DeferredCredentials); }); +builder.Services.AddDidKey(); + +static void GeneratePrivateKey() +{ + var did = DidKeyGenerator.New().GenerateRandomES256Key().Export(false, true); + var serialized = SignatureKeySerializer.SerializedToJson(did.Key); +} + var app = builder.Build(); app.UseStaticFiles(); app.UseRequestLocalization(e => diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Resources/Global.Designer.cs b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Resources/Global.Designer.cs index 3f6a217ce..0b517b626 100644 --- a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Resources/Global.Designer.cs +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Resources/Global.Designer.cs @@ -114,6 +114,33 @@ public static string Loading { } } + /// + /// Recherche une chaîne localisée semblable à Pre-authorized. + /// + public static string PreAuthorized { + get { + return ResourceManager.GetString("PreAuthorized", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à QR code. + /// + public static string QrCode { + get { + return ResourceManager.GetString("QrCode", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Requires user PIN. + /// + public static string RequiresUserPin { + get { + return ResourceManager.GetString("RequiresUserPin", resourceCulture); + } + } + /// /// Recherche une chaîne localisée semblable à Scan the QR code with your wallet application. /// diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Resources/Global.resx b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Resources/Global.resx index 92ba92a20..9217ebefa 100644 --- a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Resources/Global.resx +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Resources/Global.resx @@ -135,6 +135,15 @@ Loading + + Pre-authorized + + + QR code + + + Requires user PIN + Scan the QR code with your wallet application diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/SimpleIdServer.CredentialIssuer.Startup.csproj b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/SimpleIdServer.CredentialIssuer.Startup.csproj index 842870a4f..833f5fe45 100644 --- a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/SimpleIdServer.CredentialIssuer.Startup.csproj +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/SimpleIdServer.CredentialIssuer.Startup.csproj @@ -4,6 +4,7 @@ Exe + @@ -11,6 +12,7 @@ + diff --git a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Views/Credentials/Index.cshtml b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Views/Credentials/Index.cshtml index 0c97ebbce..6b4e01cc7 100644 --- a/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Views/Credentials/Index.cshtml +++ b/src/CredentialIssuer/SimpleIdServer.CredentialIssuer.Startup/Views/Credentials/Index.cshtml @@ -1,6 +1,8 @@ @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@using Microsoft.Extensions.Options @using SimpleIdServer.CredentialIssuer.Startup.Resources; @using System.Globalization; +@using SimpleIdServer.IdServer.CredentialIssuer @model SimpleIdServer.CredentialIssuer.UI.ViewModels.CredentialsViewModel @{ @@ -30,28 +32,34 @@ var title = display == null ? credentialConfiguration.ServerId : display.Name;
-
-
-
-
- +
+
+
+
+
+ +
+
+
@title
+ @if (display != null) + { +

@display.Description

+ } +
-
-
@title
- @if (display != null) - { -

@display.Description

- } +
+ +
-
- -
+
}
@@ -64,6 +72,14 @@