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
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26123.0
|
||||
VisualStudioVersion = 15.0.26507.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0F647068-6602-4E24-B1DC-8ED91481A50A}"
|
||||
EndProject
|
||||
|
|
@ -26,6 +26,34 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNet.Identity.A
|
|||
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}"
|
||||
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
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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|x86.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -144,5 +340,19 @@ Global
|
|||
{4490894C-3572-4E63-86F1-EE5105CE8A06} = {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}
|
||||
{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
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<AspNetCoreVersion>2.0.0-*</AspNetCoreVersion>
|
||||
<IdentityModelOpenIdVersion>2.1.3</IdentityModelOpenIdVersion>
|
||||
<CoreFxVersion>4.3.0</CoreFxVersion>
|
||||
<IdentityEFCompatVersion>2.2.1</IdentityEFCompatVersion>
|
||||
<InternalAspNetCoreSdkVersion>2.1.0-*</InternalAspNetCoreSdkVersion>
|
||||
<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