Add support for exposing identity as a service
This commit is contained in:
parent
ba64cd0fb0
commit
c7567f9f74
212
Identity.sln
212
Identity.sln
|
|
@ -1,6 +1,6 @@
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.26123.0
|
VisualStudioVersion = 15.0.26507.0
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0F647068-6602-4E24-B1DC-8ED91481A50A}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0F647068-6602-4E24-B1DC-8ED91481A50A}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -26,6 +26,34 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNet.Identity.A
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Specification.Tests", "src\Microsoft.AspNetCore.Identity.Specification.Tests\Microsoft.AspNetCore.Identity.Specification.Tests.csproj", "{5608E828-DD54-4E2A-B73C-FC22268BE797}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Specification.Tests", "src\Microsoft.AspNetCore.Identity.Specification.Tests\Microsoft.AspNetCore.Identity.Specification.Tests.csproj", "{5608E828-DD54-4E2A-B73C-FC22268BE797}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Diagnostics.Identity.Service", "src\Microsoft.AspNetCore.Diagnostics.Identity.Service\Microsoft.AspNetCore.Diagnostics.Identity.Service.csproj", "{CD787C9A-58B7-4CBC-B8E3-66698EE58C11}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service", "src\Microsoft.AspNetCore.Identity.Service\Microsoft.AspNetCore.Identity.Service.csproj", "{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service.Abstractions", "src\Microsoft.AspNetCore.Identity.Service.Abstractions\Microsoft.AspNetCore.Identity.Service.Abstractions.csproj", "{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service.Core", "src\Microsoft.AspNetCore.Identity.Service.Core\Microsoft.AspNetCore.Identity.Service.Core.csproj", "{590697C1-EA60-4412-8A21-4EF35142381F}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore", "src\Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore\Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore.csproj", "{CD360545-3395-4C44-AD27-C32EECDD9572}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service.IntegratedWebClient", "src\Microsoft.AspNetCore.Identity.Service.IntegratedWebClient\Microsoft.AspNetCore.Identity.Service.IntegratedWebClient.csproj", "{CA19785B-CE2F-480D-BB57-93A43A2DFDAB}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service.Mvc", "src\Microsoft.AspNetCore.Identity.Service.Mvc\Microsoft.AspNetCore.Identity.Service.Mvc.csproj", "{B3AE446B-859B-4C2C-98FD-A084C854941E}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service.Abstractions.Test", "test\Microsoft.AspNetCore.Identity.Service.Abstractions.Test\Microsoft.AspNetCore.Identity.Service.Abstractions.Test.csproj", "{27D28F0E-08F6-4EEA-8705-E0B559C87F3B}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service.Core.Test", "test\Microsoft.AspNetCore.Identity.Service.Core.Test\Microsoft.AspNetCore.Identity.Service.Core.Test.csproj", "{444F07E7-CF65-4717-BEF3-BA29F60DDE6E}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service.Test", "test\Microsoft.AspNetCore.Identity.Service.Test\Microsoft.AspNetCore.Identity.Service.Test.csproj", "{204163F9-E9BB-4940-9659-77F617C00D97}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service.Specification.Tests", "src\Microsoft.AspNetCore.Identity.Service.Specification.Tests\Microsoft.AspNetCore.Identity.Service.Specification.Tests.csproj", "{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore.InMemory.Test", "test\Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore.InMemory.Test\Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore.InMemory.Test.csproj", "{7423EB30-FFE9-4707-A44B-571E89A7CA15}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore.Test", "test\Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore.Test\Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore.Test.csproj", "{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service.InMemory.Test", "test\Microsoft.AspNetCore.Identity.Service.InMemory.Test\Microsoft.AspNetCore.Identity.Service.InMemory.Test.csproj", "{94EC586A-2AE6-4AF2-894A-B0973C65BD68}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -130,6 +158,174 @@ Global
|
||||||
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|x86.ActiveCfg = Release|Any CPU
|
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|x86.Build.0 = Release|Any CPU
|
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{CD787C9A-58B7-4CBC-B8E3-66698EE58C11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CD787C9A-58B7-4CBC-B8E3-66698EE58C11}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CD787C9A-58B7-4CBC-B8E3-66698EE58C11}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{CD787C9A-58B7-4CBC-B8E3-66698EE58C11}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{CD787C9A-58B7-4CBC-B8E3-66698EE58C11}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{CD787C9A-58B7-4CBC-B8E3-66698EE58C11}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{CD787C9A-58B7-4CBC-B8E3-66698EE58C11}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CD787C9A-58B7-4CBC-B8E3-66698EE58C11}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CD787C9A-58B7-4CBC-B8E3-66698EE58C11}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{CD787C9A-58B7-4CBC-B8E3-66698EE58C11}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{CD787C9A-58B7-4CBC-B8E3-66698EE58C11}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{CD787C9A-58B7-4CBC-B8E3-66698EE58C11}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{590697C1-EA60-4412-8A21-4EF35142381F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{590697C1-EA60-4412-8A21-4EF35142381F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{590697C1-EA60-4412-8A21-4EF35142381F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{590697C1-EA60-4412-8A21-4EF35142381F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{590697C1-EA60-4412-8A21-4EF35142381F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{590697C1-EA60-4412-8A21-4EF35142381F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{590697C1-EA60-4412-8A21-4EF35142381F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{590697C1-EA60-4412-8A21-4EF35142381F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{590697C1-EA60-4412-8A21-4EF35142381F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{590697C1-EA60-4412-8A21-4EF35142381F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{590697C1-EA60-4412-8A21-4EF35142381F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{590697C1-EA60-4412-8A21-4EF35142381F}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{CD360545-3395-4C44-AD27-C32EECDD9572}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CD360545-3395-4C44-AD27-C32EECDD9572}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CD360545-3395-4C44-AD27-C32EECDD9572}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{CD360545-3395-4C44-AD27-C32EECDD9572}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{CD360545-3395-4C44-AD27-C32EECDD9572}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{CD360545-3395-4C44-AD27-C32EECDD9572}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{CD360545-3395-4C44-AD27-C32EECDD9572}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CD360545-3395-4C44-AD27-C32EECDD9572}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CD360545-3395-4C44-AD27-C32EECDD9572}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{CD360545-3395-4C44-AD27-C32EECDD9572}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{CD360545-3395-4C44-AD27-C32EECDD9572}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{CD360545-3395-4C44-AD27-C32EECDD9572}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{CA19785B-CE2F-480D-BB57-93A43A2DFDAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CA19785B-CE2F-480D-BB57-93A43A2DFDAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CA19785B-CE2F-480D-BB57-93A43A2DFDAB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{CA19785B-CE2F-480D-BB57-93A43A2DFDAB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{CA19785B-CE2F-480D-BB57-93A43A2DFDAB}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{CA19785B-CE2F-480D-BB57-93A43A2DFDAB}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{CA19785B-CE2F-480D-BB57-93A43A2DFDAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CA19785B-CE2F-480D-BB57-93A43A2DFDAB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CA19785B-CE2F-480D-BB57-93A43A2DFDAB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{CA19785B-CE2F-480D-BB57-93A43A2DFDAB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{CA19785B-CE2F-480D-BB57-93A43A2DFDAB}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{CA19785B-CE2F-480D-BB57-93A43A2DFDAB}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{B3AE446B-859B-4C2C-98FD-A084C854941E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B3AE446B-859B-4C2C-98FD-A084C854941E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B3AE446B-859B-4C2C-98FD-A084C854941E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{B3AE446B-859B-4C2C-98FD-A084C854941E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{B3AE446B-859B-4C2C-98FD-A084C854941E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{B3AE446B-859B-4C2C-98FD-A084C854941E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{B3AE446B-859B-4C2C-98FD-A084C854941E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B3AE446B-859B-4C2C-98FD-A084C854941E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B3AE446B-859B-4C2C-98FD-A084C854941E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{B3AE446B-859B-4C2C-98FD-A084C854941E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{B3AE446B-859B-4C2C-98FD-A084C854941E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{B3AE446B-859B-4C2C-98FD-A084C854941E}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{27D28F0E-08F6-4EEA-8705-E0B559C87F3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{27D28F0E-08F6-4EEA-8705-E0B559C87F3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{27D28F0E-08F6-4EEA-8705-E0B559C87F3B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{27D28F0E-08F6-4EEA-8705-E0B559C87F3B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{27D28F0E-08F6-4EEA-8705-E0B559C87F3B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{27D28F0E-08F6-4EEA-8705-E0B559C87F3B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{27D28F0E-08F6-4EEA-8705-E0B559C87F3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{27D28F0E-08F6-4EEA-8705-E0B559C87F3B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{27D28F0E-08F6-4EEA-8705-E0B559C87F3B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{27D28F0E-08F6-4EEA-8705-E0B559C87F3B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{27D28F0E-08F6-4EEA-8705-E0B559C87F3B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{27D28F0E-08F6-4EEA-8705-E0B559C87F3B}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{444F07E7-CF65-4717-BEF3-BA29F60DDE6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{444F07E7-CF65-4717-BEF3-BA29F60DDE6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{444F07E7-CF65-4717-BEF3-BA29F60DDE6E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{444F07E7-CF65-4717-BEF3-BA29F60DDE6E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{444F07E7-CF65-4717-BEF3-BA29F60DDE6E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{444F07E7-CF65-4717-BEF3-BA29F60DDE6E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{444F07E7-CF65-4717-BEF3-BA29F60DDE6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{444F07E7-CF65-4717-BEF3-BA29F60DDE6E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{444F07E7-CF65-4717-BEF3-BA29F60DDE6E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{444F07E7-CF65-4717-BEF3-BA29F60DDE6E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{444F07E7-CF65-4717-BEF3-BA29F60DDE6E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{444F07E7-CF65-4717-BEF3-BA29F60DDE6E}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{204163F9-E9BB-4940-9659-77F617C00D97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{204163F9-E9BB-4940-9659-77F617C00D97}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{204163F9-E9BB-4940-9659-77F617C00D97}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{204163F9-E9BB-4940-9659-77F617C00D97}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{204163F9-E9BB-4940-9659-77F617C00D97}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{204163F9-E9BB-4940-9659-77F617C00D97}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{204163F9-E9BB-4940-9659-77F617C00D97}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{204163F9-E9BB-4940-9659-77F617C00D97}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{204163F9-E9BB-4940-9659-77F617C00D97}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{204163F9-E9BB-4940-9659-77F617C00D97}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{204163F9-E9BB-4940-9659-77F617C00D97}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{204163F9-E9BB-4940-9659-77F617C00D97}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{7423EB30-FFE9-4707-A44B-571E89A7CA15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7423EB30-FFE9-4707-A44B-571E89A7CA15}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7423EB30-FFE9-4707-A44B-571E89A7CA15}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{7423EB30-FFE9-4707-A44B-571E89A7CA15}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{7423EB30-FFE9-4707-A44B-571E89A7CA15}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{7423EB30-FFE9-4707-A44B-571E89A7CA15}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{7423EB30-FFE9-4707-A44B-571E89A7CA15}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7423EB30-FFE9-4707-A44B-571E89A7CA15}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7423EB30-FFE9-4707-A44B-571E89A7CA15}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{7423EB30-FFE9-4707-A44B-571E89A7CA15}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{7423EB30-FFE9-4707-A44B-571E89A7CA15}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{7423EB30-FFE9-4707-A44B-571E89A7CA15}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -144,5 +340,19 @@ Global
|
||||||
{4490894C-3572-4E63-86F1-EE5105CE8A06} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
{4490894C-3572-4E63-86F1-EE5105CE8A06} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
||||||
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
||||||
{5608E828-DD54-4E2A-B73C-FC22268BE797} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
{5608E828-DD54-4E2A-B73C-FC22268BE797} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
||||||
|
{CD787C9A-58B7-4CBC-B8E3-66698EE58C11} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
||||||
|
{B44C2A7F-EA9E-4A9F-9698-1C9F9BB40E0C} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
||||||
|
{F34C3ED8-D4A9-47CE-BE0F-1F234A33AC81} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
||||||
|
{590697C1-EA60-4412-8A21-4EF35142381F} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
||||||
|
{CD360545-3395-4C44-AD27-C32EECDD9572} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
||||||
|
{CA19785B-CE2F-480D-BB57-93A43A2DFDAB} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
||||||
|
{B3AE446B-859B-4C2C-98FD-A084C854941E} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
||||||
|
{27D28F0E-08F6-4EEA-8705-E0B559C87F3B} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
|
||||||
|
{444F07E7-CF65-4717-BEF3-BA29F60DDE6E} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
|
||||||
|
{204163F9-E9BB-4940-9659-77F617C00D97} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
|
||||||
|
{C05D641C-A3EE-4A56-9A39-F20F3B9C4D36} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
|
||||||
|
{7423EB30-FFE9-4707-A44B-571E89A7CA15} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
|
||||||
|
{4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
|
||||||
|
{94EC586A-2AE6-4AF2-894A-B0973C65BD68} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AspNetCoreVersion>2.0.0-*</AspNetCoreVersion>
|
<AspNetCoreVersion>2.0.0-*</AspNetCoreVersion>
|
||||||
|
<IdentityModelOpenIdVersion>2.1.3</IdentityModelOpenIdVersion>
|
||||||
|
<CoreFxVersion>4.3.0</CoreFxVersion>
|
||||||
<IdentityEFCompatVersion>2.2.1</IdentityEFCompatVersion>
|
<IdentityEFCompatVersion>2.2.1</IdentityEFCompatVersion>
|
||||||
<InternalAspNetCoreSdkVersion>2.1.0-*</InternalAspNetCoreSdkVersion>
|
<InternalAspNetCoreSdkVersion>2.1.0-*</InternalAspNetCoreSdkVersion>
|
||||||
<MoqVersion>4.7.1</MoqVersion>
|
<MoqVersion>4.7.1</MoqVersion>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Identity.Service;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Diagnostics.Identity.Service
|
||||||
|
{
|
||||||
|
public class DeveloperCertificateMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
private readonly IHostingEnvironment _environment;
|
||||||
|
private readonly IOptions<DeveloperCertificateOptions> _options;
|
||||||
|
private readonly ITimeStampManager _timeStampManager;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
private readonly IOptionsCache<IdentityServiceOptions> _identityServiceOptionsCache;
|
||||||
|
|
||||||
|
public DeveloperCertificateMiddleware(
|
||||||
|
RequestDelegate next,
|
||||||
|
IOptions<DeveloperCertificateOptions> options,
|
||||||
|
IOptionsCache<IdentityServiceOptions> identityServiceOptions,
|
||||||
|
ITimeStampManager timeStampManager,
|
||||||
|
IHostingEnvironment environment,
|
||||||
|
IConfiguration configuration)
|
||||||
|
{
|
||||||
|
_next = next;
|
||||||
|
_options = options;
|
||||||
|
_identityServiceOptionsCache = identityServiceOptions;
|
||||||
|
_environment = environment;
|
||||||
|
_timeStampManager = timeStampManager;
|
||||||
|
_configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InvokeAsync(HttpContext context)
|
||||||
|
{
|
||||||
|
var credentialsProvider = context.RequestServices.GetRequiredService<ISigningCredentialsPolicyProvider>();
|
||||||
|
var openIdOptionsCache = context.RequestServices.GetRequiredService<IOptionsCache<OpenIdConnectOptions>>();
|
||||||
|
|
||||||
|
if (_environment.IsDevelopment() &&
|
||||||
|
context.Request.Path.Equals(_options.Value.ListeningEndpoint))
|
||||||
|
{
|
||||||
|
if (context.Request.Method.Equals(HttpMethods.Get))
|
||||||
|
{
|
||||||
|
var credentials = await credentialsProvider.GetAllCredentialsAsync();
|
||||||
|
bool hasDevelopmentCertificate = await IsDevelopmentCertificateConfiguredAndValid();
|
||||||
|
var foundDeveloperCertificate = FoundDeveloperCertificate();
|
||||||
|
if (!foundDeveloperCertificate || !hasDevelopmentCertificate)
|
||||||
|
{
|
||||||
|
var page = new DeveloperCertificateErrorPage();
|
||||||
|
page.Model = new DeveloperCertificateViewModel()
|
||||||
|
{
|
||||||
|
CertificateExists = foundDeveloperCertificate,
|
||||||
|
CertificateIsInvalid = !hasDevelopmentCertificate,
|
||||||
|
Options = _options.Value
|
||||||
|
};
|
||||||
|
|
||||||
|
await page.ExecuteAsync(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (context.Request.Method.Equals(HttpMethods.Post))
|
||||||
|
{
|
||||||
|
CreateDevelopmentCertificate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _next(context);
|
||||||
|
void CreateDevelopmentCertificate()
|
||||||
|
{
|
||||||
|
using (var rsa = RSA.Create(2048))
|
||||||
|
{
|
||||||
|
var signingRequest = new CertificateRequest(
|
||||||
|
new X500DistinguishedName("CN=IdentityService.Development"), rsa, HashAlgorithmName.SHA256);
|
||||||
|
var enhacedKeyUsage = new OidCollection();
|
||||||
|
enhacedKeyUsage.Add(new Oid("1.3.6.1.5.5.7.3.1", "Server Authentication"));
|
||||||
|
signingRequest.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(enhacedKeyUsage, critical: true));
|
||||||
|
signingRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, critical: true));
|
||||||
|
|
||||||
|
var certificate = signingRequest.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(1));
|
||||||
|
certificate.FriendlyName = "Identity Service developer certificate";
|
||||||
|
|
||||||
|
// We need to take this step so that the key gets persisted.
|
||||||
|
var export = certificate.Export(X509ContentType.Pkcs12, "");
|
||||||
|
var imported = new X509Certificate2(export, "", X509KeyStorageFlags.PersistKeySet);
|
||||||
|
Array.Clear(export, 0, export.Length);
|
||||||
|
|
||||||
|
using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
|
||||||
|
{
|
||||||
|
store.Open(OpenFlags.ReadWrite);
|
||||||
|
store.Add(imported);
|
||||||
|
store.Close();
|
||||||
|
_identityServiceOptionsCache.TryRemove(Options.DefaultName);
|
||||||
|
openIdOptionsCache.TryRemove(OpenIdConnectDefaults.AuthenticationScheme);
|
||||||
|
|
||||||
|
context.Response.StatusCode = StatusCodes.Status204NoContent;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FoundDeveloperCertificate()
|
||||||
|
{
|
||||||
|
using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
|
||||||
|
{
|
||||||
|
store.Open(OpenFlags.ReadOnly);
|
||||||
|
var developmentCertificate = store.Certificates.Find(
|
||||||
|
X509FindType.FindBySubjectName,
|
||||||
|
"IdentityService.Development",
|
||||||
|
validOnly: false);
|
||||||
|
|
||||||
|
store.Close();
|
||||||
|
return developmentCertificate.OfType<X509Certificate2>().Any();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task<bool> IsDevelopmentCertificateConfiguredAndValid()
|
||||||
|
{
|
||||||
|
var certificates = await credentialsProvider.GetAllCredentialsAsync();
|
||||||
|
return certificates.Any(
|
||||||
|
c => _timeStampManager.IsValidPeriod(c.NotBefore, c.Expires) &&
|
||||||
|
c.Credentials.Key is X509SecurityKey key &&
|
||||||
|
key.Certificate.Subject.Equals("CN=IdentityService.Development"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Diagnostics.Identity.Service
|
||||||
|
{
|
||||||
|
public class DeveloperCertificateOptions
|
||||||
|
{
|
||||||
|
public PathString ListeningEndpoint { get; set; } = "/tfp/IdentityService/signinsignup/oauth2/v2.0/authorize";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Diagnostics.Identity.Service
|
||||||
|
{
|
||||||
|
public static class IdentityApplicationBuilderExtensions
|
||||||
|
{
|
||||||
|
public static IApplicationBuilder UseDevelopmentCertificateErrorPage(
|
||||||
|
this IApplicationBuilder builder,
|
||||||
|
IConfiguration configuration)
|
||||||
|
{
|
||||||
|
builder.UseMiddleware<DeveloperCertificateMiddleware>(configuration);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
|
||||||
|
|
||||||
|
<Import Project="..\..\build\common.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<Description>ASP.NET Core Identity Service Diagnostics Middleware.</Description>
|
||||||
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<PackageTags>aspnetcore</PackageTags>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="$(AspNetCoreVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="$(AspNetCoreVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.RazorViews.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../Microsoft.AspNetCore.Identity.Service/Microsoft.AspNetCore.Identity.Service.csproj" />
|
||||||
|
<ProjectReference Include="../Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore/Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore.csproj" />
|
||||||
|
<ProjectReference Include="../Microsoft.AspNetCore.Identity.Service.Mvc/Microsoft.AspNetCore.Identity.Service.Mvc.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<DotNetCliToolReference Include="RazorPageGenerator" Version="$(AspNetCoreVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="Strings.Designer.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Strings.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Update="Strings.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Diagnostics.Identity.Service {
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Strings {
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Strings() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
|
get {
|
||||||
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.AspNetCore.Diagnostics.Identity.Service.Strings", typeof(Strings).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Developer certificate.
|
||||||
|
/// </summary>
|
||||||
|
internal static string CertificateErrorPage_Title {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("CertificateErrorPage_Title", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Create certificate.
|
||||||
|
/// </summary>
|
||||||
|
internal static string CreateCertificate {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("CreateCertificate", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Done.
|
||||||
|
/// </summary>
|
||||||
|
internal static string CreateCertificateDone {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("CreateCertificateDone", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Certificate creation failed..
|
||||||
|
/// </summary>
|
||||||
|
internal static string CreateCertificateFailed {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("CreateCertificateFailed", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Certificate creation succeeded. Try refreshing the page..
|
||||||
|
/// </summary>
|
||||||
|
internal static string CreateCertificateRefresh {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("CreateCertificateRefresh", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Creating developer certificate....
|
||||||
|
/// </summary>
|
||||||
|
internal static string CreateCertificateRunning {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("CreateCertificateRunning", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Identity requires a certificate to sign tokens. You can create a developer certificate by clicking the Create Certificate button to generate a developer certificate for you automatically. This will create a self-signed certificate with subject IdentityService.Development and will add it to your current user personal store.
|
||||||
|
/// Alternatively, you can create this certificate manually with the instructions given in the following link:
|
||||||
|
/// .
|
||||||
|
/// </summary>
|
||||||
|
internal static string ManualCertificateGenerationInfo {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ManualCertificateGenerationInfo", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to https://go.microsoft.com/fwlink/?linkid=848037.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ManualCertificateGenerationInfoLink {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ManualCertificateGenerationInfoLink", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to The developer certificate is missing or invalid.
|
||||||
|
/// </summary>
|
||||||
|
internal static string MissingOrInvalidCertificate {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("MissingOrInvalidCertificate", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="CertificateErrorPage_Title" xml:space="preserve">
|
||||||
|
<value>Developer certificate</value>
|
||||||
|
</data>
|
||||||
|
<data name="CreateCertificate" xml:space="preserve">
|
||||||
|
<value>Create certificate</value>
|
||||||
|
</data>
|
||||||
|
<data name="CreateCertificateDone" xml:space="preserve">
|
||||||
|
<value>Done</value>
|
||||||
|
</data>
|
||||||
|
<data name="CreateCertificateFailed" xml:space="preserve">
|
||||||
|
<value>Certificate creation failed.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CreateCertificateRefresh" xml:space="preserve">
|
||||||
|
<value>Certificate creation succeeded. Try refreshing the page.</value>
|
||||||
|
</data>
|
||||||
|
<data name="CreateCertificateRunning" xml:space="preserve">
|
||||||
|
<value>Creating developer certificate...</value>
|
||||||
|
</data>
|
||||||
|
<data name="ManualCertificateGenerationInfo" xml:space="preserve">
|
||||||
|
<value>Identity requires a certificate to sign tokens. You can create a developer certificate by clicking the Create Certificate button to generate a developer certificate for you automatically. This will create a self-signed certificate with subject IdentityService.Development and will add it to your current user personal store.
|
||||||
|
Alternatively, you can create this certificate manually with the instructions given in the following link:
|
||||||
|
</value>
|
||||||
|
</data>
|
||||||
|
<data name="ManualCertificateGenerationInfoLink" xml:space="preserve">
|
||||||
|
<value>https://go.microsoft.com/fwlink/?linkid=848037</value>
|
||||||
|
</data>
|
||||||
|
<data name="MissingOrInvalidCertificate" xml:space="preserve">
|
||||||
|
<value>The developer certificate is missing or invalid</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
247
src/Microsoft.AspNetCore.Diagnostics.Identity.Service/Views/DeveloperCertificateErrorPage.Designer.cs
generated
Normal file
247
src/Microsoft.AspNetCore.Diagnostics.Identity.Service/Views/DeveloperCertificateErrorPage.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,247 @@
|
||||||
|
namespace Microsoft.AspNetCore.Diagnostics.Identity.Service
|
||||||
|
{
|
||||||
|
#line hidden
|
||||||
|
#line 1 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
using System;
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
internal class DeveloperCertificateErrorPage : Microsoft.Extensions.RazorViews.BaseView
|
||||||
|
{
|
||||||
|
#pragma warning disable 1998
|
||||||
|
public async override global::System.Threading.Tasks.Task ExecuteAsync()
|
||||||
|
{
|
||||||
|
#line 2 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
|
||||||
|
Response.StatusCode = 500;
|
||||||
|
Response.ContentType = "text/html; charset=utf-8";
|
||||||
|
Response.ContentLength = null; // Clear any prior Content-Length
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(@"<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang=""en"" xmlns=""http://www.w3.org/1999/xhtml"">
|
||||||
|
<head>
|
||||||
|
<meta charset=""utf-8"" />
|
||||||
|
<title>Internal Server Error</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Arial, Helvetica, sans-serif;
|
||||||
|
font-size: .813em;
|
||||||
|
line-height: 1.4em;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5 {
|
||||||
|
font-weight: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #44525e;
|
||||||
|
margin: 15px 0 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 10px 5px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: #363636;
|
||||||
|
margin: 5px 5px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: Consolas, ""Courier New"", courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #1ba1e2;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #13709e;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: 1px #ddd solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .titleerror {
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#createCertificate {
|
||||||
|
font-size: 14px;
|
||||||
|
background: #44c5f2;
|
||||||
|
color: #ffffff;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 12px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-weight: normal;");
|
||||||
|
WriteLiteral(@"
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#createCertificate:disabled {
|
||||||
|
background-color: #a9e4f9;
|
||||||
|
border-color: #44c5f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expanded {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsed {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>");
|
||||||
|
#line 110 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
Write(Strings.CertificateErrorPage_Title);
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</h1>\r\n <p>\r\n </p>\r\n <hr />\r\n\r\n");
|
||||||
|
#line 115 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
if (!Model.CertificateExists || Model.CertificateIsInvalid)
|
||||||
|
{
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <h2>");
|
||||||
|
#line 117 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
Write(Strings.MissingOrInvalidCertificate);
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</h2>\r\n <p>");
|
||||||
|
#line 118 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
Write(Strings.ManualCertificateGenerationInfo);
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("<a");
|
||||||
|
BeginWriteAttribute("href", " href=\"", 2170, "\"", 2221, 1);
|
||||||
|
#line 118 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
WriteAttributeValue("", 2177, Strings.ManualCertificateGenerationInfoLink, 2177, 44, false);
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
EndWriteAttribute();
|
||||||
|
WriteLiteral(">");
|
||||||
|
#line 118 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
Write(Strings.ManualCertificateGenerationInfoLink);
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</a></p>\r\n <br />\r\n <hr />\r\n <div>\r\n <p>\r\n <button id=\"createCertificate\" onclick=\"CreateCertificate()\">");
|
||||||
|
#line 123 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
Write(Strings.CreateCertificate);
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(@"</button>
|
||||||
|
<span id=""createCertificateError"" class=""error""></span>
|
||||||
|
<span id=""createCertificateSuccess""></span>
|
||||||
|
</p>
|
||||||
|
<script>
|
||||||
|
function CreateCertificate() {
|
||||||
|
createCertificate.disabled = true;
|
||||||
|
createCertificateError.innerHTML = """";
|
||||||
|
createCertificate.innerHTML = """);
|
||||||
|
#line 131 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
Write(JavaScriptEncode(Strings.CreateCertificateRunning));
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\";\r\n\r\n var req = new XMLHttpRequest();\r\n\r\n req.onload = function (e) {\r\n if (req.status === 204) {\r\n createCertificate.innerHTML = \"");
|
||||||
|
#line 137 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
Write(JavaScriptEncode(Strings.CreateCertificateDone));
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\";\r\n createCertificateSuccess.innerHTML = \"");
|
||||||
|
#line 138 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
Write(JavaScriptEncode(Strings.CreateCertificateRefresh));
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(@""";
|
||||||
|
} else {
|
||||||
|
ErrorCreatingCertificate();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
req.onerror = function (e) {
|
||||||
|
ErrorCreatingCertificate();
|
||||||
|
};
|
||||||
|
|
||||||
|
var formBody = """";
|
||||||
|
req.open(""POST"", """);
|
||||||
|
#line 149 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
Write(JavaScriptEncode(Model.Options.ListeningEndpoint.Value));
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(@""", true);
|
||||||
|
req.setRequestHeader(""Content-type"", ""application/x-www-form-urlencoded"");
|
||||||
|
req.setRequestHeader(""Content-length"", formBody.length);
|
||||||
|
req.setRequestHeader(""Connection"", ""close"");
|
||||||
|
req.send(formBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ErrorCreatingCertificate() {
|
||||||
|
createCertificate.innerHTML = """);
|
||||||
|
#line 157 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
Write(JavaScriptEncode(Strings.CreateCertificate));
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\";\r\n createCertificateError.innerHTML = \"");
|
||||||
|
#line 158 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
Write(JavaScriptEncode(Strings.CreateCertificateFailed));
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\";\r\n createCertificate.disabled = false;\r\n }\r\n </script>\r\n </div>\r\n");
|
||||||
|
#line 163 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</body>\r\n</html>");
|
||||||
|
}
|
||||||
|
#pragma warning restore 1998
|
||||||
|
#line 8 "DeveloperCertificateErrorPage.cshtml"
|
||||||
|
|
||||||
|
public DeveloperCertificateViewModel Model { get; set; }
|
||||||
|
|
||||||
|
public string UrlEncode(string content)
|
||||||
|
{
|
||||||
|
return UrlEncoder.Encode(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string JavaScriptEncode(string content)
|
||||||
|
{
|
||||||
|
return JavaScriptEncoder.Encode(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
@using System
|
||||||
|
@{
|
||||||
|
Response.StatusCode = 500;
|
||||||
|
Response.ContentType = "text/html; charset=utf-8";
|
||||||
|
Response.ContentLength = null; // Clear any prior Content-Length
|
||||||
|
}
|
||||||
|
@functions
|
||||||
|
{
|
||||||
|
public DeveloperCertificateViewModel Model { get; set; }
|
||||||
|
|
||||||
|
public string UrlEncode(string content)
|
||||||
|
{
|
||||||
|
return UrlEncoder.Encode(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string JavaScriptEncode(string content)
|
||||||
|
{
|
||||||
|
return JavaScriptEncoder.Encode(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Internal Server Error</title>
|
||||||
|
<style>
|
||||||
|
<%$ include: ErrorPage.css %>
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>@Strings.CertificateErrorPage_Title</h1>
|
||||||
|
<p>
|
||||||
|
</p>
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
@if (!Model.CertificateExists || Model.CertificateIsInvalid)
|
||||||
|
{
|
||||||
|
<h2>@Strings.MissingOrInvalidCertificate</h2>
|
||||||
|
<p>@Strings.ManualCertificateGenerationInfo<a href="@Strings.ManualCertificateGenerationInfoLink">@Strings.ManualCertificateGenerationInfoLink</a></p>
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
<button id="createCertificate" onclick="CreateCertificate()">@Strings.CreateCertificate</button>
|
||||||
|
<span id="createCertificateError" class="error"></span>
|
||||||
|
<span id="createCertificateSuccess"></span>
|
||||||
|
</p>
|
||||||
|
<script>
|
||||||
|
function CreateCertificate() {
|
||||||
|
createCertificate.disabled = true;
|
||||||
|
createCertificateError.innerHTML = "";
|
||||||
|
createCertificate.innerHTML = "@JavaScriptEncode(Strings.CreateCertificateRunning)";
|
||||||
|
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
|
||||||
|
req.onload = function (e) {
|
||||||
|
if (req.status === 204) {
|
||||||
|
createCertificate.innerHTML = "@JavaScriptEncode(Strings.CreateCertificateDone)";
|
||||||
|
createCertificateSuccess.innerHTML = "@JavaScriptEncode(Strings.CreateCertificateRefresh)";
|
||||||
|
} else {
|
||||||
|
ErrorCreatingCertificate();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
req.onerror = function (e) {
|
||||||
|
ErrorCreatingCertificate();
|
||||||
|
};
|
||||||
|
|
||||||
|
var formBody = "";
|
||||||
|
req.open("POST", "@JavaScriptEncode(Model.Options.ListeningEndpoint.Value)", true);
|
||||||
|
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||||
|
req.setRequestHeader("Content-length", formBody.length);
|
||||||
|
req.setRequestHeader("Connection", "close");
|
||||||
|
req.send(formBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ErrorCreatingCertificate() {
|
||||||
|
createCertificate.innerHTML = "@JavaScriptEncode(Strings.CreateCertificate)";
|
||||||
|
createCertificateError.innerHTML = "@JavaScriptEncode(Strings.CreateCertificateFailed)";
|
||||||
|
createCertificate.disabled = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Diagnostics.Identity.Service
|
||||||
|
{
|
||||||
|
public class DeveloperCertificateViewModel
|
||||||
|
{
|
||||||
|
public DeveloperCertificateOptions Options { get; set; }
|
||||||
|
public bool CertificateExists { get; set; }
|
||||||
|
public bool CertificateIsInvalid { get; set; }
|
||||||
|
public bool CertificateIsFoundInConfiguration { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Arial, Helvetica, sans-serif;
|
||||||
|
font-size: .813em;
|
||||||
|
line-height: 1.4em;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5 {
|
||||||
|
font-weight: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #44525e;
|
||||||
|
margin: 15px 0 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 10px 5px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: #363636;
|
||||||
|
margin: 5px 5px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: Consolas, "Courier New", courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #1ba1e2;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #13709e;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: 1px #ddd solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .titleerror {
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#createCertificate {
|
||||||
|
font-size: 14px;
|
||||||
|
background: #44c5f2;
|
||||||
|
color: #ffffff;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 12px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#createCertificate:disabled {
|
||||||
|
background-color: #a9e4f9;
|
||||||
|
border-color: #44c5f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expanded {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsed {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
dotnet razorpagegenerator Microsoft.AspNetCore.Diagnostics.Identity.Service
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
|
||||||
|
public class ApplicationScope : IEquatable<ApplicationScope>
|
||||||
|
{
|
||||||
|
public static readonly ApplicationScope OpenId = new ApplicationScope("openid");
|
||||||
|
public static readonly ApplicationScope Profile = new ApplicationScope("profile");
|
||||||
|
public static readonly ApplicationScope Email = new ApplicationScope("email");
|
||||||
|
public static readonly ApplicationScope OfflineAccess = new ApplicationScope("offline_access");
|
||||||
|
|
||||||
|
public static readonly IReadOnlyDictionary<string, ApplicationScope> CanonicalScopes = new Dictionary<string, ApplicationScope>(StringComparer.Ordinal)
|
||||||
|
{
|
||||||
|
[OpenId.Scope] = OpenId,
|
||||||
|
[Profile.Scope] = Profile,
|
||||||
|
[Email.Scope] = Email,
|
||||||
|
[OfflineAccess.Scope] = OfflineAccess
|
||||||
|
};
|
||||||
|
|
||||||
|
private ApplicationScope(string scope)
|
||||||
|
{
|
||||||
|
Scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApplicationScope(string clientId, string scope)
|
||||||
|
{
|
||||||
|
ClientId = clientId;
|
||||||
|
Scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ClientId { get; }
|
||||||
|
public string Scope { get; }
|
||||||
|
|
||||||
|
public bool Equals(ApplicationScope other) => string.Equals(ClientId, other?.ClientId, StringComparison.Ordinal) &&
|
||||||
|
string.Equals(Scope, other?.Scope, StringComparison.Ordinal);
|
||||||
|
|
||||||
|
public override bool Equals(object obj) => Equals(obj as ApplicationScope);
|
||||||
|
|
||||||
|
public override int GetHashCode() => ClientId == null ? Scope.GetHashCode() : ClientId.GetHashCode() ^ Scope.GetHashCode();
|
||||||
|
|
||||||
|
private string DebuggerDisplay() => ClientId != null ? $"{ClientId},{Scope}" : Scope;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class AuthorizationGrant
|
||||||
|
{
|
||||||
|
private AuthorizationGrant(OpenIdConnectMessage error)
|
||||||
|
{
|
||||||
|
IsValid = false;
|
||||||
|
Error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthorizationGrant(
|
||||||
|
string userId,
|
||||||
|
string clientId,
|
||||||
|
IEnumerable<string> grantedTokens,
|
||||||
|
IEnumerable<ApplicationScope> grantedScopes,
|
||||||
|
Token token)
|
||||||
|
{
|
||||||
|
IsValid = true;
|
||||||
|
UserId = userId;
|
||||||
|
ClientId = clientId;
|
||||||
|
GrantedTokens = grantedTokens;
|
||||||
|
GrantedScopes = grantedScopes;
|
||||||
|
Token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsValid { get; }
|
||||||
|
|
||||||
|
public OpenIdConnectMessage Error { get; }
|
||||||
|
public Token Token { get; }
|
||||||
|
public string UserId { get; }
|
||||||
|
public string ClientId { get; }
|
||||||
|
public IEnumerable<string> GrantedTokens { get; }
|
||||||
|
public IEnumerable<ApplicationScope> GrantedScopes { get; }
|
||||||
|
public string Resource { get; }
|
||||||
|
|
||||||
|
public static AuthorizationGrant Invalid(OpenIdConnectMessage error)
|
||||||
|
{
|
||||||
|
return new AuthorizationGrant(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AuthorizationGrant Valid(
|
||||||
|
string userId,
|
||||||
|
string clientId,
|
||||||
|
IEnumerable<string> grantedTokens,
|
||||||
|
IEnumerable<ApplicationScope> grantedScopes,
|
||||||
|
Token token)
|
||||||
|
{
|
||||||
|
return new AuthorizationGrant(userId, clientId, grantedTokens, grantedScopes, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class AuthorizationRequest
|
||||||
|
{
|
||||||
|
private AuthorizationRequest(AuthorizationRequestError error)
|
||||||
|
{
|
||||||
|
IsValid = false;
|
||||||
|
Error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthorizationRequest(OpenIdConnectMessage request, RequestGrants requestGrants)
|
||||||
|
{
|
||||||
|
IsValid = true;
|
||||||
|
Message = request;
|
||||||
|
RequestGrants = requestGrants;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsValid { get; }
|
||||||
|
public AuthorizationRequestError Error { get; }
|
||||||
|
public OpenIdConnectMessage Message { get; }
|
||||||
|
public RequestGrants RequestGrants { get; }
|
||||||
|
|
||||||
|
public static AuthorizationRequest Invalid(AuthorizationRequestError authorizationRequestError)
|
||||||
|
{
|
||||||
|
return new AuthorizationRequest(authorizationRequestError);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AuthorizationRequest Valid(
|
||||||
|
OpenIdConnectMessage request,
|
||||||
|
RequestGrants requestGrants)
|
||||||
|
{
|
||||||
|
return new AuthorizationRequest(request, requestGrants);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenGeneratingContext CreateTokenGeneratingContext(ClaimsPrincipal user, ClaimsPrincipal application)
|
||||||
|
{
|
||||||
|
return new TokenGeneratingContext(
|
||||||
|
user,
|
||||||
|
application,
|
||||||
|
Message,
|
||||||
|
RequestGrants);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class AuthorizationResponse
|
||||||
|
{
|
||||||
|
public OpenIdConnectMessage Message { get; set; }
|
||||||
|
public string RedirectUri { get; set; }
|
||||||
|
public string ResponseMode { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service.Claims
|
||||||
|
{
|
||||||
|
public class ClaimsGenerationContext
|
||||||
|
{
|
||||||
|
public string TokenType { get; set; }
|
||||||
|
public TokenGeneratingContext GenerationContext { get; set; }
|
||||||
|
public IEnumerable<TokenResult> GeneratedTokens { get; set; }
|
||||||
|
public IList<Claim> Claims { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface ITokenClaimsManager
|
||||||
|
{
|
||||||
|
Task CreateClaimsAsync(TokenGeneratingContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service.Claims
|
||||||
|
{
|
||||||
|
public interface ITokenClaimsProvider
|
||||||
|
{
|
||||||
|
int Order { get; }
|
||||||
|
Task OnGeneratingClaims(TokenGeneratingContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class ConfigurationContext
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public HttpContext HttpContext { get; set; }
|
||||||
|
public string AuthorizationEndpoint { get; set; }
|
||||||
|
public string TokenEndpoint { get; set; }
|
||||||
|
public string JwksUriEndpoint { get; set; }
|
||||||
|
public string EndSessionEndpoint { get; set; }
|
||||||
|
public NameValueCollection AdditionalValues { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IAuthorizationRequestFactory
|
||||||
|
{
|
||||||
|
Task<AuthorizationRequest> CreateAuthorizationRequestAsync(IDictionary<string, string[]> requestParameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IAuthorizationResponseFactory
|
||||||
|
{
|
||||||
|
Task<AuthorizationResponse> CreateAuthorizationResponseAsync(TokenGeneratingContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IAuthorizationResponseParameterProvider
|
||||||
|
{
|
||||||
|
int Order { get; }
|
||||||
|
|
||||||
|
Task AddParameters(TokenGeneratingContext context, AuthorizationResponse response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IConfigurationManager
|
||||||
|
{
|
||||||
|
Task<OpenIdConnectConfiguration> GetConfigurationAsync(ConfigurationContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IConfigurationMetadataProvider
|
||||||
|
{
|
||||||
|
int Order { get; }
|
||||||
|
|
||||||
|
Task ConfigureMetadataAsync(OpenIdConnectConfiguration configuration, ConfigurationContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IIdentityServiceBuilder
|
||||||
|
{
|
||||||
|
IServiceCollection Services { get; }
|
||||||
|
Type ApplicationType { get; }
|
||||||
|
Type UserType { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IKeySetMetadataProvider
|
||||||
|
{
|
||||||
|
Task<JsonWebKeySet> GetKeysAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface ILogoutRequestFactory
|
||||||
|
{
|
||||||
|
Task<LogoutRequest> CreateLogoutRequestAsync(IDictionary<string, string[]> requestParameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface ISigningCredentialsPolicyProvider
|
||||||
|
{
|
||||||
|
Task<IEnumerable<SigningCredentialsDescriptor>> GetAllCredentialsAsync();
|
||||||
|
Task<SigningCredentialsDescriptor> GetSigningCredentialsAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface ISigningCredentialsSource
|
||||||
|
{
|
||||||
|
Task<IEnumerable<SigningCredentialsDescriptor>> GetCredentials();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface ITokenManager
|
||||||
|
{
|
||||||
|
Task IssueTokensAsync(TokenGeneratingContext context);
|
||||||
|
Task<AuthorizationGrant> ExchangeTokenAsync(OpenIdConnectMessage message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface ITokenRequestFactory
|
||||||
|
{
|
||||||
|
Task<TokenRequest> CreateTokenRequestAsync(IDictionary<string, string[]> requestParameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface ITokenResponseFactory
|
||||||
|
{
|
||||||
|
Task<OpenIdConnectMessage> CreateTokenResponseAsync(TokenGeneratingContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface ITokenResponseParameterProvider
|
||||||
|
{
|
||||||
|
int Order { get; }
|
||||||
|
|
||||||
|
Task AddParameters(TokenGeneratingContext context, OpenIdConnectMessage response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class IdentityServiceClaimTypes
|
||||||
|
{
|
||||||
|
public const string TokenUniqueId = "tuid";
|
||||||
|
public const string ObjectId = "oid";
|
||||||
|
public const string JwtId = "jti";
|
||||||
|
public const string Issuer = "iss";
|
||||||
|
public const string Subject = "sub";
|
||||||
|
public const string Audience = "aud";
|
||||||
|
public const string AuthorizedParty = "azp";
|
||||||
|
public const string ClientId = "client_id";
|
||||||
|
public const string RedirectUri = "r_uri";
|
||||||
|
public const string LogoutRedirectUri = "lo_uri";
|
||||||
|
public const string IssuedAt = "iat";
|
||||||
|
public const string Expires = "exp";
|
||||||
|
public const string NotBefore = "nbf";
|
||||||
|
public const string Scope = "scp";
|
||||||
|
public const string Nonce = "nonce";
|
||||||
|
public const string CodeHash = "c_hash";
|
||||||
|
public const string AccessTokenHash = "at_hash";
|
||||||
|
public const string AuthenticationTime = "auth_time";
|
||||||
|
public const string UserId = "user_id";
|
||||||
|
public const string Version = "ver";
|
||||||
|
public const string Name = "name";
|
||||||
|
public const string GrantedToken = "g_token";
|
||||||
|
public const string TenantId = "tid";
|
||||||
|
public const string Resource = "rid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class IdentityServiceErrorCodes
|
||||||
|
{
|
||||||
|
public const string InvalidRequest = "invalid_request";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IAccessTokenIssuer
|
||||||
|
{
|
||||||
|
Task IssueAccessTokenAsync(TokenGeneratingContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IAuthorizationCodeIssuer
|
||||||
|
{
|
||||||
|
Task CreateAuthorizationCodeAsync(TokenGeneratingContext context);
|
||||||
|
Task<AuthorizationGrant> ExchangeAuthorizationCodeAsync(OpenIdConnectMessage message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IIdTokenIssuer
|
||||||
|
{
|
||||||
|
Task IssueIdTokenAsync(TokenGeneratingContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IRefreshTokenIssuer
|
||||||
|
{
|
||||||
|
Task IssueRefreshTokenAsync(TokenGeneratingContext context);
|
||||||
|
Task<AuthorizationGrant> ExchangeRefreshTokenAsync(OpenIdConnectMessage message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface ITokenHasher
|
||||||
|
{
|
||||||
|
string HashToken(string token, string algorithm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class TokenResult
|
||||||
|
{
|
||||||
|
public TokenResult(Token token, string serializedValue)
|
||||||
|
{
|
||||||
|
Token = token;
|
||||||
|
SerializedValue = serializedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenResult(Token token, string serializedValue, string tokenType)
|
||||||
|
: this(token, serializedValue)
|
||||||
|
{
|
||||||
|
Token = token;
|
||||||
|
TokenType = tokenType;
|
||||||
|
SerializedValue = serializedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Token Token { get; }
|
||||||
|
public string TokenType { get; }
|
||||||
|
public string SerializedValue { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class LogoutRequest
|
||||||
|
{
|
||||||
|
private LogoutRequest(OpenIdConnectMessage message)
|
||||||
|
{
|
||||||
|
Message = message;
|
||||||
|
IsValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LogoutRequest(OpenIdConnectMessage message, string logoutRedirectUri)
|
||||||
|
{
|
||||||
|
Message = message;
|
||||||
|
LogoutRedirectUri = logoutRedirectUri;
|
||||||
|
IsValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenIdConnectMessage Message { get; }
|
||||||
|
public string LogoutRedirectUri { get; set; }
|
||||||
|
public bool IsValid { get; }
|
||||||
|
|
||||||
|
public static LogoutRequest Valid(OpenIdConnectMessage message, string logoutRedirectUri) => new LogoutRequest(message, logoutRedirectUri);
|
||||||
|
public static LogoutRequest Invalid(OpenIdConnectMessage error) => new LogoutRequest(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<Import Project="..\..\build\common.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<Description>ASP.NET Core common types defining the main abstractions for Identity Service.</Description>
|
||||||
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<PackageTags>aspnetcore</PackageTags>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="$(AspNetCoreVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(AspNetCoreVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="$(IdentityModelOpenIdVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public static class PromptValues
|
||||||
|
{
|
||||||
|
public const string None = "none";
|
||||||
|
public const string Login = "login";
|
||||||
|
public const string Consent = "consent";
|
||||||
|
public const string SelectAccount = "select_account";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class AuthorizationRequestError
|
||||||
|
{
|
||||||
|
public AuthorizationRequestError(OpenIdConnectMessage error, string redirectUri, string responseMode)
|
||||||
|
{
|
||||||
|
Message = error;
|
||||||
|
RedirectUri = redirectUri;
|
||||||
|
ResponseMode = responseMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenIdConnectMessage Message { get; set; }
|
||||||
|
|
||||||
|
public string RedirectUri { get; set; }
|
||||||
|
|
||||||
|
public string ResponseMode { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class RedirectUriResolutionResult
|
||||||
|
{
|
||||||
|
private RedirectUriResolutionResult(string uri)
|
||||||
|
{
|
||||||
|
IsValid = true;
|
||||||
|
Uri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RedirectUriResolutionResult(OpenIdConnectMessage error)
|
||||||
|
{
|
||||||
|
IsValid = false;
|
||||||
|
Error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsValid { get; }
|
||||||
|
public string Uri { get; }
|
||||||
|
public OpenIdConnectMessage Error { get; }
|
||||||
|
|
||||||
|
public static RedirectUriResolutionResult Valid(string uri)
|
||||||
|
{
|
||||||
|
return new RedirectUriResolutionResult(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RedirectUriResolutionResult Invalid(OpenIdConnectMessage error)
|
||||||
|
{
|
||||||
|
return new RedirectUriResolutionResult(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class RequestGrants
|
||||||
|
{
|
||||||
|
public string RedirectUri { get; set; }
|
||||||
|
public string ResponseMode { get; set; }
|
||||||
|
public IList<string> Tokens { get; set; } = new List<string>();
|
||||||
|
public IList<ApplicationScope> Scopes { get; set; } = new List<ApplicationScope>();
|
||||||
|
public IList<Claim> Claims { get; set; } = new List<Claim>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class ScopeResolutionResult
|
||||||
|
{
|
||||||
|
public ScopeResolutionResult(IEnumerable<ApplicationScope> scopes)
|
||||||
|
{
|
||||||
|
IsValid = true;
|
||||||
|
Scopes = scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScopeResolutionResult(OpenIdConnectMessage error)
|
||||||
|
{
|
||||||
|
IsValid = false;
|
||||||
|
Error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ApplicationScope> Scopes { get; }
|
||||||
|
public OpenIdConnectMessage Error { get; }
|
||||||
|
public bool IsValid { get; }
|
||||||
|
|
||||||
|
public static ScopeResolutionResult Valid(IEnumerable<ApplicationScope> scopes)
|
||||||
|
{
|
||||||
|
return new ScopeResolutionResult(scopes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScopeResolutionResult Invalid(OpenIdConnectMessage error)
|
||||||
|
{
|
||||||
|
return new ScopeResolutionResult(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
[DebuggerDisplay("{GetDebugDisplay(),nq}")]
|
||||||
|
public class SigningCredentialsDescriptor
|
||||||
|
{
|
||||||
|
public SigningCredentialsDescriptor(
|
||||||
|
SigningCredentials credentials,
|
||||||
|
string algorithm,
|
||||||
|
DateTimeOffset notBefore,
|
||||||
|
DateTimeOffset expires,
|
||||||
|
IDictionary<string, string> metadata)
|
||||||
|
{
|
||||||
|
Credentials = credentials;
|
||||||
|
Algorithm = algorithm;
|
||||||
|
NotBefore = notBefore;
|
||||||
|
Expires = expires;
|
||||||
|
Metadata = metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Id => Credentials.Kid;
|
||||||
|
public string Algorithm { get; set; }
|
||||||
|
public DateTimeOffset NotBefore { get; set; }
|
||||||
|
public DateTimeOffset Expires { get; set; }
|
||||||
|
public SigningCredentials Credentials { get; set; }
|
||||||
|
public IDictionary<string, string> Metadata { get; set; }
|
||||||
|
|
||||||
|
private string GetDebugDisplay()
|
||||||
|
{
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder.Append($"Id = {Id}, ");
|
||||||
|
builder.Append($"Alg = {Algorithm}, ");
|
||||||
|
builder.Append($"Nbf = {NotBefore}, ");
|
||||||
|
builder.Append($"Exp = {Expires}, ");
|
||||||
|
foreach (var kvp in Metadata)
|
||||||
|
{
|
||||||
|
builder.Append($"{kvp.Key} = {kvp.Value}, ");
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class TokenGeneratingContext
|
||||||
|
{
|
||||||
|
private readonly IList<TokenResult> _issuedTokens = new List<TokenResult>();
|
||||||
|
|
||||||
|
public TokenGeneratingContext(
|
||||||
|
ClaimsPrincipal user,
|
||||||
|
ClaimsPrincipal application,
|
||||||
|
OpenIdConnectMessage requestParameters,
|
||||||
|
RequestGrants requestGrants)
|
||||||
|
{
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (application == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(application));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestParameters == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(requestParameters));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestGrants == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(requestGrants));
|
||||||
|
}
|
||||||
|
|
||||||
|
User = user;
|
||||||
|
Application = application;
|
||||||
|
RequestParameters = requestParameters;
|
||||||
|
RequestGrants = requestGrants;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClaimsPrincipal User { get; }
|
||||||
|
public ClaimsPrincipal Application { get; }
|
||||||
|
public OpenIdConnectMessage RequestParameters { get; }
|
||||||
|
public RequestGrants RequestGrants { get; }
|
||||||
|
public IList<Claim> AmbientClaims { get; } = new List<Claim>();
|
||||||
|
public string CurrentToken { get; private set; }
|
||||||
|
public IList<Claim> CurrentClaims { get; private set; }
|
||||||
|
public IEnumerable<TokenResult> IssuedTokens { get => _issuedTokens; }
|
||||||
|
|
||||||
|
public TokenResult AuthorizationCode =>
|
||||||
|
IssuedTokens.SingleOrDefault(it => it.Token.IsOfKind(TokenTypes.AuthorizationCode));
|
||||||
|
public TokenResult AccessToken =>
|
||||||
|
IssuedTokens.SingleOrDefault(it => it.Token.IsOfKind(TokenTypes.AccessToken));
|
||||||
|
public TokenResult IdToken =>
|
||||||
|
IssuedTokens.SingleOrDefault(it => it.Token.IsOfKind(TokenTypes.IdToken));
|
||||||
|
public TokenResult RefreshToken =>
|
||||||
|
IssuedTokens.SingleOrDefault(it => it.Token.IsOfKind(TokenTypes.RefreshToken));
|
||||||
|
|
||||||
|
public void InitializeForToken(string tokenType)
|
||||||
|
{
|
||||||
|
if (tokenType == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(tokenType));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CurrentToken != null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Currently issuing a token for {CurrentToken}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IssuedTokens.Any(it => it.Token.IsOfKind(tokenType)))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"A token of type '{tokenType}' has already been emitted.");
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentToken = tokenType;
|
||||||
|
CurrentClaims = new List<Claim>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsContextForTokenTypes(params string [] tokenTypes)
|
||||||
|
{
|
||||||
|
if (CurrentToken == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (var token in tokenTypes)
|
||||||
|
{
|
||||||
|
if (CurrentToken.Equals(token, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddClaimToCurrentToken(Claim claim)
|
||||||
|
{
|
||||||
|
if (CurrentToken == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentClaims.Add(claim);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddClaimToCurrentToken(string type, string value) => AddClaimToCurrentToken(new Claim(type, value));
|
||||||
|
|
||||||
|
public void AddToken(TokenResult result)
|
||||||
|
{
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.Token.IsOfKind(CurrentToken))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Can't add a result of token type '{result.Token.Kind}' to a context of '{CurrentToken ?? "(null)"}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
_issuedTokens.Add(result);
|
||||||
|
CurrentToken = null;
|
||||||
|
CurrentClaims = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class TokenKinds
|
||||||
|
{
|
||||||
|
public static readonly string Bearer = "Bearer";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class TokenRequest
|
||||||
|
{
|
||||||
|
private TokenRequest(OpenIdConnectMessage error)
|
||||||
|
{
|
||||||
|
IsValid = false;
|
||||||
|
Error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TokenRequest(
|
||||||
|
OpenIdConnectMessage request,
|
||||||
|
string userId,
|
||||||
|
string clientId,
|
||||||
|
RequestGrants grants)
|
||||||
|
{
|
||||||
|
IsValid = true;
|
||||||
|
Request = request;
|
||||||
|
UserId = userId;
|
||||||
|
ClientId = clientId;
|
||||||
|
RequestGrants = grants;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsValid { get; }
|
||||||
|
public OpenIdConnectMessage Request { get; }
|
||||||
|
public string UserId { get; }
|
||||||
|
public string ClientId { get; }
|
||||||
|
public OpenIdConnectMessage Error { get; }
|
||||||
|
public RequestGrants RequestGrants { get; }
|
||||||
|
|
||||||
|
public static TokenRequest Invalid(OpenIdConnectMessage error)
|
||||||
|
{
|
||||||
|
return new TokenRequest(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TokenRequest Valid(
|
||||||
|
OpenIdConnectMessage request,
|
||||||
|
string userId,
|
||||||
|
string clientId,
|
||||||
|
RequestGrants grants)
|
||||||
|
{
|
||||||
|
return new TokenRequest(request, userId, clientId, grants);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenGeneratingContext CreateTokenGeneratingContext(ClaimsPrincipal user, ClaimsPrincipal application)
|
||||||
|
{
|
||||||
|
return new TokenGeneratingContext(user, application, Request, RequestGrants);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class TokenTypes
|
||||||
|
{
|
||||||
|
public const string AuthorizationCode = "code";
|
||||||
|
public const string AccessToken = "access_token";
|
||||||
|
public const string RefreshToken = "refresh_token";
|
||||||
|
public const string IdToken = "id_token";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class AccessToken : Token
|
||||||
|
{
|
||||||
|
public AccessToken(IEnumerable<Claim> claims)
|
||||||
|
: base(ValidateClaims(claims))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Claim> ValidateClaims(IEnumerable<Claim> claims)
|
||||||
|
{
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.Issuer, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.Subject, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.Audience, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.Scope, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.AuthorizedParty, claims);
|
||||||
|
return claims;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Kind => TokenTypes.AccessToken;
|
||||||
|
public string Issuer => GetClaimValue(IdentityServiceClaimTypes.Issuer);
|
||||||
|
public string Subject => GetClaimValue(IdentityServiceClaimTypes.Subject);
|
||||||
|
public string Audience => GetClaimValue(IdentityServiceClaimTypes.Audience);
|
||||||
|
public string AuthorizedParty => GetClaimValue(IdentityServiceClaimTypes.AuthorizedParty);
|
||||||
|
public IEnumerable<string> Scopes => GetClaimValuesOrEmpty(IdentityServiceClaimTypes.Scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class AuthorizationCode : Token
|
||||||
|
{
|
||||||
|
public AuthorizationCode(IEnumerable<Claim> claims)
|
||||||
|
: base(ValidateClaims(claims))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Claim> ValidateClaims(IEnumerable<Claim> claims)
|
||||||
|
{
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.UserId, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.ClientId, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.RedirectUri, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.Scope, claims);
|
||||||
|
EnsureRequiredClaim(IdentityServiceClaimTypes.GrantedToken, claims);
|
||||||
|
|
||||||
|
return claims;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Kind => TokenTypes.AuthorizationCode;
|
||||||
|
public string UserId => GetClaimValue(IdentityServiceClaimTypes.UserId);
|
||||||
|
public string ClientId => GetClaimValue(IdentityServiceClaimTypes.ClientId);
|
||||||
|
public string Resource => GetClaimValue(IdentityServiceClaimTypes.Resource);
|
||||||
|
public string RedirectUri => GetClaimValue(IdentityServiceClaimTypes.RedirectUri);
|
||||||
|
public IEnumerable<string> Scopes => GetClaimValuesOrEmpty(IdentityServiceClaimTypes.Scope);
|
||||||
|
public IEnumerable<string> GrantedTokens => GetClaimValuesOrEmpty(IdentityServiceClaimTypes.GrantedToken);
|
||||||
|
public string Nonce => GetClaimValue(IdentityServiceClaimTypes.Nonce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class IdToken : Token
|
||||||
|
{
|
||||||
|
public IdToken(IEnumerable<Claim> claims)
|
||||||
|
: base(ValidateClaims(claims))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Claim> ValidateClaims(IEnumerable<Claim> claims)
|
||||||
|
{
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.Issuer, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.Subject, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.Audience, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.Nonce, claims, required: false);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.CodeHash, claims, required: false);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.AccessTokenHash, claims, required: false);
|
||||||
|
return claims;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Kind => TokenTypes.IdToken;
|
||||||
|
public string Issuer => GetClaimValue(IdentityServiceClaimTypes.Issuer);
|
||||||
|
public string Subject => GetClaimValue(IdentityServiceClaimTypes.Subject);
|
||||||
|
public string Audience => GetClaimValue(IdentityServiceClaimTypes.Audience);
|
||||||
|
public string Nonce => GetClaimValue(IdentityServiceClaimTypes.Nonce);
|
||||||
|
public string CodeHash => GetClaimValue(IdentityServiceClaimTypes.CodeHash);
|
||||||
|
public string AccessTokenHash => GetClaimValue(IdentityServiceClaimTypes.AccessTokenHash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class RefreshToken : Token
|
||||||
|
{
|
||||||
|
public RefreshToken(IEnumerable<Claim> claims)
|
||||||
|
: base(ValidateClaims(claims))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Claim> ValidateClaims(IEnumerable<Claim> claims)
|
||||||
|
{
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.UserId, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.ClientId, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.Scope, claims);
|
||||||
|
EnsureRequiredClaim(IdentityServiceClaimTypes.GrantedToken, claims);
|
||||||
|
|
||||||
|
return claims;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Kind => TokenTypes.RefreshToken;
|
||||||
|
public string UserId => GetClaimValue(IdentityServiceClaimTypes.UserId);
|
||||||
|
public string ClientId => GetClaimValue(IdentityServiceClaimTypes.ClientId);
|
||||||
|
public string Resource => GetClaimValue(IdentityServiceClaimTypes.Resource);
|
||||||
|
public string Issuer => GetClaimValue(IdentityServiceClaimTypes.Issuer);
|
||||||
|
public IEnumerable<string> GrantedTokens => GetClaimValuesOrEmpty(IdentityServiceClaimTypes.GrantedToken);
|
||||||
|
public IEnumerable<string> Scopes => GetClaimValuesOrEmpty(IdentityServiceClaimTypes.Scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public abstract class Token : IEnumerable<Claim>
|
||||||
|
{
|
||||||
|
private readonly IList<Claim> _claims = new List<Claim>();
|
||||||
|
|
||||||
|
protected Token(IEnumerable<Claim> claims)
|
||||||
|
{
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.TokenUniqueId, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.IssuedAt, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.Expires, claims);
|
||||||
|
EnsureUniqueClaim(IdentityServiceClaimTypes.NotBefore, claims);
|
||||||
|
_claims = new List<Claim>(claims);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void EnsureUniqueClaim(string claimType, IEnumerable<Claim> claims, bool required = true)
|
||||||
|
{
|
||||||
|
var count = 0;
|
||||||
|
foreach (var claim in claims)
|
||||||
|
{
|
||||||
|
if (string.Equals(claimType, claim.Type, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0 && required)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"'{claimType}' is required.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"'{claimType}' must be unique.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void EnsureRequiredClaim(string claimType, IEnumerable<Claim> claims)
|
||||||
|
{
|
||||||
|
foreach (var claim in claims)
|
||||||
|
{
|
||||||
|
if (string.Equals(claimType, claim.Type, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException($"'{claimType}' not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract string Kind { get; }
|
||||||
|
public virtual string Id => GetClaimValue(IdentityServiceClaimTypes.TokenUniqueId);
|
||||||
|
public virtual DateTimeOffset IssuedAt => GetClaimValueOrNull(IdentityServiceClaimTypes.IssuedAt, v => EpochTime.DateTime(long.Parse(v)));
|
||||||
|
public virtual DateTimeOffset Expires => GetClaimValueOrNull(IdentityServiceClaimTypes.Expires, v => EpochTime.DateTime(long.Parse(v)));
|
||||||
|
public virtual DateTimeOffset NotBefore => GetClaimValueOrNull(IdentityServiceClaimTypes.NotBefore, v => EpochTime.DateTime(long.Parse(v)));
|
||||||
|
|
||||||
|
public bool IsOfKind(string tokenType) => Kind.Equals(tokenType, StringComparison.Ordinal);
|
||||||
|
|
||||||
|
public virtual string GetClaimValue(string claimType)
|
||||||
|
{
|
||||||
|
foreach (var claim in _claims)
|
||||||
|
{
|
||||||
|
if (string.Equals(claimType, claim.Type, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return claim.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual T GetClaimValueOrNull<T>(string claimType, Func<string, T> valueFactory)
|
||||||
|
{
|
||||||
|
foreach (var claim in _claims)
|
||||||
|
{
|
||||||
|
if (string.Equals(claimType, claim.Type, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return valueFactory(claim.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual IEnumerable<string> GetClaimValuesOrEmpty(string claimType)
|
||||||
|
{
|
||||||
|
foreach (var claim in _claims)
|
||||||
|
{
|
||||||
|
if (string.Equals(claimType, claim.Type, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
yield return claim.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<Claim> GetEnumerator() => _claims.GetEnumerator();
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => _claims.GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IAuthorizationRequestValidator
|
||||||
|
{
|
||||||
|
Task<AuthorizationRequest> ValidateRequestAsync(AuthorizationRequest request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IClientIdValidator
|
||||||
|
{
|
||||||
|
Task<bool> ValidateClientIdAsync(string clientId);
|
||||||
|
Task<bool> ValidateClientCredentialsAsync(string clientId, string clientSecret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IRedirectUriResolver
|
||||||
|
{
|
||||||
|
Task<RedirectUriResolutionResult> ResolveRedirectUriAsync(string clientId, string redirectUrl);
|
||||||
|
Task<RedirectUriResolutionResult> ResolveLogoutUriAsync(string clientId, string logoutUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface IScopeResolver
|
||||||
|
{
|
||||||
|
Task<ScopeResolutionResult> ResolveScopesAsync(string clientId, IEnumerable<string> scopes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface ITimeStampManager
|
||||||
|
{
|
||||||
|
DateTimeOffset GetCurrentTimeStampUtc();
|
||||||
|
DateTimeOffset GetTimeStampUtc(TimeSpan validityPeriod);
|
||||||
|
DateTime GetCurrentTimeStampUtcAsDateTime();
|
||||||
|
DateTime GetTimeStampUtcAsDateTime(TimeSpan validityPeriod);
|
||||||
|
string GetTimeStampInEpochTime(TimeSpan validityPeriod);
|
||||||
|
string GetCurrentTimeStampInEpochTime();
|
||||||
|
DateTimeOffset GetTimeStampFromEpochTime(string epochTime);
|
||||||
|
long GetDurationInSeconds(DateTimeOffset end, DateTimeOffset beginning);
|
||||||
|
bool IsValidPeriod(DateTimeOffset start, DateTimeOffset end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public interface ITokenRequestValidator
|
||||||
|
{
|
||||||
|
Task<TokenRequest> ValidateRequestAsync(TokenRequest request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class AuthorizationCodeIssuer : IAuthorizationCodeIssuer
|
||||||
|
{
|
||||||
|
private readonly ISecureDataFormat<AuthorizationCode> _dataFormat;
|
||||||
|
private readonly ITokenClaimsManager _claimsManager;
|
||||||
|
private readonly ProtocolErrorProvider _errorProvider;
|
||||||
|
|
||||||
|
public AuthorizationCodeIssuer(
|
||||||
|
ITokenClaimsManager claimsManager,
|
||||||
|
ISecureDataFormat<AuthorizationCode> dataFormat,
|
||||||
|
ProtocolErrorProvider errorProvider)
|
||||||
|
{
|
||||||
|
_claimsManager = claimsManager;
|
||||||
|
_dataFormat = dataFormat;
|
||||||
|
_errorProvider = errorProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateAuthorizationCodeAsync(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
await _claimsManager.CreateClaimsAsync(context);
|
||||||
|
var claims = context.CurrentClaims;
|
||||||
|
|
||||||
|
var code = new AuthorizationCode(claims);
|
||||||
|
|
||||||
|
var tokenResult = new TokenResult(code, _dataFormat.Protect(code));
|
||||||
|
|
||||||
|
context.AddToken(tokenResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<AuthorizationGrant> ExchangeAuthorizationCodeAsync(OpenIdConnectMessage message)
|
||||||
|
{
|
||||||
|
var code = _dataFormat.Unprotect(message.Code);
|
||||||
|
|
||||||
|
if (code == null)
|
||||||
|
{
|
||||||
|
return Task.FromResult(AuthorizationGrant.Invalid(_errorProvider.InvalidAuthorizationCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
var userId = code.UserId;
|
||||||
|
var clientId = code.ClientId;
|
||||||
|
var scopes = code.Scopes;
|
||||||
|
var resource = code.Resource;
|
||||||
|
var nonce = code.Nonce;
|
||||||
|
|
||||||
|
var tokenTypes = code.GrantedTokens;
|
||||||
|
var grantedScopes = scopes.SelectMany(s => s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
.Select(s => ApplicationScope.CanonicalScopes.TryGetValue(s, out var canonicalScope) ? canonicalScope : new ApplicationScope(resource, s))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return Task.FromResult(AuthorizationGrant.Valid(userId, clientId, tokenTypes, grantedScopes, code));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,398 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class AuthorizationRequestFactory : IAuthorizationRequestFactory
|
||||||
|
{
|
||||||
|
private static readonly string[] ValidResponseTypes = new string[] {
|
||||||
|
OpenIdConnectResponseType.None,
|
||||||
|
OpenIdConnectResponseType.Token,
|
||||||
|
OpenIdConnectResponseType.IdToken,
|
||||||
|
OpenIdConnectResponseType.Code
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly string[] ValidResponseModes = new string[] {
|
||||||
|
OpenIdConnectResponseMode.Query,
|
||||||
|
OpenIdConnectResponseMode.Fragment,
|
||||||
|
OpenIdConnectResponseMode.FormPost
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly IClientIdValidator _clientIdValidator;
|
||||||
|
private readonly IRedirectUriResolver _redirectUrlValidator;
|
||||||
|
private readonly IScopeResolver _scopeValidator;
|
||||||
|
private readonly IEnumerable<IAuthorizationRequestValidator> _validators;
|
||||||
|
private readonly ProtocolErrorProvider _errorProvider;
|
||||||
|
|
||||||
|
public AuthorizationRequestFactory(
|
||||||
|
IClientIdValidator clientIdValidator,
|
||||||
|
IRedirectUriResolver redirectUriValidator,
|
||||||
|
IScopeResolver scopeValidator,
|
||||||
|
IEnumerable<IAuthorizationRequestValidator> validators,
|
||||||
|
ProtocolErrorProvider errorProvider)
|
||||||
|
{
|
||||||
|
_clientIdValidator = clientIdValidator;
|
||||||
|
_redirectUrlValidator = redirectUriValidator;
|
||||||
|
_scopeValidator = scopeValidator;
|
||||||
|
_validators = validators;
|
||||||
|
_errorProvider = errorProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AuthorizationRequest> CreateAuthorizationRequestAsync(IDictionary<string, string[]> requestParameters)
|
||||||
|
{
|
||||||
|
// Parameters sent without a value MUST be treated as if they were
|
||||||
|
// omitted from the request.The authorization server MUST ignore
|
||||||
|
// unrecognized request parameters.Request and response parameters
|
||||||
|
// MUST NOT be included more than once.
|
||||||
|
|
||||||
|
// Validate that we only got send one state property as it needs to be included in all responses (including error ones)
|
||||||
|
var (state, stateError) = RequestParametersHelper.ValidateOptionalParameterIsUnique(requestParameters, OpenIdConnectParameterNames.State, _errorProvider);
|
||||||
|
|
||||||
|
|
||||||
|
// Start by validating the client_id and redirect_uri as any of them being invalid indicates that we need to
|
||||||
|
// return a 400 response instead of a 302 response with the error. This is signaled by the result not containing
|
||||||
|
// a url to redirect to.
|
||||||
|
var (clientId, redirectUri, clientError) = await ValidateClientIdAndRedirectUri(requestParameters, state);
|
||||||
|
if (clientError != null)
|
||||||
|
{
|
||||||
|
// Send first the state error if there was one.
|
||||||
|
return AuthorizationRequest.Invalid(new AuthorizationRequestError(
|
||||||
|
stateError ?? clientError,
|
||||||
|
redirectUri: null,
|
||||||
|
responseMode: null));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to determine what response mode to use to send the errors in case there are any.
|
||||||
|
// In case the response type and response modes are valid, we should use those values when
|
||||||
|
// notifying clients of the errors.
|
||||||
|
// In case there is an issue with the response type or the response mode we need to determine
|
||||||
|
// how to notify the relying party of the errors.
|
||||||
|
// We can divide this in two situations:
|
||||||
|
// The response mode is invalid:
|
||||||
|
// * We ignore the response mode and base our response based on the response type specified.
|
||||||
|
// If a token was requested we send the error response on the fragment of the redirect uri.
|
||||||
|
// If no token was requested we send the error response on the query of the redirect uri.
|
||||||
|
// The response type is invalid:
|
||||||
|
// * We try to determine if this is a hybrid or implicit flow:
|
||||||
|
// If the invalid response type contained a request for an id_token or an access_token, or
|
||||||
|
// contained more than one space separated value, we send the response on the fragment,
|
||||||
|
// unless the response mode is specified and form_post.
|
||||||
|
// If the invalid response type only contained one value and we can not determine is an
|
||||||
|
// implicit request flow, we return the error on the query string unless the response mode
|
||||||
|
// is specified and form_post or fragment.
|
||||||
|
|
||||||
|
var (responseType, parsedResponseType, tokenRequested, responseTypeError) = ValidateResponseType(requestParameters);
|
||||||
|
var (responseMode, responseModeError) = ValidateResponseMode(requestParameters);
|
||||||
|
|
||||||
|
var invalidCombinationError = ValidateResponseModeTypeCombination(responseType, tokenRequested, responseMode);
|
||||||
|
if (responseModeError != null || responseMode == null)
|
||||||
|
{
|
||||||
|
responseMode = GetResponseMode(parsedResponseType, tokenRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseTypeError != null)
|
||||||
|
{
|
||||||
|
responseTypeError.State = state;
|
||||||
|
return AuthorizationRequest.Invalid(
|
||||||
|
new AuthorizationRequestError(stateError ?? responseTypeError, redirectUri, responseMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseModeError != null)
|
||||||
|
{
|
||||||
|
responseModeError.State = state;
|
||||||
|
return AuthorizationRequest.Invalid(
|
||||||
|
new AuthorizationRequestError(stateError ?? responseModeError, redirectUri, responseMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalidCombinationError != null)
|
||||||
|
{
|
||||||
|
invalidCombinationError.State = state;
|
||||||
|
return AuthorizationRequest.Invalid(
|
||||||
|
new AuthorizationRequestError(stateError ?? invalidCombinationError, redirectUri, responseMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
var (nonce, nonceError) = tokenRequested ?
|
||||||
|
RequestParametersHelper.ValidateParameterIsUnique(requestParameters, OpenIdConnectParameterNames.Nonce, _errorProvider) :
|
||||||
|
RequestParametersHelper.ValidateOptionalParameterIsUnique(requestParameters, OpenIdConnectParameterNames.Nonce, _errorProvider);
|
||||||
|
|
||||||
|
if (nonceError != null)
|
||||||
|
{
|
||||||
|
nonceError.State = state;
|
||||||
|
return AuthorizationRequest.Invalid(new AuthorizationRequestError(nonceError, redirectUri, responseMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
var (scope, scopeError) = RequestParametersHelper.ValidateParameterIsUnique(requestParameters, OpenIdConnectParameterNames.Scope, _errorProvider);
|
||||||
|
if (scopeError != null)
|
||||||
|
{
|
||||||
|
scopeError.State = state;
|
||||||
|
return AuthorizationRequest.Invalid(new AuthorizationRequestError(scopeError, redirectUri, responseMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
var parsedScope = scope.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
var allWhiteSpace = true;
|
||||||
|
for (int i = 0; i < parsedScope.Length; i++)
|
||||||
|
{
|
||||||
|
allWhiteSpace = string.IsNullOrWhiteSpace(parsedScope[i]);
|
||||||
|
if (!allWhiteSpace)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allWhiteSpace)
|
||||||
|
{
|
||||||
|
scopeError = _errorProvider.MissingRequiredParameter(OpenIdConnectParameterNames.Scope);
|
||||||
|
scopeError.State = state;
|
||||||
|
|
||||||
|
return AuthorizationRequest.Invalid(new AuthorizationRequestError(
|
||||||
|
scopeError,
|
||||||
|
redirectUri,
|
||||||
|
responseMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedResponseType.Contains(OpenIdConnectResponseType.IdToken) && !parsedScope.Contains(OpenIdConnectScope.OpenId))
|
||||||
|
{
|
||||||
|
scopeError = _errorProvider.MissingOpenIdScope();
|
||||||
|
scopeError.State = state;
|
||||||
|
|
||||||
|
return AuthorizationRequest.Invalid(new AuthorizationRequestError(
|
||||||
|
scopeError,
|
||||||
|
redirectUri,
|
||||||
|
responseMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
var resolvedScopes = await _scopeValidator.ResolveScopesAsync(clientId, parsedScope);
|
||||||
|
if (!resolvedScopes.IsValid)
|
||||||
|
{
|
||||||
|
resolvedScopes.Error.State = state;
|
||||||
|
return AuthorizationRequest.Invalid(new AuthorizationRequestError(resolvedScopes.Error, redirectUri, responseMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
var (prompt, promptError) = RequestParametersHelper.ValidateOptionalParameterIsUnique(requestParameters, OpenIdConnectParameterNames.Prompt, _errorProvider);
|
||||||
|
if (promptError != null)
|
||||||
|
{
|
||||||
|
promptError.State = state;
|
||||||
|
return AuthorizationRequest.Invalid(new AuthorizationRequestError(promptError, redirectUri, responseMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prompt != null)
|
||||||
|
{
|
||||||
|
var parsedPrompt = prompt.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
promptError = ValidatePrompt(parsedPrompt);
|
||||||
|
if (promptError != null)
|
||||||
|
{
|
||||||
|
promptError.State = state;
|
||||||
|
return AuthorizationRequest.Invalid(new AuthorizationRequestError(promptError, redirectUri, responseMode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = new OpenIdConnectMessage(requestParameters);
|
||||||
|
result.RequestType = OpenIdConnectRequestType.Authentication;
|
||||||
|
|
||||||
|
var requestGrants = new RequestGrants
|
||||||
|
{
|
||||||
|
Tokens = GetRequestedTokens(parsedResponseType, resolvedScopes.Scopes),
|
||||||
|
Scopes = resolvedScopes.Scopes.ToList(),
|
||||||
|
ResponseMode = responseMode,
|
||||||
|
RedirectUri = redirectUri
|
||||||
|
};
|
||||||
|
|
||||||
|
return await ValidateRequestAsync(AuthorizationRequest.Valid(result, requestGrants));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IList<string> GetRequestedTokens(IEnumerable<string> parsedResponseType, IEnumerable<ApplicationScope> scopes)
|
||||||
|
{
|
||||||
|
var tokens = new List<string>();
|
||||||
|
foreach (var response in parsedResponseType)
|
||||||
|
{
|
||||||
|
switch (response)
|
||||||
|
{
|
||||||
|
case OpenIdConnectResponseType.Code:
|
||||||
|
tokens.Add(TokenTypes.AuthorizationCode);
|
||||||
|
break;
|
||||||
|
case OpenIdConnectResponseType.Token when HasCustomScope():
|
||||||
|
tokens.Add(TokenTypes.AccessToken);
|
||||||
|
break;
|
||||||
|
case OpenIdConnectResponseType.IdToken when HasOpenIdScope():
|
||||||
|
tokens.Add(TokenTypes.IdToken);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens;
|
||||||
|
|
||||||
|
bool HasCustomScope() => scopes.Any(s => s.ClientId != null);
|
||||||
|
bool HasOpenIdScope() => scopes.Contains(ApplicationScope.OpenId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<AuthorizationRequest> ValidateRequestAsync(AuthorizationRequest authorizationRequest)
|
||||||
|
{
|
||||||
|
foreach (var validator in _validators)
|
||||||
|
{
|
||||||
|
var newRequest = await validator.ValidateRequestAsync(authorizationRequest);
|
||||||
|
if (!newRequest.IsValid)
|
||||||
|
{
|
||||||
|
return newRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return authorizationRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OpenIdConnectMessage ValidatePrompt(string[] parsedPrompt)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < parsedPrompt.Length; i++)
|
||||||
|
{
|
||||||
|
var prompt = parsedPrompt[i];
|
||||||
|
if (string.Equals(prompt, PromptValues.None, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
if (parsedPrompt.Length > 1)
|
||||||
|
{
|
||||||
|
return _errorProvider.PromptNoneMustBeTheOnlyValue(string.Join(" ", parsedPrompt));
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(prompt, PromptValues.Login, StringComparison.Ordinal) ||
|
||||||
|
string.Equals(prompt, PromptValues.Consent, StringComparison.Ordinal) ||
|
||||||
|
string.Equals(prompt, PromptValues.SelectAccount, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _errorProvider.InvalidPromptValue(prompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetResponseMode(string[] parsedResponseType, bool tokenRequested)
|
||||||
|
{
|
||||||
|
return tokenRequested || parsedResponseType != null && parsedResponseType.Length > 1
|
||||||
|
? OpenIdConnectResponseMode.Fragment : OpenIdConnectResponseMode.Query;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OpenIdConnectMessage ValidateResponseModeTypeCombination(string responseType, bool tokenRequested, string responseMode)
|
||||||
|
{
|
||||||
|
return tokenRequested && responseMode != null && responseMode.Equals(OpenIdConnectResponseMode.Query) ?
|
||||||
|
_errorProvider.InvalidResponseTypeModeCombination(responseType, responseMode) :
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private (string responseMode, OpenIdConnectMessage responseModeError) ValidateResponseMode(IDictionary<string, string[]> parameters)
|
||||||
|
{
|
||||||
|
var (responseMode, responseModeParameterError) = RequestParametersHelper.ValidateOptionalParameterIsUnique(parameters, OpenIdConnectParameterNames.ResponseMode, _errorProvider);
|
||||||
|
var responseModeValidationError = responseMode != null && !ValidResponseModes.Contains(responseMode) ?
|
||||||
|
_errorProvider.InvalidParameterValue(responseMode, OpenIdConnectParameterNames.ResponseMode) :
|
||||||
|
null;
|
||||||
|
var isResponseModeInvalid = responseModeParameterError != null || responseModeValidationError != null;
|
||||||
|
|
||||||
|
return (isResponseModeInvalid ? null : responseMode, responseModeParameterError ?? responseModeValidationError);
|
||||||
|
}
|
||||||
|
|
||||||
|
private (string responseType, string[] parsedResponseType, bool tokenRequested, OpenIdConnectMessage error) ValidateResponseType(IDictionary<string, string[]> parameters)
|
||||||
|
{
|
||||||
|
var (responseType, responseTypeParameterError) = RequestParametersHelper.ValidateParameterIsUnique(parameters, OpenIdConnectParameterNames.ResponseType, _errorProvider);
|
||||||
|
var parsedResponseType = responseType?.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
var (tokenRequested, responseTypeValidationError) = parsedResponseType != null ? IsValidResponseTypeCombination(parsedResponseType) : (false, null);
|
||||||
|
|
||||||
|
return (responseType, parsedResponseType, tokenRequested, responseTypeParameterError ?? responseTypeValidationError);
|
||||||
|
}
|
||||||
|
|
||||||
|
private (bool tokenRequested, OpenIdConnectMessage error) IsValidResponseTypeCombination(string[] parsedResponseType)
|
||||||
|
{
|
||||||
|
var containsNone = false;
|
||||||
|
var tokenRequested = false;
|
||||||
|
for (var i = 0; i < parsedResponseType.Length; i++)
|
||||||
|
{
|
||||||
|
containsNone = containsNone || string.Equals(OpenIdConnectResponseType.None, parsedResponseType[i], StringComparison.Ordinal);
|
||||||
|
|
||||||
|
tokenRequested = tokenRequested ||
|
||||||
|
string.Equals(OpenIdConnectResponseType.Token, parsedResponseType[i], StringComparison.Ordinal) ||
|
||||||
|
string.Equals(OpenIdConnectResponseType.IdToken, parsedResponseType[i], StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (containsNone && parsedResponseType.Length > 1)
|
||||||
|
{
|
||||||
|
return (tokenRequested, _errorProvider.ResponseTypeNoneNotAllowed());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < parsedResponseType.Length; i++)
|
||||||
|
{
|
||||||
|
if (!ValidResponseTypes.Contains(parsedResponseType[i]))
|
||||||
|
{
|
||||||
|
var error = _errorProvider.InvalidParameterValue(
|
||||||
|
parsedResponseType[i],
|
||||||
|
OpenIdConnectParameterNames.ResponseType);
|
||||||
|
return (tokenRequested, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (tokenRequested, null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<(string clientId, string redirectUri, OpenIdConnectMessage error)> ValidateClientIdAndRedirectUri(
|
||||||
|
IDictionary<string, string[]> requestParameters, string state)
|
||||||
|
{
|
||||||
|
var (clientId, clientIdError) = RequestParametersHelper.ValidateParameterIsUnique(requestParameters, OpenIdConnectParameterNames.ClientId, _errorProvider);
|
||||||
|
if (clientIdError != null)
|
||||||
|
{
|
||||||
|
clientIdError.State = state;
|
||||||
|
return (null, null, clientIdError);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await _clientIdValidator.ValidateClientIdAsync(clientId))
|
||||||
|
{
|
||||||
|
clientIdError = _errorProvider.InvalidClientId(clientId);
|
||||||
|
clientIdError.State = state;
|
||||||
|
|
||||||
|
return (null, null, clientIdError);
|
||||||
|
}
|
||||||
|
|
||||||
|
var (redirectUri, redirectUriError) = RequestParametersHelper.ValidateOptionalParameterIsUnique(requestParameters, OpenIdConnectParameterNames.RedirectUri, _errorProvider);
|
||||||
|
if (redirectUriError != null)
|
||||||
|
{
|
||||||
|
redirectUriError.State = state;
|
||||||
|
return (null, null, redirectUriError);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (redirectUri != null)
|
||||||
|
{
|
||||||
|
if (!Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute))
|
||||||
|
{
|
||||||
|
redirectUriError = _errorProvider.InvalidUriFormat(redirectUri);
|
||||||
|
redirectUriError.State = state;
|
||||||
|
return (null, null, redirectUriError);
|
||||||
|
}
|
||||||
|
|
||||||
|
var parsedUri = new Uri(redirectUri, UriKind.Absolute);
|
||||||
|
if (!string.IsNullOrEmpty(parsedUri.Fragment))
|
||||||
|
{
|
||||||
|
redirectUriError = _errorProvider.InvalidUriFormat(redirectUri);
|
||||||
|
redirectUriError.State = state;
|
||||||
|
return (null, null, redirectUriError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var resolvedUriResult = await _redirectUrlValidator.ResolveRedirectUriAsync(clientId, redirectUri);
|
||||||
|
if (!resolvedUriResult.IsValid)
|
||||||
|
{
|
||||||
|
resolvedUriResult.Error.State = state;
|
||||||
|
return (null, null, resolvedUriResult.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (clientId, resolvedUriResult.Uri, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Identity.Service.Claims;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class DefaultTokenClaimsManager : ITokenClaimsManager
|
||||||
|
{
|
||||||
|
private readonly ITokenClaimsProvider[] _providers;
|
||||||
|
|
||||||
|
public DefaultTokenClaimsManager(IEnumerable<ITokenClaimsProvider> providers)
|
||||||
|
{
|
||||||
|
_providers = providers.OrderBy(p => p.Order).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateClaimsAsync(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
foreach (var provider in _providers)
|
||||||
|
{
|
||||||
|
await provider.OnGeneratingClaims(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,145 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service.Claims
|
||||||
|
{
|
||||||
|
public class DefaultTokenClaimsProvider : ITokenClaimsProvider
|
||||||
|
{
|
||||||
|
private readonly IOptions<IdentityServiceOptions> _options;
|
||||||
|
|
||||||
|
public DefaultTokenClaimsProvider(IOptions<IdentityServiceOptions> options)
|
||||||
|
{
|
||||||
|
_options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Order => 100;
|
||||||
|
|
||||||
|
public Task OnGeneratingClaims(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.TokenUniqueId, Guid.NewGuid().ToString());
|
||||||
|
|
||||||
|
var userMapping = GetUserPrincipalTokenMapping(context.CurrentToken);
|
||||||
|
var applicationMapping = GetApplicationPrincipalTokenMapping(context.CurrentToken);
|
||||||
|
var ambientMapping = GetAmbientClaimsTokenMapping(context.CurrentToken);
|
||||||
|
|
||||||
|
MapFromPrincipal(context, context.User, userMapping);
|
||||||
|
MapFromPrincipal(context, context.Application, applicationMapping);
|
||||||
|
MapFromContext(context, context.AmbientClaims, ambientMapping);
|
||||||
|
|
||||||
|
if (context.IsContextForTokenTypes(TokenTypes.AccessToken, TokenTypes.IdToken))
|
||||||
|
{
|
||||||
|
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.Issuer, _options.Value.Issuer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.IsContextForTokenTypes(TokenTypes.AuthorizationCode) && context.RequestParameters.RedirectUri != null)
|
||||||
|
{
|
||||||
|
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.RedirectUri, context.RequestParameters.RedirectUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TokenMapping GetAmbientClaimsTokenMapping(string tokenType)
|
||||||
|
{
|
||||||
|
switch (tokenType)
|
||||||
|
{
|
||||||
|
case TokenTypes.AuthorizationCode:
|
||||||
|
return _options.Value.AuthorizationCodeOptions.ContextClaims;
|
||||||
|
case TokenTypes.AccessToken:
|
||||||
|
return _options.Value.AccessTokenOptions.ContextClaims;
|
||||||
|
case TokenTypes.IdToken:
|
||||||
|
return _options.Value.IdTokenOptions.ContextClaims;
|
||||||
|
case TokenTypes.RefreshToken:
|
||||||
|
return _options.Value.RefreshTokenOptions.ContextClaims;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TokenMapping GetApplicationPrincipalTokenMapping(string tokenType)
|
||||||
|
{
|
||||||
|
switch (tokenType)
|
||||||
|
{
|
||||||
|
case TokenTypes.AuthorizationCode:
|
||||||
|
return _options.Value.AuthorizationCodeOptions.ApplicationClaims;
|
||||||
|
case TokenTypes.AccessToken:
|
||||||
|
return _options.Value.AccessTokenOptions.ApplicationClaims;
|
||||||
|
case TokenTypes.IdToken:
|
||||||
|
return _options.Value.IdTokenOptions.ApplicationClaims;
|
||||||
|
case TokenTypes.RefreshToken:
|
||||||
|
return _options.Value.RefreshTokenOptions.ApplicationClaims;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TokenMapping GetUserPrincipalTokenMapping(string tokenType)
|
||||||
|
{
|
||||||
|
switch (tokenType)
|
||||||
|
{
|
||||||
|
case TokenTypes.AuthorizationCode:
|
||||||
|
return _options.Value.AuthorizationCodeOptions.UserClaims;
|
||||||
|
case TokenTypes.AccessToken:
|
||||||
|
return _options.Value.AccessTokenOptions.UserClaims;
|
||||||
|
case TokenTypes.IdToken:
|
||||||
|
return _options.Value.IdTokenOptions.UserClaims;
|
||||||
|
case TokenTypes.RefreshToken:
|
||||||
|
return _options.Value.RefreshTokenOptions.UserClaims;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MapFromPrincipal(
|
||||||
|
TokenGeneratingContext context,
|
||||||
|
ClaimsPrincipal user,
|
||||||
|
TokenMapping claimsDefinition)
|
||||||
|
{
|
||||||
|
foreach (var mapping in claimsDefinition)
|
||||||
|
{
|
||||||
|
var foundClaims = user.FindAll(mapping.Alias);
|
||||||
|
ValidateCardinality(mapping, foundClaims, claimsDefinition.Source);
|
||||||
|
foreach (var userClaim in foundClaims)
|
||||||
|
{
|
||||||
|
context.AddClaimToCurrentToken(mapping.Name, userClaim.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MapFromContext(
|
||||||
|
TokenGeneratingContext context,
|
||||||
|
IList<Claim> ambientClaims,
|
||||||
|
TokenMapping claimsDefinition)
|
||||||
|
{
|
||||||
|
foreach (var mapping in claimsDefinition)
|
||||||
|
{
|
||||||
|
var ctxValues = ambientClaims.Where(c => c.Type == mapping.Alias);
|
||||||
|
ValidateCardinality(mapping, ctxValues, claimsDefinition.Source);
|
||||||
|
foreach (var ctxValue in ctxValues)
|
||||||
|
{
|
||||||
|
context.AddClaimToCurrentToken(mapping.Name, ctxValue.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ValidateCardinality<T>(TokenValueDescriptor mapping, IEnumerable<T> foundClaims, string source)
|
||||||
|
{
|
||||||
|
if (mapping.Cardinality != TokenValueCardinality.Zero && !foundClaims.Any())
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Missing '{mapping.Alias}' claim from the {source}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapping.Cardinality != TokenValueCardinality.Many && foundClaims.Skip(1).Any())
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Multiple claims found for '{mapping.Alias}' claim from the {source}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service.Claims
|
||||||
|
{
|
||||||
|
public class GrantedTokensTokenClaimsProvider : ITokenClaimsProvider
|
||||||
|
{
|
||||||
|
public int Order => 100;
|
||||||
|
|
||||||
|
public Task OnGeneratingClaims(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
if (context.IsContextForTokenTypes(TokenTypes.AuthorizationCode))
|
||||||
|
{
|
||||||
|
foreach (var grantedToken in GetGrantedTokensForAuthorizationCode(context))
|
||||||
|
{
|
||||||
|
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.GrantedToken, grantedToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.IsContextForTokenTypes(TokenTypes.RefreshToken))
|
||||||
|
{
|
||||||
|
foreach (var grantedToken in context.RequestGrants.Tokens)
|
||||||
|
{
|
||||||
|
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.GrantedToken, grantedToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<string> GetGrantedTokensForAuthorizationCode(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
if (context.RequestGrants.Scopes.Any(s => s.ClientId != null))
|
||||||
|
{
|
||||||
|
yield return TokenTypes.AccessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.RequestGrants.Scopes.Contains(ApplicationScope.OpenId))
|
||||||
|
{
|
||||||
|
yield return TokenTypes.IdToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.RequestGrants.Scopes.Contains(ApplicationScope.OfflineAccess))
|
||||||
|
{
|
||||||
|
yield return TokenTypes.RefreshToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service.Claims
|
||||||
|
{
|
||||||
|
public class NonceTokenClaimsProvider : ITokenClaimsProvider
|
||||||
|
{
|
||||||
|
public int Order => 100;
|
||||||
|
|
||||||
|
public Task OnGeneratingClaims(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
var nonce = GetNonce(context);
|
||||||
|
if (context.IsContextForTokenTypes(
|
||||||
|
TokenTypes.IdToken,
|
||||||
|
TokenTypes.AccessToken,
|
||||||
|
TokenTypes.AuthorizationCode) && nonce != null)
|
||||||
|
{
|
||||||
|
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.Nonce, nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetNonce(TokenGeneratingContext context) =>
|
||||||
|
context.RequestParameters.RequestType == OpenIdConnectRequestType.Authentication ?
|
||||||
|
context.RequestParameters.Nonce :
|
||||||
|
context.RequestGrants.Claims.SingleOrDefault(c => c.Type.Equals(IdentityServiceClaimTypes.Nonce))?.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service.Claims
|
||||||
|
{
|
||||||
|
public class ScopesTokenClaimsProvider : ITokenClaimsProvider
|
||||||
|
{
|
||||||
|
public int Order => 100;
|
||||||
|
|
||||||
|
public Task OnGeneratingClaims(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
var resource = context.RequestGrants.Scopes.FirstOrDefault(rg => rg.ClientId != null)?.ClientId;
|
||||||
|
|
||||||
|
if (context.IsContextForTokenTypes(TokenTypes.AccessToken) && resource != null)
|
||||||
|
{
|
||||||
|
// For access tokens we use the scopes from the set of granted scopes, this takes into account the
|
||||||
|
// fact that a token request can ask for a subset of the scopes granted during authorization, either
|
||||||
|
// on a code exchange or on a refresh token grant flow.
|
||||||
|
AddClaimsForAccessToken(context, resource);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.IsContextForTokenTypes(TokenTypes.AuthorizationCode))
|
||||||
|
{
|
||||||
|
context.AddClaimToCurrentToken(
|
||||||
|
IdentityServiceClaimTypes.Scope,
|
||||||
|
GetScopeValue(context.RequestGrants.Scopes, excludeCanonical: false));
|
||||||
|
|
||||||
|
if (resource != null)
|
||||||
|
{
|
||||||
|
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.Resource, resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (context.IsContextForTokenTypes(TokenTypes.RefreshToken))
|
||||||
|
{
|
||||||
|
// For refresh tokens the scope claim never changes as the set of scopes granted for a refresh token
|
||||||
|
// should not change no matter what scopes are sent on a token request.
|
||||||
|
var scopeClaim = context
|
||||||
|
.RequestGrants
|
||||||
|
.Claims
|
||||||
|
.Single(c => c.Type.Equals(IdentityServiceClaimTypes.Scope, StringComparison.Ordinal));
|
||||||
|
|
||||||
|
var resourceClaim = context
|
||||||
|
.RequestGrants
|
||||||
|
.Claims
|
||||||
|
.SingleOrDefault(c => c.Type.Equals(IdentityServiceClaimTypes.Resource, StringComparison.Ordinal));
|
||||||
|
|
||||||
|
context.AddClaimToCurrentToken(scopeClaim);
|
||||||
|
|
||||||
|
if (resourceClaim != null)
|
||||||
|
{
|
||||||
|
context.AddClaimToCurrentToken(resourceClaim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddClaimsForAccessToken(TokenGeneratingContext context, string resource)
|
||||||
|
{
|
||||||
|
var scopes = context.RequestGrants.Scopes;
|
||||||
|
var accessTokenScopes = GetAccessTokenScopes(scopes);
|
||||||
|
|
||||||
|
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.Scope, GetScopeValue(scopes, excludeCanonical: true));
|
||||||
|
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.Audience, resource);
|
||||||
|
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.AuthorizedParty, context.RequestParameters.ClientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<ApplicationScope> GetAccessTokenScopes(IEnumerable<ApplicationScope> applicationScopes) =>
|
||||||
|
applicationScopes.Where(s => s.ClientId != null);
|
||||||
|
|
||||||
|
private string GetScopeValue(IEnumerable<ApplicationScope> scopes, bool excludeCanonical) =>
|
||||||
|
!excludeCanonical ?
|
||||||
|
string.Join(" ", scopes.Select(s => s.Scope)) :
|
||||||
|
string.Join(" ", scopes.Where(s => s.ClientId != null).Select(s => s.Scope));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service.Claims
|
||||||
|
{
|
||||||
|
public class TimestampsTokenClaimsProvider : ITokenClaimsProvider
|
||||||
|
{
|
||||||
|
private readonly ITimeStampManager _timeStampManager;
|
||||||
|
private readonly IOptions<IdentityServiceOptions> _options;
|
||||||
|
|
||||||
|
public TimestampsTokenClaimsProvider(
|
||||||
|
ITimeStampManager timestampManager,
|
||||||
|
IOptions<IdentityServiceOptions> options)
|
||||||
|
{
|
||||||
|
_timeStampManager = timestampManager;
|
||||||
|
_options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Order => 100;
|
||||||
|
|
||||||
|
public Task OnGeneratingClaims(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
var options = GetOptions(context.CurrentToken);
|
||||||
|
context.CurrentClaims.Add(new Claim(
|
||||||
|
IdentityServiceClaimTypes.NotBefore,
|
||||||
|
_timeStampManager.GetTimeStampInEpochTime(options.NotValidBefore)));
|
||||||
|
|
||||||
|
context.CurrentClaims.Add(new Claim(
|
||||||
|
IdentityServiceClaimTypes.IssuedAt,
|
||||||
|
_timeStampManager.GetCurrentTimeStampInEpochTime()));
|
||||||
|
|
||||||
|
context.CurrentClaims.Add(new Claim(
|
||||||
|
IdentityServiceClaimTypes.Expires,
|
||||||
|
_timeStampManager.GetTimeStampInEpochTime(options.NotValidAfter)));
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TokenOptions GetOptions(string tokenType)
|
||||||
|
{
|
||||||
|
switch (tokenType)
|
||||||
|
{
|
||||||
|
case TokenTypes.AccessToken:
|
||||||
|
return _options.Value.AccessTokenOptions;
|
||||||
|
case TokenTypes.AuthorizationCode:
|
||||||
|
return _options.Value.AuthorizationCodeOptions;
|
||||||
|
case TokenTypes.IdToken:
|
||||||
|
return _options.Value.IdTokenOptions;
|
||||||
|
case TokenTypes.RefreshToken:
|
||||||
|
return _options.Value.RefreshTokenOptions;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task OnValidatingClaims(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service.Claims
|
||||||
|
{
|
||||||
|
public class TokenHashTokenClaimsProvider : ITokenClaimsProvider
|
||||||
|
{
|
||||||
|
private readonly ITokenHasher _tokenHasher;
|
||||||
|
|
||||||
|
public TokenHashTokenClaimsProvider(ITokenHasher tokenHasher)
|
||||||
|
{
|
||||||
|
_tokenHasher = tokenHasher;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Order => 100;
|
||||||
|
|
||||||
|
public Task OnGeneratingClaims(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
if (context.IsContextForTokenTypes(TokenTypes.IdToken))
|
||||||
|
{
|
||||||
|
var accessToken = context
|
||||||
|
.IssuedTokens.SingleOrDefault(t => t.Token.Kind == TokenTypes.AccessToken);
|
||||||
|
var authorizationCode = context
|
||||||
|
.IssuedTokens.SingleOrDefault(t => t.Token.Kind == TokenTypes.AuthorizationCode);
|
||||||
|
|
||||||
|
if (accessToken != null)
|
||||||
|
{
|
||||||
|
context.CurrentClaims.Add(new Claim(
|
||||||
|
IdentityServiceClaimTypes.AccessTokenHash,
|
||||||
|
GetTokenHash(accessToken.SerializedValue)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authorizationCode != null)
|
||||||
|
{
|
||||||
|
context.CurrentClaims.Add(new Claim(
|
||||||
|
IdentityServiceClaimTypes.CodeHash,
|
||||||
|
GetTokenHash(authorizationCode.SerializedValue)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetTokenHash(string token)
|
||||||
|
{
|
||||||
|
return _tokenHasher.HashToken(token, "RS256");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
internal static class CryptographyHelpers
|
||||||
|
{
|
||||||
|
public static string FindAlgorithm(X509Certificate2 certificate)
|
||||||
|
{
|
||||||
|
var rsapk = certificate.GetRSAPublicKey();
|
||||||
|
if (rsapk != null)
|
||||||
|
{
|
||||||
|
return "RS256";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Algorithm not supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ValidateRsaKeyLength(X509Certificate2 certificate)
|
||||||
|
{
|
||||||
|
var rsa = certificate.GetRSAPublicKey();
|
||||||
|
if (rsa == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Algorithm not supported.");
|
||||||
|
}
|
||||||
|
ValidateRsaKeyLength(rsa);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ValidateRsaKeyLength(RSA rsa)
|
||||||
|
{
|
||||||
|
if (rsa.KeySize < 2048)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("The RSA key must be at least 2048 bits long.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RSA CreateRsaAlgorithm() => RSA.Create(2048);
|
||||||
|
|
||||||
|
public static SHA256 CreateSHA256() => SHA256.Create();
|
||||||
|
|
||||||
|
public static RSAParameters GetRSAParameters(SigningCredentials credentials)
|
||||||
|
{
|
||||||
|
RSA algorithm = null;
|
||||||
|
if (credentials.Key is X509SecurityKey x509SecurityKey)
|
||||||
|
{
|
||||||
|
algorithm = x509SecurityKey.PublicKey as RSA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (credentials.Key is RsaSecurityKey rsaSecurityKey)
|
||||||
|
{
|
||||||
|
algorithm = rsaSecurityKey.Rsa;
|
||||||
|
|
||||||
|
if (algorithm == null)
|
||||||
|
{
|
||||||
|
var rsa = RSA.Create();
|
||||||
|
rsa.ImportParameters(rsaSecurityKey.Parameters);
|
||||||
|
algorithm = rsa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var parameters = algorithm.ExportParameters(includePrivateParameters: false);
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetAlgorithm(SigningCredentials credentials)
|
||||||
|
{
|
||||||
|
RSA algorithm = null;
|
||||||
|
if (credentials.Key is X509SecurityKey x509SecurityKey && x509SecurityKey.PublicKey is RSA)
|
||||||
|
{
|
||||||
|
return JsonWebAlgorithmsKeyTypes.RSA;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rsaSecurityKey = credentials.Key as RsaSecurityKey;
|
||||||
|
// Check that the key has either an Asymetric Algorithm assigned or that at least
|
||||||
|
// one of the RSA parameters are initialized to consider the key "valid".
|
||||||
|
if (rsaSecurityKey != null &&
|
||||||
|
(rsaSecurityKey.Rsa != null || rsaSecurityKey.Parameters.Modulus != null))
|
||||||
|
{
|
||||||
|
return JsonWebAlgorithmsKeyTypes.RSA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (algorithm != null)
|
||||||
|
{
|
||||||
|
return JsonWebAlgorithmsKeyTypes.RSA;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class DefaultAuthorizationResponseFactory : IAuthorizationResponseFactory
|
||||||
|
{
|
||||||
|
private readonly IAuthorizationResponseParameterProvider[] _providers;
|
||||||
|
|
||||||
|
public DefaultAuthorizationResponseFactory(IEnumerable<IAuthorizationResponseParameterProvider> providers)
|
||||||
|
{
|
||||||
|
_providers = providers.OrderBy(p => p.Order).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AuthorizationResponse> CreateAuthorizationResponseAsync(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
var result = new AuthorizationResponse();
|
||||||
|
result.Message = new OpenIdConnectMessage();
|
||||||
|
result.ResponseMode = context.RequestGrants.ResponseMode;
|
||||||
|
result.RedirectUri = context.RequestGrants.RedirectUri;
|
||||||
|
|
||||||
|
foreach (var provider in _providers)
|
||||||
|
{
|
||||||
|
await provider.AddParameters(context, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class DefaultAuthorizationResponseParameterProvider : IAuthorizationResponseParameterProvider
|
||||||
|
{
|
||||||
|
private readonly ITimeStampManager _manager;
|
||||||
|
|
||||||
|
public int Order => 100;
|
||||||
|
|
||||||
|
public DefaultAuthorizationResponseParameterProvider(ITimeStampManager manager)
|
||||||
|
{
|
||||||
|
_manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task AddParameters(TokenGeneratingContext context, AuthorizationResponse response)
|
||||||
|
{
|
||||||
|
if (context.AuthorizationCode != null)
|
||||||
|
{
|
||||||
|
response.Message.Code = context.AuthorizationCode.SerializedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.AccessToken != null)
|
||||||
|
{
|
||||||
|
response.Message.AccessToken = context.AccessToken.SerializedValue;
|
||||||
|
response.Message.TokenType = "Bearer";
|
||||||
|
response.Message.ExpiresIn = GetExpirationTime(context.AccessToken.Token);
|
||||||
|
response.Message.Scope = string.Join(" ", context.RequestGrants.Scopes.Select(s => s.Scope));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.IdToken != null)
|
||||||
|
{
|
||||||
|
response.Message.IdToken = context.IdToken.SerializedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
response.Message.State = context.RequestParameters.State;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetExpirationTime(Token token)
|
||||||
|
{
|
||||||
|
if (token.Expires < token.IssuedAt)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Can't expire before issuance.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _manager.GetDurationInSeconds(token.Expires, token.IssuedAt).ToString(CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class DefaultConfigurationManager : IConfigurationManager
|
||||||
|
{
|
||||||
|
private readonly IConfigurationMetadataProvider[] _providers;
|
||||||
|
private readonly ConcurrentDictionary<string, Lazy<Task<OpenIdConnectConfiguration>>> _configurations =
|
||||||
|
new ConcurrentDictionary<string, Lazy<Task<OpenIdConnectConfiguration>>>();
|
||||||
|
|
||||||
|
public DefaultConfigurationManager(
|
||||||
|
IEnumerable<IConfigurationMetadataProvider> providers)
|
||||||
|
{
|
||||||
|
_providers = providers.OrderBy(p => p.Order).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OpenIdConnectConfiguration> GetConfigurationAsync(ConfigurationContext context)
|
||||||
|
{
|
||||||
|
return await _configurations.GetOrAdd(
|
||||||
|
context.Id,
|
||||||
|
new Lazy<Task<OpenIdConnectConfiguration>>(CreateConfiguration)).Value;
|
||||||
|
|
||||||
|
async Task<OpenIdConnectConfiguration> CreateConfiguration()
|
||||||
|
{
|
||||||
|
var configuration = new OpenIdConnectConfiguration();
|
||||||
|
foreach (var provider in _providers)
|
||||||
|
{
|
||||||
|
await provider.ConfigureMetadataAsync(configuration, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class DefaultSigningCredentialsPolicyProvider : ISigningCredentialsPolicyProvider
|
||||||
|
{
|
||||||
|
private readonly IEnumerable<ISigningCredentialsSource> _sources;
|
||||||
|
private readonly IHostingEnvironment _environment;
|
||||||
|
private SigningCredentialsDescriptor[] _credentials;
|
||||||
|
private readonly ITimeStampManager _timeStampManager;
|
||||||
|
|
||||||
|
public DefaultSigningCredentialsPolicyProvider(
|
||||||
|
IEnumerable<ISigningCredentialsSource> sources,
|
||||||
|
ITimeStampManager timeStampManager,
|
||||||
|
IHostingEnvironment environment)
|
||||||
|
{
|
||||||
|
_sources = sources;
|
||||||
|
_timeStampManager = timeStampManager;
|
||||||
|
_environment = environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SigningCredentialsDescriptor>> GetAllCredentialsAsync()
|
||||||
|
{
|
||||||
|
if (_credentials == null || CredentialsExpired())
|
||||||
|
{
|
||||||
|
// This has the potential to spin up multiple calls to RetrieveCredentials
|
||||||
|
// we might consider an alternative pattern in which we hold a task in this
|
||||||
|
// instance and upon expired credentials we lock, make the call to retrieve
|
||||||
|
// credentials, swap the task on the instance, release the lock and then await.
|
||||||
|
_credentials = await RetrieveCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _credentials;
|
||||||
|
|
||||||
|
async Task<SigningCredentialsDescriptor[]> RetrieveCredentials()
|
||||||
|
{
|
||||||
|
var credentialsFromSources = await Task.WhenAll(_sources.Select(s => s.GetCredentials()));
|
||||||
|
|
||||||
|
var finalList = new List<SigningCredentialsDescriptor>();
|
||||||
|
foreach (var credential in credentialsFromSources.SelectMany(c => c))
|
||||||
|
{
|
||||||
|
if (!_environment.IsDevelopment() && credential.Id.StartsWith("IdentityService.Development"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
finalList.Add(credential);
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalList.OrderBy(o => o.NotBefore).ThenBy(d => d.Expires).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CredentialsExpired()
|
||||||
|
{
|
||||||
|
foreach (var credential in _credentials)
|
||||||
|
{
|
||||||
|
if (_timeStampManager.IsValidPeriod(credential.NotBefore, credential.Expires))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SigningCredentialsDescriptor> GetSigningCredentialsAsync()
|
||||||
|
{
|
||||||
|
var credentials = await GetAllCredentialsAsync();
|
||||||
|
foreach (var credential in credentials)
|
||||||
|
{
|
||||||
|
if (_timeStampManager.IsValidPeriod(credential.NotBefore, credential.Expires))
|
||||||
|
{
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException("Could not find valid credentials to use for signing.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service.Core
|
||||||
|
{
|
||||||
|
public class DefaultSigningCredentialsSource : ISigningCredentialsSource
|
||||||
|
{
|
||||||
|
private readonly IOptionsSnapshot<IdentityServiceOptions> _options;
|
||||||
|
private readonly ITimeStampManager _timeStampManager;
|
||||||
|
|
||||||
|
public DefaultSigningCredentialsSource(
|
||||||
|
IOptionsSnapshot<IdentityServiceOptions> options,
|
||||||
|
ITimeStampManager timeStampManager)
|
||||||
|
{
|
||||||
|
_options = options;
|
||||||
|
_timeStampManager = timeStampManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<SigningCredentialsDescriptor>> GetCredentials()
|
||||||
|
{
|
||||||
|
var descriptors = GetDescriptors(_options.Get(Options.DefaultName));
|
||||||
|
return Task.FromResult(descriptors);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<SigningCredentialsDescriptor> GetDescriptors(IdentityServiceOptions options)
|
||||||
|
{
|
||||||
|
return options.SigningKeys.Select(sk =>
|
||||||
|
{
|
||||||
|
var validity = GetValidity(sk);
|
||||||
|
return new SigningCredentialsDescriptor(
|
||||||
|
sk,
|
||||||
|
CryptographyHelpers.GetAlgorithm(sk),
|
||||||
|
validity.NotBefore,
|
||||||
|
validity.Expires,
|
||||||
|
GetMetadata(sk));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Validity GetValidity(SigningCredentials credentials)
|
||||||
|
{
|
||||||
|
var x509SecurityKey = credentials.Key as X509SecurityKey;
|
||||||
|
if (x509SecurityKey != null)
|
||||||
|
{
|
||||||
|
var certificate = x509SecurityKey.Certificate;
|
||||||
|
return new Validity
|
||||||
|
{
|
||||||
|
NotBefore = certificate.NotBefore.ToUniversalTime(),
|
||||||
|
Expires = certificate.NotAfter.ToUniversalTime()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var rsaSecurityKey = credentials.Key as RsaSecurityKey;
|
||||||
|
if (rsaSecurityKey != null)
|
||||||
|
{
|
||||||
|
return new Validity
|
||||||
|
{
|
||||||
|
NotBefore = _timeStampManager.GetCurrentTimeStampUtcAsDateTime(),
|
||||||
|
Expires = _timeStampManager.GetTimeStampUtcAsDateTime(TimeSpan.FromDays(1))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct Validity
|
||||||
|
{
|
||||||
|
public DateTimeOffset NotBefore;
|
||||||
|
public DateTimeOffset Expires;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IDictionary<string, string> GetMetadata(SigningCredentials credentials)
|
||||||
|
{
|
||||||
|
var rsaParameters = CryptographyHelpers.GetRSAParameters(credentials);
|
||||||
|
return new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
[JsonWebKeyParameterNames.E] = Base64UrlEncoder.Encode(rsaParameters.Exponent),
|
||||||
|
[JsonWebKeyParameterNames.N] = Base64UrlEncoder.Encode(rsaParameters.Modulus),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class DefaultTokenResponseFactory : ITokenResponseFactory
|
||||||
|
{
|
||||||
|
private readonly ITokenResponseParameterProvider[] _providers;
|
||||||
|
|
||||||
|
public DefaultTokenResponseFactory(IEnumerable<ITokenResponseParameterProvider> providers)
|
||||||
|
{
|
||||||
|
_providers = providers.OrderBy(o => o.Order).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<OpenIdConnectMessage> CreateTokenResponseAsync(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
var response = new OpenIdConnectMessage();
|
||||||
|
foreach (var provider in _providers)
|
||||||
|
{
|
||||||
|
await provider.AddParameters(context, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class DefaultTokenResponseParameterProvider : ITokenResponseParameterProvider
|
||||||
|
{
|
||||||
|
private readonly ITimeStampManager _manager;
|
||||||
|
|
||||||
|
public int Order => 100;
|
||||||
|
|
||||||
|
public DefaultTokenResponseParameterProvider(ITimeStampManager manager)
|
||||||
|
{
|
||||||
|
_manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task AddParameters(TokenGeneratingContext context, OpenIdConnectMessage response)
|
||||||
|
{
|
||||||
|
if (context.IdToken != null)
|
||||||
|
{
|
||||||
|
response.IdToken = context.IdToken.SerializedValue;
|
||||||
|
var expiresIn = _manager.GetDurationInSeconds(
|
||||||
|
context.IdToken.Token.Expires,
|
||||||
|
context.IdToken.Token.IssuedAt);
|
||||||
|
|
||||||
|
response.Parameters.Add(
|
||||||
|
"id_token_expires_in",
|
||||||
|
expiresIn.ToString(CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.AccessToken != null)
|
||||||
|
{
|
||||||
|
response.AccessToken = context.AccessToken.SerializedValue;
|
||||||
|
response.ExpiresIn = GetExpirationTime(context.AccessToken.Token);
|
||||||
|
response.Parameters["expires_on"] = context.AccessToken.Token.GetClaimValue(IdentityServiceClaimTypes.Expires);
|
||||||
|
response.Parameters["not_before"] = context.AccessToken.Token.GetClaimValue(IdentityServiceClaimTypes.NotBefore);
|
||||||
|
response.Resource = context.RequestGrants.Scopes.First(s => s.ClientId != null).ClientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.RefreshToken != null)
|
||||||
|
{
|
||||||
|
response.RefreshToken = context.RefreshToken.SerializedValue;
|
||||||
|
var expiresIn = _manager.GetDurationInSeconds(
|
||||||
|
context.RefreshToken.Token.Expires,
|
||||||
|
context.RefreshToken.Token.IssuedAt);
|
||||||
|
|
||||||
|
response.Parameters.Add(
|
||||||
|
"refresh_token_expires_in",
|
||||||
|
expiresIn.ToString(CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
|
||||||
|
response.TokenType = "Bearer";
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetExpirationTime(Token token)
|
||||||
|
{
|
||||||
|
if (token.Expires < token.IssuedAt)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Can't expire before issuance.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var expirationTimeInSeconds = Math.Truncate((token.Expires - token.IssuedAt).TotalSeconds);
|
||||||
|
checked
|
||||||
|
{
|
||||||
|
return ((long)expirationTimeInSeconds).ToString(CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class FormPostResponseGenerator
|
||||||
|
{
|
||||||
|
private const string FormPostHeaderFormat = @"<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Please wait while you're being redirected to the identity provider</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form name=""form"" method=""post"" action=""{0}"">";
|
||||||
|
|
||||||
|
private const string FormPostParameterFormat = @" <input type=""hidden"" name=""{0}"" value=""{1}"" />";
|
||||||
|
|
||||||
|
private const string FormPostFooterFormat =
|
||||||
|
@" <noscript>Click here to finish the process: <input type=""submit"" /></noscript>
|
||||||
|
</form>
|
||||||
|
<script>document.form.submit();</script>
|
||||||
|
</body>
|
||||||
|
</html>";
|
||||||
|
|
||||||
|
private readonly HtmlEncoder _encoder;
|
||||||
|
|
||||||
|
public FormPostResponseGenerator(HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
_encoder = encoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task GenerateResponseAsync(
|
||||||
|
HttpContext context,
|
||||||
|
string redirectUri,
|
||||||
|
IEnumerable<KeyValuePair<string, string>> parameters)
|
||||||
|
{
|
||||||
|
using (var stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: 1024, leaveOpen: true))
|
||||||
|
{
|
||||||
|
writer.WriteLine(FormPostHeaderFormat, redirectUri);
|
||||||
|
foreach (var parameter in parameters)
|
||||||
|
{
|
||||||
|
writer.WriteLine(FormPostParameterFormat, _encoder.Encode(parameter.Key), _encoder.Encode(parameter.Value));
|
||||||
|
}
|
||||||
|
writer.Write(FormPostFooterFormat);
|
||||||
|
};
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
context.Response.ContentType = "text/html; charset=utf-8";
|
||||||
|
context.Response.ContentLength = stream.Length;
|
||||||
|
await stream.CopyToAsync(context.Response.Body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class FragmentResponseGenerator
|
||||||
|
{
|
||||||
|
private readonly UrlEncoder _urlEncoder;
|
||||||
|
|
||||||
|
public FragmentResponseGenerator(UrlEncoder urlEncoder)
|
||||||
|
{
|
||||||
|
_urlEncoder = urlEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GenerateResponse(
|
||||||
|
HttpContext context,
|
||||||
|
string redirectUri,
|
||||||
|
IEnumerable<KeyValuePair<string, string>> parameters)
|
||||||
|
{
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder.Append(redirectUri);
|
||||||
|
builder.Append('#');
|
||||||
|
|
||||||
|
var enumerator = parameters.GetEnumerator();
|
||||||
|
while (enumerator.MoveNext())
|
||||||
|
{
|
||||||
|
if (!ShouldSkipKey(enumerator.Current.Key))
|
||||||
|
{
|
||||||
|
builder.Append(_urlEncoder.Encode(enumerator.Current.Key));
|
||||||
|
builder.Append('=');
|
||||||
|
builder.Append(_urlEncoder.Encode(enumerator.Current.Value));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (enumerator.MoveNext())
|
||||||
|
{
|
||||||
|
if (!ShouldSkipKey(enumerator.Current.Key))
|
||||||
|
{
|
||||||
|
builder.Append('&');
|
||||||
|
builder.Append(_urlEncoder.Encode(enumerator.Current.Key));
|
||||||
|
builder.Append('=');
|
||||||
|
builder.Append(_urlEncoder.Encode(enumerator.Current.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Response.Redirect(builder.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ShouldSkipKey(string key)
|
||||||
|
{
|
||||||
|
return string.Equals(key, OpenIdConnectParameterNames.RedirectUri, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public static class IdentityServiceBuilderExtensions
|
||||||
|
{
|
||||||
|
public static IIdentityServiceBuilder AddSigningCertificate(
|
||||||
|
this IIdentityServiceBuilder builder,
|
||||||
|
X509Certificate2 certificate)
|
||||||
|
{
|
||||||
|
CryptographyHelpers.ValidateRsaKeyLength(certificate);
|
||||||
|
var key = new X509SecurityKey(certificate);
|
||||||
|
builder.Services.Configure<IdentityServiceOptions>(
|
||||||
|
options =>
|
||||||
|
{
|
||||||
|
var algorithm = CryptographyHelpers.FindAlgorithm(certificate);
|
||||||
|
options.SigningKeys.Add(new SigningCredentials(key, algorithm));
|
||||||
|
});
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IIdentityServiceBuilder AddSigningCertificates(
|
||||||
|
this IIdentityServiceBuilder builder,
|
||||||
|
IEnumerable<X509Certificate2> certificates)
|
||||||
|
{
|
||||||
|
foreach (var certificate in certificates)
|
||||||
|
{
|
||||||
|
builder.AddSigningCertificate(certificate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IIdentityServiceBuilder AddSigningCertificates(
|
||||||
|
this IIdentityServiceBuilder builder,
|
||||||
|
Func<IEnumerable<X509Certificate2>> certificatesLoader)
|
||||||
|
{
|
||||||
|
builder.Services.Configure<IdentityServiceOptions>(o =>
|
||||||
|
{
|
||||||
|
var certificates = certificatesLoader();
|
||||||
|
foreach (var certificate in certificates)
|
||||||
|
{
|
||||||
|
var algorithm = CryptographyHelpers.FindAlgorithm(certificate);
|
||||||
|
o.SigningKeys.Add(new SigningCredentials(new X509SecurityKey(certificate), algorithm));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IIdentityServiceBuilder AddSigningCertificate(this IIdentityServiceBuilder builder, Func<X509Certificate2> func)
|
||||||
|
{
|
||||||
|
var cert = func();
|
||||||
|
if (cert == null)
|
||||||
|
{
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return builder.AddSigningCertificate(cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class JwtAccessTokenIssuer : IAccessTokenIssuer
|
||||||
|
{
|
||||||
|
private static readonly string[] ClaimsToFilter = new string[]
|
||||||
|
{
|
||||||
|
IdentityServiceClaimTypes.TokenUniqueId,
|
||||||
|
IdentityServiceClaimTypes.ObjectId,
|
||||||
|
IdentityServiceClaimTypes.Issuer,
|
||||||
|
IdentityServiceClaimTypes.Audience,
|
||||||
|
IdentityServiceClaimTypes.IssuedAt,
|
||||||
|
IdentityServiceClaimTypes.Expires,
|
||||||
|
IdentityServiceClaimTypes.NotBefore,
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly JwtSecurityTokenHandler _handler;
|
||||||
|
private readonly IdentityServiceOptions _options;
|
||||||
|
private readonly ITokenClaimsManager _claimsManager;
|
||||||
|
private readonly ISigningCredentialsPolicyProvider _credentialsProvider;
|
||||||
|
|
||||||
|
public JwtAccessTokenIssuer(
|
||||||
|
ITokenClaimsManager claimsManager,
|
||||||
|
ISigningCredentialsPolicyProvider credentialsProvider,
|
||||||
|
JwtSecurityTokenHandler handler,
|
||||||
|
IOptions<IdentityServiceOptions> options)
|
||||||
|
{
|
||||||
|
_claimsManager = claimsManager;
|
||||||
|
_credentialsProvider = credentialsProvider;
|
||||||
|
_handler = handler;
|
||||||
|
_options = options.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task IssueAccessTokenAsync(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
var accessToken = await CreateAccessTokenAsync(context);
|
||||||
|
var subjectIdentity = CreateSubject(accessToken);
|
||||||
|
|
||||||
|
var descriptor = new SecurityTokenDescriptor();
|
||||||
|
|
||||||
|
descriptor.Issuer = accessToken.Issuer;
|
||||||
|
descriptor.Audience = accessToken.Audience;
|
||||||
|
descriptor.Subject = subjectIdentity;
|
||||||
|
descriptor.Expires = accessToken.Expires.UtcDateTime;
|
||||||
|
descriptor.NotBefore = accessToken.NotBefore.UtcDateTime;
|
||||||
|
|
||||||
|
var credentialsDescriptor = await _credentialsProvider.GetSigningCredentialsAsync();
|
||||||
|
descriptor.SigningCredentials = credentialsDescriptor.Credentials;
|
||||||
|
|
||||||
|
var token = _handler.CreateJwtSecurityToken(descriptor);
|
||||||
|
|
||||||
|
token.Payload.Remove(IdentityServiceClaimTypes.JwtId);
|
||||||
|
token.Payload.Remove(IdentityServiceClaimTypes.IssuedAt);
|
||||||
|
//token.Payload.Add(IdentityServiceClaimTypes.JwtId, accessToken.Id);
|
||||||
|
|
||||||
|
context.AddToken(new TokenResult(accessToken, _handler.WriteToken(token), TokenKinds.Bearer));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClaimsIdentity CreateSubject(AccessToken accessToken) => new ClaimsIdentity(GetFilteredClaims(accessToken));
|
||||||
|
|
||||||
|
private IEnumerable<Claim> GetFilteredClaims(AccessToken token)
|
||||||
|
{
|
||||||
|
foreach (var claim in token)
|
||||||
|
{
|
||||||
|
if (!ClaimsToFilter.Contains(claim.Type))
|
||||||
|
{
|
||||||
|
yield return claim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<AccessToken> CreateAccessTokenAsync(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
await _claimsManager.CreateClaimsAsync(context);
|
||||||
|
|
||||||
|
var claims = context.CurrentClaims;
|
||||||
|
return new AccessToken(claims);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class JwtIdTokenIssuer : IIdTokenIssuer
|
||||||
|
{
|
||||||
|
private static readonly string[] ClaimsToFilter = new string[]
|
||||||
|
{
|
||||||
|
IdentityServiceClaimTypes.TokenUniqueId,
|
||||||
|
IdentityServiceClaimTypes.Issuer,
|
||||||
|
IdentityServiceClaimTypes.Audience,
|
||||||
|
IdentityServiceClaimTypes.IssuedAt,
|
||||||
|
IdentityServiceClaimTypes.Expires,
|
||||||
|
IdentityServiceClaimTypes.NotBefore,
|
||||||
|
IdentityServiceClaimTypes.Nonce,
|
||||||
|
IdentityServiceClaimTypes.CodeHash,
|
||||||
|
IdentityServiceClaimTypes.AccessTokenHash,
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly ITokenClaimsManager _claimsManager;
|
||||||
|
private readonly JwtSecurityTokenHandler _handler;
|
||||||
|
private readonly IdentityServiceOptions _options;
|
||||||
|
private readonly ISigningCredentialsPolicyProvider _credentialsProvider;
|
||||||
|
|
||||||
|
public JwtIdTokenIssuer(
|
||||||
|
ITokenClaimsManager claimsManager,
|
||||||
|
ISigningCredentialsPolicyProvider credentialsProvider,
|
||||||
|
JwtSecurityTokenHandler handler,
|
||||||
|
IOptions<IdentityServiceOptions> options)
|
||||||
|
{
|
||||||
|
_claimsManager = claimsManager;
|
||||||
|
_credentialsProvider = credentialsProvider;
|
||||||
|
_handler = handler;
|
||||||
|
_options = options.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task IssueIdTokenAsync(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
var idToken = await CreateIdTokenAsync(context);
|
||||||
|
var subjectIdentity = CreateSubject(idToken);
|
||||||
|
|
||||||
|
var descriptor = new SecurityTokenDescriptor();
|
||||||
|
|
||||||
|
descriptor.Issuer = idToken.Issuer;
|
||||||
|
descriptor.Audience = idToken.Audience;
|
||||||
|
descriptor.Subject = subjectIdentity;
|
||||||
|
descriptor.IssuedAt = idToken.IssuedAt.UtcDateTime;
|
||||||
|
descriptor.Expires = idToken.Expires.UtcDateTime;
|
||||||
|
descriptor.NotBefore = idToken.NotBefore.UtcDateTime;
|
||||||
|
|
||||||
|
var credentialsDescriptor = await _credentialsProvider.GetSigningCredentialsAsync();
|
||||||
|
descriptor.SigningCredentials = credentialsDescriptor.Credentials;
|
||||||
|
|
||||||
|
var token = _handler.CreateJwtSecurityToken(descriptor);
|
||||||
|
|
||||||
|
token.Payload.Remove(IdentityServiceClaimTypes.JwtId);
|
||||||
|
//token.Payload.Add(IdentityServiceClaimTypes.JwtId, idToken.Id);
|
||||||
|
|
||||||
|
if (idToken.Nonce != null)
|
||||||
|
{
|
||||||
|
token.Payload.AddClaim(new Claim(IdentityServiceClaimTypes.Nonce, idToken.Nonce));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idToken.CodeHash != null)
|
||||||
|
{
|
||||||
|
token.Payload.AddClaim(new Claim(IdentityServiceClaimTypes.CodeHash, idToken.CodeHash));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idToken.AccessTokenHash != null)
|
||||||
|
{
|
||||||
|
token.Payload.AddClaim(new Claim(IdentityServiceClaimTypes.AccessTokenHash, idToken.AccessTokenHash));
|
||||||
|
}
|
||||||
|
|
||||||
|
context.AddToken(new TokenResult(idToken, _handler.WriteToken(token)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClaimsIdentity CreateSubject(IdToken idToken) =>
|
||||||
|
new ClaimsIdentity(GetFilteredClaims(idToken));
|
||||||
|
|
||||||
|
private IEnumerable<Claim> GetFilteredClaims(IdToken token)
|
||||||
|
{
|
||||||
|
foreach (var claim in token)
|
||||||
|
{
|
||||||
|
if (!ClaimsToFilter.Contains(claim.Type))
|
||||||
|
{
|
||||||
|
yield return claim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IdToken> CreateIdTokenAsync(TokenGeneratingContext context)
|
||||||
|
{
|
||||||
|
await _claimsManager.CreateClaimsAsync(context);
|
||||||
|
|
||||||
|
var claims = context.CurrentClaims;
|
||||||
|
|
||||||
|
return new IdToken(claims);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class LogoutRequestFactory : ILogoutRequestFactory
|
||||||
|
{
|
||||||
|
private readonly IRedirectUriResolver _redirectUriValidator;
|
||||||
|
private readonly ProtocolErrorProvider _errorProvider;
|
||||||
|
|
||||||
|
public LogoutRequestFactory(
|
||||||
|
IRedirectUriResolver redirectUriValidator,
|
||||||
|
ProtocolErrorProvider errorProvider)
|
||||||
|
{
|
||||||
|
_redirectUriValidator = redirectUriValidator;
|
||||||
|
_errorProvider = errorProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<LogoutRequest> CreateLogoutRequestAsync(IDictionary<string, string[]> requestParameters)
|
||||||
|
{
|
||||||
|
var (state, stateError) = RequestParametersHelper.ValidateOptionalParameterIsUnique(requestParameters, OpenIdConnectParameterNames.State, _errorProvider);
|
||||||
|
if (stateError != null)
|
||||||
|
{
|
||||||
|
return LogoutRequest.Invalid(stateError);
|
||||||
|
}
|
||||||
|
|
||||||
|
var (logoutRedirectUri, redirectUriError) = RequestParametersHelper.ValidateOptionalParameterIsUnique(requestParameters, OpenIdConnectParameterNames.PostLogoutRedirectUri, _errorProvider);
|
||||||
|
if (redirectUriError != null)
|
||||||
|
{
|
||||||
|
return LogoutRequest.Invalid(redirectUriError);
|
||||||
|
}
|
||||||
|
|
||||||
|
var (idTokenHint,idTokenHintError) = RequestParametersHelper.ValidateOptionalParameterIsUnique(requestParameters, OpenIdConnectParameterNames.IdTokenHint, _errorProvider);
|
||||||
|
if (idTokenHintError != null)
|
||||||
|
{
|
||||||
|
return LogoutRequest.Invalid(idTokenHintError);
|
||||||
|
}
|
||||||
|
|
||||||
|
var redirectUriValidationResult = await _redirectUriValidator.ResolveLogoutUriAsync(null, logoutRedirectUri);
|
||||||
|
if (!redirectUriValidationResult.IsValid)
|
||||||
|
{
|
||||||
|
return LogoutRequest.Invalid(redirectUriValidationResult.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LogoutRequest.Valid(new OpenIdConnectMessage(requestParameters),redirectUriValidationResult.Uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service.Metadata
|
||||||
|
{
|
||||||
|
public class DefaultConfigurationMetadataProvider : IConfigurationMetadataProvider
|
||||||
|
{
|
||||||
|
private readonly IOptions<IdentityServiceOptions> _options;
|
||||||
|
|
||||||
|
public DefaultConfigurationMetadataProvider(IOptions<IdentityServiceOptions> options)
|
||||||
|
{
|
||||||
|
_options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Order { get; } = 1000;
|
||||||
|
|
||||||
|
public Task ConfigureMetadataAsync(OpenIdConnectConfiguration configuration, ConfigurationContext context)
|
||||||
|
{
|
||||||
|
configuration.Issuer = _options.Value.Issuer;
|
||||||
|
configuration.AuthorizationEndpoint = context.AuthorizationEndpoint;
|
||||||
|
configuration.TokenEndpoint = context.TokenEndpoint;
|
||||||
|
configuration.JwksUri = context.JwksUriEndpoint;
|
||||||
|
configuration.EndSessionEndpoint = context.EndSessionEndpoint;
|
||||||
|
configuration.ResponseModesSupported.Add(OpenIdConnectResponseMode.Query);
|
||||||
|
configuration.ResponseModesSupported.Add(OpenIdConnectResponseMode.Fragment);
|
||||||
|
configuration.ResponseModesSupported.Add(OpenIdConnectResponseMode.FormPost);
|
||||||
|
configuration.ResponseTypesSupported.Add(OpenIdConnectResponseType.Code);
|
||||||
|
configuration.ResponseTypesSupported.Add(OpenIdConnectResponseType.IdToken);
|
||||||
|
configuration.ResponseTypesSupported.Add(OpenIdConnectResponseType.CodeIdToken);
|
||||||
|
configuration.ScopesSupported.Add("openid");
|
||||||
|
configuration.SubjectTypesSupported.Add("pairwise");
|
||||||
|
configuration.IdTokenSigningAlgValuesSupported.Add("RS256");
|
||||||
|
configuration.TokenEndpointAuthMethodsSupported.Add("client_secret_post");
|
||||||
|
configuration.ClaimsSupported.Add("oid");
|
||||||
|
configuration.ClaimsSupported.Add("sub");
|
||||||
|
configuration.ClaimsSupported.Add("name");
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service.Metadata
|
||||||
|
{
|
||||||
|
public class DefaultKeySetMetadataProvider : IKeySetMetadataProvider
|
||||||
|
{
|
||||||
|
private readonly ISigningCredentialsPolicyProvider _provider;
|
||||||
|
|
||||||
|
public DefaultKeySetMetadataProvider(ISigningCredentialsPolicyProvider provider)
|
||||||
|
{
|
||||||
|
_provider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<JsonWebKeySet> GetKeysAsync()
|
||||||
|
{
|
||||||
|
var keySet = new JsonWebKeySet();
|
||||||
|
var credentials = await _provider.GetAllCredentialsAsync();
|
||||||
|
foreach (var key in credentials)
|
||||||
|
{
|
||||||
|
keySet.Keys.Add(CreateJsonWebKey(key));
|
||||||
|
}
|
||||||
|
return keySet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonWebKey CreateJsonWebKey(SigningCredentialsDescriptor descriptor)
|
||||||
|
{
|
||||||
|
var jsonWebKey = new JsonWebKey
|
||||||
|
{
|
||||||
|
Kid = descriptor.Id,
|
||||||
|
Use = JsonWebKeyUseNames.Sig,
|
||||||
|
Kty = descriptor.Algorithm
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!descriptor.Algorithm.Equals(JsonWebAlgorithmsKeyTypes.RSA))
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
if (!descriptor.Metadata.TryGetValue(JsonWebKeyParameterNames.E, out var exponent))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Missing '{JsonWebKeyParameterNames.E}' from metadata");
|
||||||
|
}
|
||||||
|
if (!descriptor.Metadata.TryGetValue(JsonWebKeyParameterNames.N, out var modulus))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Missing '{JsonWebKeyParameterNames.N}' from metadata");
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonWebKey.E = exponent;
|
||||||
|
jsonWebKey.N = modulus;
|
||||||
|
|
||||||
|
return jsonWebKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RSAParameters GetRSAParameters(SigningCredentials credentials)
|
||||||
|
{
|
||||||
|
RSA algorithm = null;
|
||||||
|
var x509SecurityKey = credentials.Key as X509SecurityKey;
|
||||||
|
if (x509SecurityKey != null)
|
||||||
|
{
|
||||||
|
algorithm = x509SecurityKey.PublicKey as RSA;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rsaSecurityKey = credentials.Key as RsaSecurityKey;
|
||||||
|
if (rsaSecurityKey != null)
|
||||||
|
{
|
||||||
|
algorithm = rsaSecurityKey.Rsa;
|
||||||
|
|
||||||
|
if (algorithm == null)
|
||||||
|
{
|
||||||
|
var rsa = RSA.Create();
|
||||||
|
rsa.ImportParameters(rsaSecurityKey.Parameters);
|
||||||
|
algorithm = rsa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var parameters = algorithm.ExportParameters(includePrivateParameters: false);
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<Import Project="..\..\build\common.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<Description>ASP.NET Core common types implementing the main abstractions for Identity Service.</Description>
|
||||||
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<PackageTags>aspnetcore</PackageTags>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Identity.Service.Abstractions\Microsoft.AspNetCore.Identity.Service.Abstractions.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="$(AspNetCoreVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="$(AspNetCoreVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="$(AspNetCoreVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="$(AspNetCoreVersion)" />
|
||||||
|
<PackageReference Include="System.ValueTuple" Version="$(CoreFxVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class IdentityServiceAuthorizationOptionsSetup : IConfigureOptions<AuthorizationOptions>
|
||||||
|
{
|
||||||
|
private readonly IOptions<IdentityServiceOptions> _identityServiceOptions;
|
||||||
|
|
||||||
|
public IdentityServiceAuthorizationOptionsSetup(IOptions<IdentityServiceOptions> identityServiceOptions)
|
||||||
|
{
|
||||||
|
_identityServiceOptions = identityServiceOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(AuthorizationOptions options)
|
||||||
|
{
|
||||||
|
options.AddPolicy(IdentityServiceOptions.LoginPolicyName, _identityServiceOptions.Value.LoginPolicy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class IdentityServiceOptions
|
||||||
|
{
|
||||||
|
public const string LoginPolicyName = "Microsoft.AspNetCore.Identity.Service.Login";
|
||||||
|
public const string SessionPolicyName = "Microsoft.AspNetCore.Identity.Service.Session";
|
||||||
|
public const string CookieAuthenticationScheme = "Microsoft.AspNetCore.Identity.Service.Session.Cookies";
|
||||||
|
public const string AuthenticationCookieName = "Microsoft.AspNetCore.Identity.Service";
|
||||||
|
|
||||||
|
public string Issuer { get; set; }
|
||||||
|
|
||||||
|
public AuthorizationPolicy LoginPolicy { get; set; }
|
||||||
|
public AuthorizationPolicy SessionPolicy { get; set; }
|
||||||
|
|
||||||
|
public IList<SigningCredentials> SigningKeys { get; set; } = new List<SigningCredentials>();
|
||||||
|
|
||||||
|
public TokenOptions AuthorizationCodeOptions { get; set; } = new TokenOptions();
|
||||||
|
|
||||||
|
public TokenOptions AccessTokenOptions { get; set; } = new TokenOptions();
|
||||||
|
|
||||||
|
public TokenOptions RefreshTokenOptions { get; set; } = new TokenOptions();
|
||||||
|
|
||||||
|
public TokenOptions IdTokenOptions { get; set; } = new TokenOptions();
|
||||||
|
|
||||||
|
public JsonSerializerSettings SerializationSettings { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity.Service.Serialization;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class IdentityServiceOptionsDefaultSetup : IConfigureOptions<IdentityServiceOptions>
|
||||||
|
{
|
||||||
|
public void Configure(IdentityServiceOptions options)
|
||||||
|
{
|
||||||
|
options.LoginPolicy = new AuthorizationPolicyBuilder()
|
||||||
|
.RequireAuthenticatedUser()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
options.SessionPolicy = new AuthorizationPolicyBuilder()
|
||||||
|
.AddAuthenticationSchemes(IdentityServiceOptions.CookieAuthenticationScheme)
|
||||||
|
.RequireAuthenticatedUser()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
options.SerializationSettings = CreateDefault();
|
||||||
|
options.SerializationSettings.Converters.Insert(0, new AuthorizationCodeConverter());
|
||||||
|
options.SerializationSettings.Converters.Insert(0, new RefreshTokenConverter());
|
||||||
|
options.AuthorizationCodeOptions = CreateAuthorizationCodeOptions(TimeSpan.FromMinutes(5), TimeSpan.Zero);
|
||||||
|
|
||||||
|
options.AccessTokenOptions = CreateAccessTokenOptions(TimeSpan.FromHours(2), TimeSpan.Zero);
|
||||||
|
options.RefreshTokenOptions = CreateRefreshTokenOptions(TimeSpan.FromDays(30), TimeSpan.Zero);
|
||||||
|
options.IdTokenOptions = CreateIdTokenOptions(TimeSpan.FromHours(2), TimeSpan.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TokenOptions CreateAuthorizationCodeOptions(TimeSpan notValidAfter, TimeSpan notValidBefore)
|
||||||
|
{
|
||||||
|
var userClaims = new TokenMapping("user");
|
||||||
|
userClaims.AddSingle(IdentityServiceClaimTypes.UserId, ClaimTypes.NameIdentifier);
|
||||||
|
|
||||||
|
var applicationClaims = new TokenMapping("application");
|
||||||
|
applicationClaims.AddSingle(IdentityServiceClaimTypes.ClientId);
|
||||||
|
|
||||||
|
return new TokenOptions()
|
||||||
|
{
|
||||||
|
UserClaims = userClaims,
|
||||||
|
ApplicationClaims = applicationClaims,
|
||||||
|
NotValidAfter = notValidAfter,
|
||||||
|
NotValidBefore = notValidBefore
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TokenOptions CreateAccessTokenOptions(TimeSpan notValidAfter, TimeSpan notValidBefore)
|
||||||
|
{
|
||||||
|
var userClaims = new TokenMapping("user");
|
||||||
|
userClaims.AddSingle(IdentityServiceClaimTypes.Subject, ClaimTypes.NameIdentifier);
|
||||||
|
|
||||||
|
var applicationClaims = new TokenMapping("application");
|
||||||
|
|
||||||
|
return new TokenOptions()
|
||||||
|
{
|
||||||
|
UserClaims = userClaims,
|
||||||
|
ApplicationClaims = applicationClaims,
|
||||||
|
NotValidAfter = notValidAfter,
|
||||||
|
NotValidBefore = notValidBefore
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TokenOptions CreateRefreshTokenOptions(TimeSpan notValidAfter, TimeSpan notValidBefore)
|
||||||
|
{
|
||||||
|
var userClaims = new TokenMapping("user");
|
||||||
|
userClaims.AddSingle(IdentityServiceClaimTypes.UserId, ClaimTypes.NameIdentifier);
|
||||||
|
|
||||||
|
var applicationClaims = new TokenMapping("application");
|
||||||
|
applicationClaims.AddSingle(IdentityServiceClaimTypes.ClientId, IdentityServiceClaimTypes.ClientId);
|
||||||
|
|
||||||
|
return new TokenOptions()
|
||||||
|
{
|
||||||
|
UserClaims = userClaims,
|
||||||
|
ApplicationClaims = applicationClaims,
|
||||||
|
NotValidAfter = notValidAfter,
|
||||||
|
NotValidBefore = notValidBefore
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TokenOptions CreateIdTokenOptions(TimeSpan notValidAfter, TimeSpan notValidBefore)
|
||||||
|
{
|
||||||
|
var userClaims = new TokenMapping("user");
|
||||||
|
|
||||||
|
var applicationClaims = new TokenMapping("application");
|
||||||
|
applicationClaims.AddSingle(IdentityServiceClaimTypes.Audience, IdentityServiceClaimTypes.ClientId);
|
||||||
|
|
||||||
|
return new TokenOptions()
|
||||||
|
{
|
||||||
|
UserClaims = userClaims,
|
||||||
|
ApplicationClaims = applicationClaims,
|
||||||
|
NotValidAfter = notValidAfter,
|
||||||
|
NotValidBefore = notValidBefore
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JsonSerializerSettings CreateDefault() =>
|
||||||
|
new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
MissingMemberHandling = MissingMemberHandling.Ignore,
|
||||||
|
NullValueHandling = NullValueHandling.Ignore,
|
||||||
|
|
||||||
|
// Limit the object graph we'll consume to a fixed depth. This prevents stackoverflow exceptions
|
||||||
|
// from deserialization errors that might occur from deeply nested objects.
|
||||||
|
MaxDepth = 32,
|
||||||
|
|
||||||
|
// Do not change this setting
|
||||||
|
// Setting this to None prevents Json.NET from loading malicious, unsafe, or security-sensitive types
|
||||||
|
TypeNameHandling = TypeNameHandling.None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class TokenMapping : Collection<TokenValueDescriptor>
|
||||||
|
{
|
||||||
|
public TokenMapping(string source)
|
||||||
|
{
|
||||||
|
Source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Source { get; }
|
||||||
|
|
||||||
|
public void AddSingle(string claimType, string contextKey)
|
||||||
|
{
|
||||||
|
Add(new TokenValueDescriptor(claimType, contextKey, TokenValueCardinality.One));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddSingle(string name)
|
||||||
|
{
|
||||||
|
Add(new TokenValueDescriptor(name, TokenValueCardinality.One));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class TokenOptions
|
||||||
|
{
|
||||||
|
public TokenMapping UserClaims { get; set; } = new TokenMapping("user");
|
||||||
|
public TokenMapping ApplicationClaims { get; set; } = new TokenMapping("application");
|
||||||
|
public TokenMapping ContextClaims { get; set; } = new TokenMapping("context");
|
||||||
|
public TimeSpan NotValidBefore { get; set; }
|
||||||
|
public TimeSpan NotValidAfter { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public enum TokenValueCardinality
|
||||||
|
{
|
||||||
|
Zero,
|
||||||
|
One,
|
||||||
|
Many
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Service
|
||||||
|
{
|
||||||
|
public class TokenValueDescriptor
|
||||||
|
{
|
||||||
|
public TokenValueDescriptor(string name, TokenValueCardinality cardinality)
|
||||||
|
: this(name, name, cardinality)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenValueDescriptor(string name, string alias, TokenValueCardinality cardinality)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Alias = alias;
|
||||||
|
Cardinality = cardinality;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
public string Alias { get; }
|
||||||
|
public TokenValueCardinality Cardinality { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace System.Security.Claims
|
||||||
|
{
|
||||||
|
internal static class PrincipalExtensions
|
||||||
|
{
|
||||||
|
public static string FindFirstValue(this ClaimsPrincipal principal, string claimType)
|
||||||
|
{
|
||||||
|
if (principal == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(principal));
|
||||||
|
}
|
||||||
|
var claim = principal.FindFirst(claimType);
|
||||||
|
return claim != null ? claim.Value : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue