This commit is contained in:
Hao Kung 2017-04-19 13:00:03 -07:00
parent 2d7cd6038f
commit 99aa3bd35d
175 changed files with 4280 additions and 5030 deletions

View File

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.26020.0 VisualStudioVersion = 15.0.26228.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4D2B6A51-2F9F-44F5-8131-EA5CAC053652}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4D2B6A51-2F9F-44F5-8131-EA5CAC053652}"
EndProject EndProject
@ -18,7 +18,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIdConnectSample", "samp
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Cookies", "src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj", "{FC152CC4-054B-457E-8D91-389C5DE3C561}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Cookies", "src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj", "{FC152CC4-054B-457E-8D91-389C5DE3C561}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication", "src\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.csproj", "{2286250A-52C8-4126-9F93-B1E45F0AD078}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication", "src\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.csproj", "{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Facebook", "src\Microsoft.AspNetCore.Authentication.Facebook\Microsoft.AspNetCore.Authentication.Facebook.csproj", "{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Facebook", "src\Microsoft.AspNetCore.Authentication.Facebook\Microsoft.AspNetCore.Authentication.Facebook.csproj", "{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}"
EndProject EndProject
@ -58,9 +58,11 @@ Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86 Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms Release|Mixed Platforms = Release|Mixed Platforms
Release|x64 = Release|x64
Release|x86 = Release|x86 Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
@ -68,272 +70,364 @@ Global
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|Any CPU.Build.0 = Debug|Any CPU {558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|Any CPU.Build.0 = Debug|Any CPU
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|x64.ActiveCfg = Debug|Any CPU
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|x64.Build.0 = Debug|Any CPU
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|x86.ActiveCfg = Debug|Any CPU {558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|x86.ActiveCfg = Debug|Any CPU
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|Any CPU.ActiveCfg = Release|Any CPU {558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|Any CPU.ActiveCfg = Release|Any CPU
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|Any CPU.Build.0 = Release|Any CPU {558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|Any CPU.Build.0 = Release|Any CPU
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|Mixed Platforms.Build.0 = Release|Any CPU {558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|x64.ActiveCfg = Release|Any CPU
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|x64.Build.0 = Release|Any CPU
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|x86.ActiveCfg = Release|Any CPU {558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|x86.ActiveCfg = Release|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|Any CPU.Build.0 = Debug|Any CPU {8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|x64.ActiveCfg = Debug|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|x64.Build.0 = Debug|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|x86.ActiveCfg = Debug|Any CPU {8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|x86.ActiveCfg = Debug|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|Any CPU.ActiveCfg = Release|Any CPU {8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|Any CPU.Build.0 = Release|Any CPU {8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|Any CPU.Build.0 = Release|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|Mixed Platforms.Build.0 = Release|Any CPU {8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|x64.ActiveCfg = Release|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|x64.Build.0 = Release|Any CPU
{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|x86.ActiveCfg = Release|Any CPU {8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|x86.ActiveCfg = Release|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|Any CPU.Build.0 = Debug|Any CPU {19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|Any CPU.Build.0 = Debug|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|x64.ActiveCfg = Debug|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|x64.Build.0 = Debug|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|x86.ActiveCfg = Debug|Any CPU {19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|x86.ActiveCfg = Debug|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|Any CPU.ActiveCfg = Release|Any CPU {19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|Any CPU.Build.0 = Release|Any CPU {19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|Any CPU.Build.0 = Release|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|Mixed Platforms.Build.0 = Release|Any CPU {19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|x64.ActiveCfg = Release|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|x64.Build.0 = Release|Any CPU
{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|x86.ActiveCfg = Release|Any CPU {19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|x86.ActiveCfg = Release|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|Any CPU.Build.0 = Debug|Any CPU {BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|x64.ActiveCfg = Debug|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|x64.Build.0 = Debug|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|x86.ActiveCfg = Debug|Any CPU {BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|x86.ActiveCfg = Debug|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|x86.Build.0 = Debug|Any CPU {BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|x86.Build.0 = Debug|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|Any CPU.ActiveCfg = Release|Any CPU {BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|Any CPU.Build.0 = Release|Any CPU {BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|Any CPU.Build.0 = Release|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|Mixed Platforms.Build.0 = Release|Any CPU {BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|x64.ActiveCfg = Release|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|x64.Build.0 = Release|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|x86.ActiveCfg = Release|Any CPU {BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|x86.ActiveCfg = Release|Any CPU
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|x86.Build.0 = Release|Any CPU {BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|x86.Build.0 = Release|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|Any CPU.Build.0 = Debug|Any CPU {FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|x64.ActiveCfg = Debug|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|x64.Build.0 = Debug|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|x86.ActiveCfg = Debug|Any CPU {FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|x86.ActiveCfg = Debug|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|x86.Build.0 = Debug|Any CPU {FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|x86.Build.0 = Debug|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|Any CPU.ActiveCfg = Release|Any CPU {FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|Any CPU.Build.0 = Release|Any CPU {FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|Any CPU.Build.0 = Release|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|Mixed Platforms.Build.0 = Release|Any CPU {FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|x64.ActiveCfg = Release|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|x64.Build.0 = Release|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|x86.ActiveCfg = Release|Any CPU {FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|x86.ActiveCfg = Release|Any CPU
{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|x86.Build.0 = Release|Any CPU {FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|x86.Build.0 = Release|Any CPU
{2286250A-52C8-4126-9F93-B1E45F0AD078}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2286250A-52C8-4126-9F93-B1E45F0AD078}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2286250A-52C8-4126-9F93-B1E45F0AD078}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2286250A-52C8-4126-9F93-B1E45F0AD078}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2286250A-52C8-4126-9F93-B1E45F0AD078}.Debug|x86.ActiveCfg = Debug|Any CPU
{2286250A-52C8-4126-9F93-B1E45F0AD078}.Debug|x86.Build.0 = Debug|Any CPU
{2286250A-52C8-4126-9F93-B1E45F0AD078}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2286250A-52C8-4126-9F93-B1E45F0AD078}.Release|Any CPU.Build.0 = Release|Any CPU
{2286250A-52C8-4126-9F93-B1E45F0AD078}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2286250A-52C8-4126-9F93-B1E45F0AD078}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2286250A-52C8-4126-9F93-B1E45F0AD078}.Release|x86.ActiveCfg = Release|Any CPU
{2286250A-52C8-4126-9F93-B1E45F0AD078}.Release|x86.Build.0 = Release|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|Any CPU.Build.0 = Debug|Any CPU {EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|x64.ActiveCfg = Debug|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|x64.Build.0 = Debug|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|x86.ActiveCfg = Debug|Any CPU {EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|x86.ActiveCfg = Debug|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|x86.Build.0 = Debug|Any CPU {EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|x86.Build.0 = Debug|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|Any CPU.ActiveCfg = Release|Any CPU {EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|Any CPU.Build.0 = Release|Any CPU {EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|Any CPU.Build.0 = Release|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|Mixed Platforms.Build.0 = Release|Any CPU {EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|x64.ActiveCfg = Release|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|x64.Build.0 = Release|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|x86.ActiveCfg = Release|Any CPU {EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|x86.ActiveCfg = Release|Any CPU
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|x86.Build.0 = Release|Any CPU {EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|x86.Build.0 = Release|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|Any CPU.Build.0 = Debug|Any CPU {76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|x64.ActiveCfg = Debug|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|x64.Build.0 = Debug|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|x86.ActiveCfg = Debug|Any CPU {76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|x86.ActiveCfg = Debug|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|x86.Build.0 = Debug|Any CPU {76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|x86.Build.0 = Debug|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|Any CPU.ActiveCfg = Release|Any CPU {76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|Any CPU.Build.0 = Release|Any CPU {76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|Any CPU.Build.0 = Release|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|Mixed Platforms.Build.0 = Release|Any CPU {76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|x64.ActiveCfg = Release|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|x64.Build.0 = Release|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|x86.ActiveCfg = Release|Any CPU {76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|x86.ActiveCfg = Release|Any CPU
{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|x86.Build.0 = Release|Any CPU {76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|x86.Build.0 = Release|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|Any CPU.Build.0 = Debug|Any CPU {35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|x64.ActiveCfg = Debug|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|x64.Build.0 = Debug|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|x86.ActiveCfg = Debug|Any CPU {35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|x86.ActiveCfg = Debug|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|x86.Build.0 = Debug|Any CPU {35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|x86.Build.0 = Debug|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|Any CPU.ActiveCfg = Release|Any CPU {35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|Any CPU.Build.0 = Release|Any CPU {35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|Any CPU.Build.0 = Release|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|Mixed Platforms.Build.0 = Release|Any CPU {35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|x64.ActiveCfg = Release|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|x64.Build.0 = Release|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|x86.ActiveCfg = Release|Any CPU {35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|x86.ActiveCfg = Release|Any CPU
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|x86.Build.0 = Release|Any CPU {35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|x86.Build.0 = Release|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|Any CPU.Build.0 = Debug|Any CPU {ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|x64.ActiveCfg = Debug|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|x64.Build.0 = Debug|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|x86.ActiveCfg = Debug|Any CPU {ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|x86.ActiveCfg = Debug|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|x86.Build.0 = Debug|Any CPU {ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|x86.Build.0 = Debug|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|Any CPU.ActiveCfg = Release|Any CPU {ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|Any CPU.Build.0 = Release|Any CPU {ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|Any CPU.Build.0 = Release|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|Mixed Platforms.Build.0 = Release|Any CPU {ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|x64.ActiveCfg = Release|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|x64.Build.0 = Release|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|x86.ActiveCfg = Release|Any CPU {ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|x86.ActiveCfg = Release|Any CPU
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|x86.Build.0 = Release|Any CPU {ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|x86.Build.0 = Release|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|Any CPU.Build.0 = Debug|Any CPU {0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|x64.ActiveCfg = Debug|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|x64.Build.0 = Debug|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|x86.ActiveCfg = Debug|Any CPU {0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|x86.ActiveCfg = Debug|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|x86.Build.0 = Debug|Any CPU {0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|x86.Build.0 = Debug|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|Any CPU.ActiveCfg = Release|Any CPU {0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|Any CPU.Build.0 = Release|Any CPU {0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|Any CPU.Build.0 = Release|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|Mixed Platforms.Build.0 = Release|Any CPU {0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|x64.ActiveCfg = Release|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|x64.Build.0 = Release|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|x86.ActiveCfg = Release|Any CPU {0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|x86.ActiveCfg = Release|Any CPU
{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|x86.Build.0 = Release|Any CPU {0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|x86.Build.0 = Release|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|Any CPU.Build.0 = Debug|Any CPU {1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|x64.ActiveCfg = Debug|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|x64.Build.0 = Debug|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|x86.ActiveCfg = Debug|Any CPU {1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|x86.ActiveCfg = Debug|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|x86.Build.0 = Debug|Any CPU {1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|x86.Build.0 = Debug|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|Any CPU.ActiveCfg = Release|Any CPU {1657C79E-7755-4AEE-9D61-571295B69A30}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|Any CPU.Build.0 = Release|Any CPU {1657C79E-7755-4AEE-9D61-571295B69A30}.Release|Any CPU.Build.0 = Release|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {1657C79E-7755-4AEE-9D61-571295B69A30}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|Mixed Platforms.Build.0 = Release|Any CPU {1657C79E-7755-4AEE-9D61-571295B69A30}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|x64.ActiveCfg = Release|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|x64.Build.0 = Release|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|x86.ActiveCfg = Release|Any CPU {1657C79E-7755-4AEE-9D61-571295B69A30}.Release|x86.ActiveCfg = Release|Any CPU
{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|x86.Build.0 = Release|Any CPU {1657C79E-7755-4AEE-9D61-571295B69A30}.Release|x86.Build.0 = Release|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|Any CPU.Build.0 = Debug|Any CPU {8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|x64.ActiveCfg = Debug|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|x64.Build.0 = Debug|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|x86.ActiveCfg = Debug|Any CPU {8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|x86.ActiveCfg = Debug|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|x86.Build.0 = Debug|Any CPU {8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|x86.Build.0 = Debug|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|Any CPU.ActiveCfg = Release|Any CPU {8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|Any CPU.Build.0 = Release|Any CPU {8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|Any CPU.Build.0 = Release|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|Mixed Platforms.Build.0 = Release|Any CPU {8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|x64.ActiveCfg = Release|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|x64.Build.0 = Release|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|x86.ActiveCfg = Release|Any CPU {8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|x86.ActiveCfg = Release|Any CPU
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|x86.Build.0 = Release|Any CPU {8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|x86.Build.0 = Release|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|Any CPU.Build.0 = Debug|Any CPU {7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|x64.ActiveCfg = Debug|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|x64.Build.0 = Debug|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|x86.ActiveCfg = Debug|Any CPU {7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|x86.ActiveCfg = Debug|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|x86.Build.0 = Debug|Any CPU {7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|x86.Build.0 = Debug|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|Any CPU.ActiveCfg = Release|Any CPU {7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|Any CPU.Build.0 = Release|Any CPU {7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|Any CPU.Build.0 = Release|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|Mixed Platforms.Build.0 = Release|Any CPU {7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|x64.ActiveCfg = Release|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|x64.Build.0 = Release|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|x86.ActiveCfg = Release|Any CPU {7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|x86.ActiveCfg = Release|Any CPU
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|x86.Build.0 = Release|Any CPU {7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|x86.Build.0 = Release|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|Any CPU.Build.0 = Debug|Any CPU {6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|x64.ActiveCfg = Debug|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|x64.Build.0 = Debug|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|x86.ActiveCfg = Debug|Any CPU {6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|x86.ActiveCfg = Debug|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|x86.Build.0 = Debug|Any CPU {6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|x86.Build.0 = Debug|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|Any CPU.ActiveCfg = Release|Any CPU {6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|Any CPU.Build.0 = Release|Any CPU {6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|Any CPU.Build.0 = Release|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|Mixed Platforms.Build.0 = Release|Any CPU {6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|x64.ActiveCfg = Release|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|x64.Build.0 = Release|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|x86.ActiveCfg = Release|Any CPU {6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|x86.ActiveCfg = Release|Any CPU
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|x86.Build.0 = Release|Any CPU {6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|x86.Build.0 = Release|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Any CPU.Build.0 = Debug|Any CPU {86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Any CPU.Build.0 = Debug|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|x64.ActiveCfg = Debug|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|x64.Build.0 = Debug|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|x86.ActiveCfg = Debug|Any CPU {86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|x86.ActiveCfg = Debug|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|x86.Build.0 = Debug|Any CPU {86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|x86.Build.0 = Debug|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Any CPU.ActiveCfg = Release|Any CPU {86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Any CPU.ActiveCfg = Release|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Any CPU.Build.0 = Release|Any CPU {86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Any CPU.Build.0 = Release|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Mixed Platforms.Build.0 = Release|Any CPU {86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|x64.ActiveCfg = Release|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|x64.Build.0 = Release|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|x86.ActiveCfg = Release|Any CPU {86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|x86.ActiveCfg = Release|Any CPU
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|x86.Build.0 = Release|Any CPU {86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|x86.Build.0 = Release|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Any CPU.Build.0 = Debug|Any CPU {1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|x64.ActiveCfg = Debug|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|x64.Build.0 = Debug|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|x86.ActiveCfg = Debug|Any CPU {1790E052-646F-4529-B90E-6FEA95520D69}.Debug|x86.ActiveCfg = Debug|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|x86.Build.0 = Debug|Any CPU {1790E052-646F-4529-B90E-6FEA95520D69}.Debug|x86.Build.0 = Debug|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|Any CPU.ActiveCfg = Release|Any CPU {1790E052-646F-4529-B90E-6FEA95520D69}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|Any CPU.Build.0 = Release|Any CPU {1790E052-646F-4529-B90E-6FEA95520D69}.Release|Any CPU.Build.0 = Release|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {1790E052-646F-4529-B90E-6FEA95520D69}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|Mixed Platforms.Build.0 = Release|Any CPU {1790E052-646F-4529-B90E-6FEA95520D69}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|x64.ActiveCfg = Release|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|x64.Build.0 = Release|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|x86.ActiveCfg = Release|Any CPU {1790E052-646F-4529-B90E-6FEA95520D69}.Release|x86.ActiveCfg = Release|Any CPU
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|x86.Build.0 = Release|Any CPU {1790E052-646F-4529-B90E-6FEA95520D69}.Release|x86.Build.0 = Release|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|Any CPU.Build.0 = Debug|Any CPU {2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|x64.ActiveCfg = Debug|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|x64.Build.0 = Debug|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|x86.ActiveCfg = Debug|Any CPU {2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|x86.ActiveCfg = Debug|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|x86.Build.0 = Debug|Any CPU {2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|x86.Build.0 = Debug|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|Any CPU.ActiveCfg = Release|Any CPU {2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|Any CPU.Build.0 = Release|Any CPU {2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|Any CPU.Build.0 = Release|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|Mixed Platforms.Build.0 = Release|Any CPU {2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|x64.ActiveCfg = Release|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|x64.Build.0 = Release|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|x86.ActiveCfg = Release|Any CPU {2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|x86.ActiveCfg = Release|Any CPU
{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|x86.Build.0 = Release|Any CPU {2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|x86.Build.0 = Release|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|Any CPU.Build.0 = Debug|Any CPU {D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|x64.ActiveCfg = Debug|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|x64.Build.0 = Debug|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|x86.ActiveCfg = Debug|Any CPU {D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|x86.ActiveCfg = Debug|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|x86.Build.0 = Debug|Any CPU {D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|x86.Build.0 = Debug|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|Any CPU.ActiveCfg = Release|Any CPU {D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|Any CPU.Build.0 = Release|Any CPU {D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|Any CPU.Build.0 = Release|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|Mixed Platforms.Build.0 = Release|Any CPU {D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|x64.ActiveCfg = Release|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|x64.Build.0 = Release|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|x86.ActiveCfg = Release|Any CPU {D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|x86.ActiveCfg = Release|Any CPU
{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|x86.Build.0 = Release|Any CPU {D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|x86.Build.0 = Release|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Any CPU.Build.0 = Debug|Any CPU {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x64.ActiveCfg = Debug|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x64.Build.0 = Debug|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x86.ActiveCfg = Debug|Any CPU {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x86.ActiveCfg = Debug|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x86.Build.0 = Debug|Any CPU {A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x86.Build.0 = Debug|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Any CPU.ActiveCfg = Release|Any CPU {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Any CPU.Build.0 = Release|Any CPU {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Any CPU.Build.0 = Release|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Mixed Platforms.Build.0 = Release|Any CPU {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x64.ActiveCfg = Release|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x64.Build.0 = Release|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x86.ActiveCfg = Release|Any CPU {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x86.ActiveCfg = Release|Any CPU
{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x86.Build.0 = Release|Any CPU {A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x86.Build.0 = Release|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Any CPU.Build.0 = Debug|Any CPU {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x64.ActiveCfg = Debug|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x64.Build.0 = Debug|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x86.ActiveCfg = Debug|Any CPU {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x86.ActiveCfg = Debug|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x86.Build.0 = Debug|Any CPU {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x86.Build.0 = Debug|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Any CPU.ActiveCfg = Release|Any CPU {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Any CPU.Build.0 = Release|Any CPU {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Any CPU.Build.0 = Release|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Mixed Platforms.Build.0 = Release|Any CPU {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x64.ActiveCfg = Release|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x64.Build.0 = Release|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x86.ActiveCfg = Release|Any CPU {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x86.ActiveCfg = Release|Any CPU
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x86.Build.0 = Release|Any CPU {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x86.Build.0 = Release|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Any CPU.Build.0 = Debug|Any CPU {3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|x64.ActiveCfg = Debug|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|x64.Build.0 = Debug|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|x86.ActiveCfg = Debug|Any CPU {3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|x86.ActiveCfg = Debug|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|x86.Build.0 = Debug|Any CPU {3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|x86.Build.0 = Debug|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|Any CPU.ActiveCfg = Release|Any CPU {3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|Any CPU.Build.0 = Release|Any CPU {3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|Any CPU.Build.0 = Release|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|Mixed Platforms.Build.0 = Release|Any CPU {3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|x64.ActiveCfg = Release|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|x64.Build.0 = Release|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|x86.ActiveCfg = Release|Any CPU {3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|x86.ActiveCfg = Release|Any CPU
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|x86.Build.0 = Release|Any CPU {3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|x86.Build.0 = Release|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {51563775-C659-4907-9BAF-9995BAB87D01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|Any CPU.Build.0 = Debug|Any CPU {51563775-C659-4907-9BAF-9995BAB87D01}.Debug|Any CPU.Build.0 = Debug|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {51563775-C659-4907-9BAF-9995BAB87D01}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {51563775-C659-4907-9BAF-9995BAB87D01}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|x64.ActiveCfg = Debug|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|x64.Build.0 = Debug|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|x86.ActiveCfg = Debug|Any CPU {51563775-C659-4907-9BAF-9995BAB87D01}.Debug|x86.ActiveCfg = Debug|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|x86.Build.0 = Debug|Any CPU {51563775-C659-4907-9BAF-9995BAB87D01}.Debug|x86.Build.0 = Debug|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Release|Any CPU.ActiveCfg = Release|Any CPU {51563775-C659-4907-9BAF-9995BAB87D01}.Release|Any CPU.ActiveCfg = Release|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Release|Any CPU.Build.0 = Release|Any CPU {51563775-C659-4907-9BAF-9995BAB87D01}.Release|Any CPU.Build.0 = Release|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {51563775-C659-4907-9BAF-9995BAB87D01}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Release|Mixed Platforms.Build.0 = Release|Any CPU {51563775-C659-4907-9BAF-9995BAB87D01}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Release|x64.ActiveCfg = Release|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Release|x64.Build.0 = Release|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Release|x86.ActiveCfg = Release|Any CPU {51563775-C659-4907-9BAF-9995BAB87D01}.Release|x86.ActiveCfg = Release|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Release|x86.Build.0 = Release|Any CPU {51563775-C659-4907-9BAF-9995BAB87D01}.Release|x86.Build.0 = Release|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|x64.ActiveCfg = Debug|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|x64.Build.0 = Debug|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|x86.ActiveCfg = Debug|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|x86.Build.0 = Debug|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|Any CPU.Build.0 = Release|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|x64.ActiveCfg = Release|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|x64.Build.0 = Release|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|x86.ActiveCfg = Release|Any CPU
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -344,7 +438,6 @@ Global
{19711880-46DA-4A26-9E0F-9B2E41D27651} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF} {19711880-46DA-4A26-9E0F-9B2E41D27651} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF} {BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
{FC152CC4-054B-457E-8D91-389C5DE3C561} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652} {FC152CC4-054B-457E-8D91-389C5DE3C561} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
{2286250A-52C8-4126-9F93-B1E45F0AD078} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652} {EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
{76579C39-B829-490D-B8BE-1BD35FE8412E} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652} {76579C39-B829-490D-B8BE-1BD35FE8412E} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652} {35115D55-B69E-46D4-BB33-C9E9E6EC5E7A} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
@ -362,5 +455,6 @@ Global
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24} = {7BF11F3A-60B6-4796-B504-579C67FFBA34} {A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF} {3A7AD414-EBDE-4F92-B307-4E8F19B6117E} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
{51563775-C659-4907-9BAF-9995BAB87D01} = {7BF11F3A-60B6-4796-B504-579C67FFBA34} {51563775-C659-4907-9BAF-9995BAB87D01} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@ -1,5 +1,6 @@
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@ -13,24 +14,21 @@ namespace CookieSample
{ {
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddAuthentication(); services.AddCookieAuthentication();
} }
public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory)
{ {
loggerfactory.AddConsole(LogLevel.Information); loggerfactory.AddConsole(LogLevel.Information);
app.UseCookieAuthentication(new CookieAuthenticationOptions app.UseAuthentication();
{
AutomaticAuthenticate = true
});
app.Run(async context => app.Run(async context =>
{ {
if (!context.User.Identities.Any(identity => identity.IsAuthenticated)) if (!context.User.Identities.Any(identity => identity.IsAuthenticated))
{ {
var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "bob") }, CookieAuthenticationDefaults.AuthenticationScheme)); var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "bob") }, CookieAuthenticationDefaults.AuthenticationScheme));
await context.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user); await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);
context.Response.ContentType = "text/plain"; context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Hello First timer"); await context.Response.WriteAsync("Hello First timer");

View File

@ -4,6 +4,7 @@ using System.Security.Claims;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -14,18 +15,14 @@ namespace CookieSessionSample
{ {
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddAuthentication(); services.AddCookieAuthentication(o => o.SessionStore = new MemoryCacheTicketStore());
} }
public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory)
{ {
loggerfactory.AddConsole(LogLevel.Information); loggerfactory.AddConsole(LogLevel.Information);
app.UseCookieAuthentication(new CookieAuthenticationOptions app.UseAuthentication();
{
AutomaticAuthenticate = true,
SessionStore = new MemoryCacheTicketStore()
});
app.Run(async context => app.Run(async context =>
{ {
@ -39,7 +36,7 @@ namespace CookieSessionSample
claims.Add(new Claim(ClaimTypes.Role, "SomeRandomGroup" + i, ClaimValueTypes.String, "IssuedByBob", "OriginalIssuerJoe")); claims.Add(new Claim(ClaimTypes.Role, "SomeRandomGroup" + i, ClaimValueTypes.String, "IssuedByBob", "OriginalIssuerJoe"));
} }
await context.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme))); new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme)));
context.Response.ContentType = "text/plain"; context.Response.ContentType = "text/plain";

View File

@ -17,6 +17,7 @@
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(AspNetCoreVersion)" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@ -42,39 +43,12 @@ namespace JwtBearerSample
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddAuthentication(); services.AddJwtBearerAuthentication(o =>
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
{
// Simple error page to avoid a repo dependency.
app.Use(async (context, next) =>
{
try
{
await next();
}
catch (Exception ex)
{
if (context.Response.HasStarted)
{
throw;
}
context.Response.StatusCode = 500;
await context.Response.WriteAsync(ex.ToString());
}
});
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseJwtBearerAuthentication(new JwtBearerOptions
{ {
// You also need to update /wwwroot/app/scripts/app.js // You also need to update /wwwroot/app/scripts/app.js
Authority = Configuration["jwt:authority"], o.Authority = Configuration["jwt:authority"];
Audience = Configuration["jwt:audience"], o.Audience = Configuration["jwt:audience"];
Events = new JwtBearerEvents() o.Events = new JwtBearerEvents()
{ {
OnAuthenticationFailed = c => OnAuthenticationFailed = c =>
{ {
@ -89,24 +63,34 @@ namespace JwtBearerSample
} }
return c.Response.WriteAsync("An error occurred processing your authentication."); return c.Response.WriteAsync("An error occurred processing your authentication.");
} }
} };
}); });
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
{
app.UseDeveloperExceptionPage();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseAuthentication();
// [Authorize] would usually handle this // [Authorize] would usually handle this
app.Use(async (context, next) => app.Use(async (context, next) =>
{ {
// Use this if options.AutomaticAuthenticate = false // Use this if there are multiple authentication schemes
// var user = await context.Authentication.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme); // var user = await context.Authentication.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
var user = context.User; // We can do this because of options.AutomaticAuthenticate = true; var user = context.User; // We can do this because of there's only a single authentication scheme
if (user?.Identity?.IsAuthenticated ?? false) if (user?.Identity?.IsAuthenticated ?? false)
{ {
await next(); await next();
} }
else else
{ {
// We can do this because of options.AutomaticChallenge = true; await context.ChallengeAsync();
await context.Authentication.ChallengeAsync();
} }
}); });
@ -135,5 +119,4 @@ namespace JwtBearerSample
}); });
} }
} }
} }

View File

@ -1,9 +1,8 @@
using System; using System;
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.IdentityModel.Clients.ActiveDirectory; using Microsoft.IdentityModel.Clients.ActiveDirectory;
namespace OpenIdConnect.AzureAdSample namespace OpenIdConnect.AzureAdSample
@ -58,10 +57,9 @@ namespace OpenIdConnect.AzureAdSample
private void BeforeAccessNotificationWithContext(TokenCacheNotificationArgs args) private void BeforeAccessNotificationWithContext(TokenCacheNotificationArgs args)
{ {
// Retrieve the auth session with the cached tokens // Retrieve the auth session with the cached tokens
var authenticateContext = new AuthenticateContext(_signInScheme); var result = _httpContext.AuthenticateAsync(_signInScheme).Result;
_httpContext.Authentication.AuthenticateAsync(authenticateContext).Wait(); _authProperties = result.Ticket.Properties;
_authProperties = new AuthenticationProperties(authenticateContext.Properties); _principal = result.Ticket.Principal;
_principal = authenticateContext.Principal;
BeforeAccessNotificationWithProperties(args); BeforeAccessNotificationWithProperties(args);
} }
@ -87,7 +85,7 @@ namespace OpenIdConnect.AzureAdSample
var cachedTokens = Serialize(); var cachedTokens = Serialize();
var cachedTokensText = Convert.ToBase64String(cachedTokens); var cachedTokensText = Convert.ToBase64String(cachedTokens);
_authProperties.Items[TokenCacheKey] = cachedTokensText; _authProperties.Items[TokenCacheKey] = cachedTokensText;
_httpContext.Authentication.SignInAsync(_signInScheme, _principal, _authProperties).Wait(); _httpContext.SignInAsync(_signInScheme, _principal, _authProperties).Wait();
} }
} }

View File

@ -17,6 +17,7 @@
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="$(IdentityModelActiveDirectoryVersion)" /> <PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="$(IdentityModelActiveDirectoryVersion)" />
<DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="$(AspNetCoreVersion)" /> <DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="$(AspNetCoreVersion)" />

View File

@ -3,12 +3,12 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -37,68 +37,55 @@ namespace OpenIdConnect.AzureAdSample
public IConfiguration Configuration { get; set; } public IConfiguration Configuration { get; set; }
private string ClientId => Configuration["oidc:clientid"];
private string ClientSecret => Configuration["oidc:clientsecret"];
private string Authority => Configuration["oidc:authority"];
private string Resource => "https://graph.windows.net";
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddAuthentication(sharedOptions => services.AddAuthentication(sharedOptions =>
sharedOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme); {
sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
});
services.AddCookieAuthentication();
services.AddOpenIdConnectAuthentication(o =>
{
o.ClientId = ClientId;
o.ClientSecret = ClientSecret; // for code flow
o.Authority = Authority;
o.ResponseType = OpenIdConnectResponseType.CodeIdToken;
o.PostLogoutRedirectUri = "/signed-out";
// GetClaimsFromUserInfoEndpoint = true,
o.Events = new OpenIdConnectEvents()
{
OnAuthorizationCodeReceived = async context =>
{
var request = context.HttpContext.Request;
var currentUri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path);
var credential = new ClientCredential(ClientId, ClientSecret);
var authContext = new AuthenticationContext(Authority, AuthPropertiesTokenCache.ForCodeRedemption(context.Properties));
var result = await authContext.AcquireTokenByAuthorizationCodeAsync(
context.ProtocolMessage.Code, new Uri(currentUri), credential, Resource);
context.HandleCodeRedemption(result.AccessToken, result.IdToken);
}
};
});
} }
public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory)
{ {
loggerfactory.AddConsole(Microsoft.Extensions.Logging.LogLevel.Information); loggerfactory.AddConsole(Microsoft.Extensions.Logging.LogLevel.Information);
// Simple error page app.UseDeveloperExceptionPage();
app.Use(async (context, next) =>
{
try
{
await next();
}
catch (Exception ex)
{
if (!context.Response.HasStarted)
{
context.Response.Clear();
context.Response.StatusCode = 500;
await context.Response.WriteAsync(ex.ToString());
}
else
{
throw;
}
}
});
app.UseCookieAuthentication(new CookieAuthenticationOptions()); app.UseAuthentication();
var clientId = Configuration["oidc:clientid"];
var clientSecret = Configuration["oidc:clientsecret"];
var authority = Configuration["oidc:authority"];
var resource = "https://graph.windows.net";
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
ClientId = clientId,
ClientSecret = clientSecret, // for code flow
Authority = authority,
ResponseType = OpenIdConnectResponseType.CodeIdToken,
PostLogoutRedirectUri = "/signed-out",
// GetClaimsFromUserInfoEndpoint = true,
Events = new OpenIdConnectEvents()
{
OnAuthorizationCodeReceived = async context =>
{
var request = context.HttpContext.Request;
var currentUri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path);
var credential = new ClientCredential(clientId, clientSecret);
var authContext = new AuthenticationContext(authority, AuthPropertiesTokenCache.ForCodeRedemption(context.Properties));
var result = await authContext.AcquireTokenByAuthorizationCodeAsync(
context.ProtocolMessage.Code, new Uri(currentUri), credential, resource);
context.HandleCodeRedemption(result.AccessToken, result.IdToken);
}
}
});
app.Run(async context => app.Run(async context =>
{ {
@ -111,13 +98,11 @@ namespace OpenIdConnect.AzureAdSample
return; return;
} }
await context.Authentication.ChallengeAsync( await context.ChallengeAsync(new AuthenticationProperties { RedirectUri = "/" });
OpenIdConnectDefaults.AuthenticationScheme,
new AuthenticationProperties { RedirectUri = "/" });
} }
else if (context.Request.Path.Equals("/signout")) else if (context.Request.Path.Equals("/signout"))
{ {
await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await WriteHtmlAsync(context.Response, await WriteHtmlAsync(context.Response,
async response => async response =>
{ {
@ -127,8 +112,8 @@ namespace OpenIdConnect.AzureAdSample
} }
else if (context.Request.Path.Equals("/signout-remote")) else if (context.Request.Path.Equals("/signout-remote"))
{ {
await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await context.Authentication.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme); await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
} }
else if (context.Request.Path.Equals("/signed-out")) else if (context.Request.Path.Equals("/signed-out"))
{ {
@ -141,7 +126,7 @@ namespace OpenIdConnect.AzureAdSample
} }
else if (context.Request.Path.Equals("/remote-signedout")) else if (context.Request.Path.Equals("/remote-signedout"))
{ {
await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await WriteHtmlAsync(context.Response, await WriteHtmlAsync(context.Response,
async response => async response =>
{ {
@ -153,7 +138,7 @@ namespace OpenIdConnect.AzureAdSample
{ {
if (!context.User.Identities.Any(identity => identity.IsAuthenticated)) if (!context.User.Identities.Any(identity => identity.IsAuthenticated))
{ {
await context.Authentication.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/" }); await context.ChallengeAsync(new AuthenticationProperties { RedirectUri = "/" });
return; return;
} }
@ -170,10 +155,10 @@ namespace OpenIdConnect.AzureAdSample
try try
{ {
// Use ADAL to get the right token // Use ADAL to get the right token
var authContext = new AuthenticationContext(authority, AuthPropertiesTokenCache.ForApiCalls(context, CookieAuthenticationDefaults.AuthenticationScheme)); var authContext = new AuthenticationContext(Authority, AuthPropertiesTokenCache.ForApiCalls(context, CookieAuthenticationDefaults.AuthenticationScheme));
var credential = new ClientCredential(clientId, clientSecret); var credential = new ClientCredential(ClientId, ClientSecret);
string userObjectID = context.User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value; string userObjectID = context.User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
var result = await authContext.AcquireTokenSilentAsync(resource, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId)); var result = await authContext.AcquireTokenSilentAsync(Resource, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
await response.WriteAsync($"<h3>access_token</h3><code>{HtmlEncode(result.AccessToken)}</code><br>"); await response.WriteAsync($"<h3>access_token</h3><code>{HtmlEncode(result.AccessToken)}</code><br>");
} }

View File

@ -18,6 +18,7 @@
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="$(AspNetCoreVersion)" />

View File

@ -3,12 +3,12 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -42,46 +42,22 @@ namespace OpenIdConnectSample
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddAuthentication(sharedOptions => services.AddAuthentication(sharedOptions =>
sharedOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme);
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory)
{
loggerfactory.AddConsole(LogLevel.Information);
loggerfactory.AddDebug(LogLevel.Information);
// Simple error page
app.Use(async (context, next) =>
{ {
try sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
{ sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
await next(); sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
}
catch (Exception ex)
{
if (!context.Response.HasStarted)
{
context.Response.Clear();
context.Response.StatusCode = 500;
await context.Response.WriteAsync(ex.ToString());
}
else
{
throw;
}
}
}); });
app.UseCookieAuthentication(new CookieAuthenticationOptions()); services.AddCookieAuthentication();
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions services.AddOpenIdConnectAuthentication(o =>
{ {
ClientId = Configuration["oidc:clientid"], o.ClientId = Configuration["oidc:clientid"];
ClientSecret = Configuration["oidc:clientsecret"], // for code flow o.ClientSecret = Configuration["oidc:clientsecret"]; // for code flow
Authority = Configuration["oidc:authority"], o.Authority = Configuration["oidc:authority"];
ResponseType = OpenIdConnectResponseType.CodeIdToken, o.ResponseType = OpenIdConnectResponseType.CodeIdToken;
GetClaimsFromUserInfoEndpoint = true, o.GetClaimsFromUserInfoEndpoint = true;
Events = new OpenIdConnectEvents() o.Events = new OpenIdConnectEvents()
{ {
OnAuthenticationFailed = c => OnAuthenticationFailed = c =>
{ {
@ -96,8 +72,17 @@ namespace OpenIdConnectSample
} }
return c.Response.WriteAsync("An error occurred processing your authentication."); return c.Response.WriteAsync("An error occurred processing your authentication.");
} }
} };
}); });
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory)
{
loggerfactory.AddConsole(LogLevel.Information);
loggerfactory.AddDebug(LogLevel.Information);
app.UseDeveloperExceptionPage();
app.UseAuthentication();
app.Run(async context => app.Run(async context =>
{ {
@ -113,7 +98,7 @@ namespace OpenIdConnectSample
if (context.Request.Path.Equals("/signout")) if (context.Request.Path.Equals("/signout"))
{ {
await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await WriteHtmlAsync(context.Response, async res => await WriteHtmlAsync(context.Response, async res =>
{ {
await context.Response.WriteAsync($"<h1>Signed out {HtmlEncode(context.User.Identity.Name)}</h1>"); await context.Response.WriteAsync($"<h1>Signed out {HtmlEncode(context.User.Identity.Name)}</h1>");
@ -125,8 +110,8 @@ namespace OpenIdConnectSample
if (context.Request.Path.Equals("/signout-remote")) if (context.Request.Path.Equals("/signout-remote"))
{ {
// Redirects // Redirects
await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await context.Authentication.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties() await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties()
{ {
RedirectUri = "/signedout" RedirectUri = "/signedout"
}); });
@ -135,7 +120,7 @@ namespace OpenIdConnectSample
if (context.Request.Path.Equals("/Account/AccessDenied")) if (context.Request.Path.Equals("/Account/AccessDenied"))
{ {
await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await WriteHtmlAsync(context.Response, async res => await WriteHtmlAsync(context.Response, async res =>
{ {
await context.Response.WriteAsync($"<h1>Access Denied for user {HtmlEncode(context.User.Identity.Name)} to resource '{HtmlEncode(context.Request.Query["ReturnUrl"])}'</h1>"); await context.Response.WriteAsync($"<h1>Access Denied for user {HtmlEncode(context.User.Identity.Name)} to resource '{HtmlEncode(context.Request.Query["ReturnUrl"])}'</h1>");
@ -144,24 +129,23 @@ namespace OpenIdConnectSample
return; return;
} }
// CookieAuthenticationOptions.AutomaticAuthenticate = true (default) causes User to be set // DefaultAuthenticateScheme causes User to be set
var user = context.User; var user = context.User;
// This is what [Authorize] calls // This is what [Authorize] calls
// var user = await context.Authentication.AuthenticateAsync(AuthenticationManager.AutomaticScheme); // var user = await context.AuthenticateAsync();
// This is what [Authorize(ActiveAuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] calls // This is what [Authorize(ActiveAuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] calls
// var user = await context.Authentication.AuthenticateAsync(OpenIdConnectDefaults.AuthenticationScheme); // var user = await context.AuthenticateAsync(OpenIdConnectDefaults.AuthenticationScheme);
// Not authenticated // Not authenticated
if (user == null || !user.Identities.Any(identity => identity.IsAuthenticated)) if (user == null || !user.Identities.Any(identity => identity.IsAuthenticated))
{ {
// This is what [Authorize] calls // This is what [Authorize] calls
// The cookie middleware will intercept this 401 and redirect to /login await context.ChallengeAsync();
await context.Authentication.ChallengeAsync();
// This is what [Authorize(ActiveAuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] calls // This is what [Authorize(ActiveAuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] calls
// await context.Authentication.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme); // await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme);
return; return;
} }
@ -169,11 +153,10 @@ namespace OpenIdConnectSample
// Authenticated, but not authorized // Authenticated, but not authorized
if (context.Request.Path.Equals("/restricted") && !user.Identities.Any(identity => identity.HasClaim("special", "true"))) if (context.Request.Path.Equals("/restricted") && !user.Identities.Any(identity => identity.HasClaim("special", "true")))
{ {
await context.Authentication.ChallengeAsync(); await context.ChallengeAsync();
return; return;
} }
await WriteHtmlAsync(context.Response, async response => await WriteHtmlAsync(context.Response, async response =>
{ {
await response.WriteAsync($"<h1>Hello Authenticated User {HtmlEncode(user.Identity.Name)}</h1>"); await response.WriteAsync($"<h1>Hello Authenticated User {HtmlEncode(user.Identity.Name)}</h1>");

View File

@ -22,6 +22,7 @@
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(AspNetCoreVersion)" />
</ItemGroup> </ItemGroup>

View File

@ -14,7 +14,6 @@ using Microsoft.AspNetCore.Authentication.Twitter;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -45,38 +44,6 @@ namespace SocialSample
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddAuthentication(options => options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme);
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory)
{
loggerfactory.AddConsole(LogLevel.Information);
// Simple error page to avoid a repo dependency.
app.Use(async (context, next) =>
{
try
{
await next();
}
catch (Exception ex)
{
if (context.Response.HasStarted)
{
throw;
}
context.Response.StatusCode = 500;
await context.Response.WriteAsync(ex.ToString());
}
});
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
LoginPath = new PathString("/login")
});
if (string.IsNullOrEmpty(Configuration["facebook:appid"])) if (string.IsNullOrEmpty(Configuration["facebook:appid"]))
{ {
// User-Secrets: https://docs.asp.net/en/latest/security/app-secrets.html // User-Secrets: https://docs.asp.net/en/latest/security/app-secrets.html
@ -84,40 +51,51 @@ namespace SocialSample
throw new InvalidOperationException("User secrets must be configured for each authentication provider."); throw new InvalidOperationException("User secrets must be configured for each authentication provider.");
} }
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
});
services.AddCookieAuthentication(o => o.LoginPath = new PathString("/login"));
// You must first create an app with Facebook and add its ID and Secret to your user-secrets. // You must first create an app with Facebook and add its ID and Secret to your user-secrets.
// https://developers.facebook.com/apps/ // https://developers.facebook.com/apps/
app.UseFacebookAuthentication(new FacebookOptions services.AddFacebookAuthentication(o =>
{ {
AppId = Configuration["facebook:appid"], o.AppId = Configuration["facebook:appid"];
AppSecret = Configuration["facebook:appsecret"], o.AppSecret = Configuration["facebook:appsecret"];
Scope = { "email" }, o.Scope.Add("email");
Fields = { "name", "email" }, o.Fields.Add("name");
SaveTokens = true, o.Fields.Add("email");
o.SaveTokens = true;
}); });
// You must first create an app with Google and add its ID and Secret to your user-secrets. // You must first create an app with Google and add its ID and Secret to your user-secrets.
// https://console.developers.google.com/project // https://console.developers.google.com/project
app.UseOAuthAuthentication(new OAuthOptions services.AddOAuthAuthentication("Google-AccessToken", o =>
{ {
AuthenticationScheme = "Google-AccessToken", o.DisplayName = "Google-AccessToken";
DisplayName = "Google-AccessToken", o.ClientId = Configuration["google:clientid"];
ClientId = Configuration["google:clientid"], o.ClientSecret = Configuration["google:clientsecret"];
ClientSecret = Configuration["google:clientsecret"], o.CallbackPath = new PathString("/signin-google-token");
CallbackPath = new PathString("/signin-google-token"), o.AuthorizationEndpoint = GoogleDefaults.AuthorizationEndpoint;
AuthorizationEndpoint = GoogleDefaults.AuthorizationEndpoint, o.TokenEndpoint = GoogleDefaults.TokenEndpoint;
TokenEndpoint = GoogleDefaults.TokenEndpoint, o.Scope.Add("openid");
Scope = { "openid", "profile", "email" }, o.Scope.Add("profile");
SaveTokens = true o.Scope.Add("email");
o.SaveTokens = true;
}); });
// You must first create an app with Google and add its ID and Secret to your user-secrets. // You must first create an app with Google and add its ID and Secret to your user-secrets.
// https://console.developers.google.com/project // https://console.developers.google.com/project
var googleOptions = new GoogleOptions services.AddGoogleAuthentication(o =>
{ {
ClientId = Configuration["google:clientid"], o.ClientId = Configuration["google:clientid"];
ClientSecret = Configuration["google:clientsecret"], o.ClientSecret = Configuration["google:clientsecret"];
SaveTokens = true, o.SaveTokens = true;
Events = new OAuthEvents() o.Events = new OAuthEvents()
{ {
OnRemoteFailure = ctx => OnRemoteFailure = ctx =>
{ {
@ -125,23 +103,23 @@ namespace SocialSample
ctx.HandleResponse(); ctx.HandleResponse();
return Task.FromResult(0); return Task.FromResult(0);
} }
} };
}; o.ClaimActions.MapJsonSubKey("urn:google:image", "image", "url");
googleOptions.ClaimActions.MapJsonSubKey("urn:google:image", "image", "url"); o.ClaimActions.Remove(ClaimTypes.GivenName);
googleOptions.ClaimActions.Remove(ClaimTypes.GivenName); });
app.UseGoogleAuthentication(googleOptions);
// You must first create an app with Twitter and add its key and Secret to your user-secrets. // You must first create an app with Twitter and add its key and Secret to your user-secrets.
// https://apps.twitter.com/ // https://apps.twitter.com/
var twitterOptions = new TwitterOptions services.AddTwitterAuthentication(o =>
{ {
ConsumerKey = Configuration["twitter:consumerkey"], o.ConsumerKey = Configuration["twitter:consumerkey"];
ConsumerSecret = Configuration["twitter:consumersecret"], o.ConsumerSecret = Configuration["twitter:consumersecret"];
// http://stackoverflow.com/questions/22627083/can-we-get-email-id-from-twitter-oauth-api/32852370#32852370 // http://stackoverflow.com/questions/22627083/can-we-get-email-id-from-twitter-oauth-api/32852370#32852370
// http://stackoverflow.com/questions/36330675/get-users-email-from-twitter-api-for-external-login-authentication-asp-net-mvc?lq=1 // http://stackoverflow.com/questions/36330675/get-users-email-from-twitter-api-for-external-login-authentication-asp-net-mvc?lq=1
RetrieveUserDetails = true, o.RetrieveUserDetails = true;
SaveTokens = true, o.SaveTokens = true;
Events = new TwitterEvents() o.ClaimActions.MapJsonKey("urn:twitter:profilepicture", "profile_image_url", ClaimTypes.Uri);
o.Events = new TwitterEvents()
{ {
OnRemoteFailure = ctx => OnRemoteFailure = ctx =>
{ {
@ -149,10 +127,8 @@ namespace SocialSample
ctx.HandleResponse(); ctx.HandleResponse();
return Task.FromResult(0); return Task.FromResult(0);
} }
} };
}; });
twitterOptions.ClaimActions.MapJsonKey("urn:twitter:profilepicture", "profile_image_url", ClaimTypes.Uri);
app.UseTwitterAuthentication(twitterOptions);
/* Azure AD app model v2 has restrictions that prevent the use of plain HTTP for redirect URLs. /* Azure AD app model v2 has restrictions that prevent the use of plain HTTP for redirect URLs.
Therefore, to authenticate through microsoft accounts, tryout the sample using the following URL: Therefore, to authenticate through microsoft accounts, tryout the sample using the following URL:
@ -160,59 +136,60 @@ namespace SocialSample
*/ */
// You must first create an app with Microsoft Account and add its ID and Secret to your user-secrets. // You must first create an app with Microsoft Account and add its ID and Secret to your user-secrets.
// https://apps.dev.microsoft.com/ // https://apps.dev.microsoft.com/
app.UseOAuthAuthentication(new OAuthOptions services.AddOAuthAuthentication("Microsoft-AccessToken", o =>
{ {
AuthenticationScheme = "Microsoft-AccessToken", o.DisplayName = "MicrosoftAccount-AccessToken";
DisplayName = "MicrosoftAccount-AccessToken", o.ClientId = Configuration["microsoftaccount:clientid"];
ClientId = Configuration["microsoftaccount:clientid"], o.ClientSecret = Configuration["microsoftaccount:clientsecret"];
ClientSecret = Configuration["microsoftaccount:clientsecret"], o.CallbackPath = new PathString("/signin-microsoft-token");
CallbackPath = new PathString("/signin-microsoft-token"), o.AuthorizationEndpoint = MicrosoftAccountDefaults.AuthorizationEndpoint;
AuthorizationEndpoint = MicrosoftAccountDefaults.AuthorizationEndpoint, o.TokenEndpoint = MicrosoftAccountDefaults.TokenEndpoint;
TokenEndpoint = MicrosoftAccountDefaults.TokenEndpoint, o.Scope.Add("https://graph.microsoft.com/user.read");
Scope = { "https://graph.microsoft.com/user.read" }, o.SaveTokens = true;
SaveTokens = true
}); });
// You must first create an app with Microsoft Account and add its ID and Secret to your user-secrets. // You must first create an app with Microsoft Account and add its ID and Secret to your user-secrets.
// https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-app-registration/ // https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-app-registration/
app.UseMicrosoftAccountAuthentication(new MicrosoftAccountOptions services.AddMicrosoftAccountAuthentication(o =>
{ {
DisplayName = "MicrosoftAccount", o.ClientId = Configuration["microsoftaccount:clientid"];
ClientId = Configuration["microsoftaccount:clientid"], o.ClientSecret = Configuration["microsoftaccount:clientsecret"];
ClientSecret = Configuration["microsoftaccount:clientsecret"], o.SaveTokens = true;
SaveTokens = true
}); });
// You must first create an app with GitHub and add its ID and Secret to your user-secrets. // You must first create an app with GitHub and add its ID and Secret to your user-secrets.
// https://github.com/settings/applications/ // https://github.com/settings/applications/
app.UseOAuthAuthentication(new OAuthOptions services.AddOAuthAuthentication("GitHub-AccessToken", o =>
{ {
AuthenticationScheme = "GitHub-AccessToken", o.DisplayName = "Github-AccessToken";
DisplayName = "Github-AccessToken", o.ClientId = Configuration["github-token:clientid"];
ClientId = Configuration["github-token:clientid"], o.ClientSecret = Configuration["github-token:clientsecret"];
ClientSecret = Configuration["github-token:clientsecret"], o.CallbackPath = new PathString("/signin-github-token");
CallbackPath = new PathString("/signin-github-token"), o.AuthorizationEndpoint = "https://github.com/login/oauth/authorize";
AuthorizationEndpoint = "https://github.com/login/oauth/authorize", o.TokenEndpoint = "https://github.com/login/oauth/access_token";
TokenEndpoint = "https://github.com/login/oauth/access_token", o.SaveTokens = true;
SaveTokens = true o.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
o.ClaimActions.MapJsonKey(ClaimTypes.Name, "login");
o.ClaimActions.MapJsonKey("urn:github:name", "name");
o.ClaimActions.MapJsonKey(ClaimTypes.Email, "email", ClaimValueTypes.Email);
o.ClaimActions.MapJsonKey("urn:github:url", "url");
}); });
// You must first create an app with GitHub and add its ID and Secret to your user-secrets. // You must first create an app with GitHub and add its ID and Secret to your user-secrets.
// https://github.com/settings/applications/ // https://github.com/settings/applications/
var githubOptions = new OAuthOptions services.AddOAuthAuthentication("GitHub", o =>
{ {
AuthenticationScheme = "GitHub", o.DisplayName = "Github";
DisplayName = "Github", o.ClientId = Configuration["github:clientid"];
ClientId = Configuration["github:clientid"], o.ClientSecret = Configuration["github:clientsecret"];
ClientSecret = Configuration["github:clientsecret"], o.CallbackPath = new PathString("/signin-github");
CallbackPath = new PathString("/signin-github"), o.AuthorizationEndpoint = "https://github.com/login/oauth/authorize";
AuthorizationEndpoint = "https://github.com/login/oauth/authorize", o.TokenEndpoint = "https://github.com/login/oauth/access_token";
TokenEndpoint = "https://github.com/login/oauth/access_token", o.UserInformationEndpoint = "https://api.github.com/user";
UserInformationEndpoint = "https://api.github.com/user", o.ClaimsIssuer = "OAuth2-Github";
ClaimsIssuer = "OAuth2-Github", o.SaveTokens = true;
SaveTokens = true,
// Retrieving user information is unique to each provider. // Retrieving user information is unique to each provider.
Events = new OAuthEvents o.Events = new OAuthEvents
{ {
OnCreatingTicket = async context => OnCreatingTicket = async context =>
{ {
@ -228,14 +205,17 @@ namespace SocialSample
context.RunClaimActions(user); context.RunClaimActions(user);
} }
} };
}; });
githubOptions.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id"); }
githubOptions.ClaimActions.MapJsonKey(ClaimTypes.Name, "login");
githubOptions.ClaimActions.MapJsonKey("urn:github:name", "name"); public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory)
githubOptions.ClaimActions.MapJsonKey(ClaimTypes.Email, "email", ClaimValueTypes.Email); {
githubOptions.ClaimActions.MapJsonKey("urn:github:url", "url"); loggerfactory.AddConsole(LogLevel.Information);
app.UseOAuthAuthentication(githubOptions);
app.UseDeveloperExceptionPage();
app.UseAuthentication();
// Choose an authentication type // Choose an authentication type
app.Map("/login", signinApp => app.Map("/login", signinApp =>
@ -247,16 +227,18 @@ namespace SocialSample
{ {
// By default the client will be redirect back to the URL that issued the challenge (/login?authtype=foo), // By default the client will be redirect back to the URL that issued the challenge (/login?authtype=foo),
// send them to the home page instead (/). // send them to the home page instead (/).
await context.Authentication.ChallengeAsync(authType, new AuthenticationProperties() { RedirectUri = "/" }); await context.ChallengeAsync(authType, new AuthenticationProperties() { RedirectUri = "/" });
return; return;
} }
context.Response.ContentType = "text/html"; context.Response.ContentType = "text/html";
await context.Response.WriteAsync("<html><body>"); await context.Response.WriteAsync("<html><body>");
await context.Response.WriteAsync("Choose an authentication scheme: <br>"); await context.Response.WriteAsync("Choose an authentication scheme: <br>");
foreach (var type in context.Authentication.GetAuthenticationSchemes()) var schemeProvider = context.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
foreach (var provider in await schemeProvider.GetAllSchemesAsync())
{ {
await context.Response.WriteAsync("<a href=\"?authscheme=" + type.AuthenticationScheme + "\">" + (type.DisplayName ?? "(suppressed)") + "</a><br>"); // REVIEW: we lost access to display name (which is buried in the handler options)
await context.Response.WriteAsync("<a href=\"?authscheme=" + provider.Name + "\">" + (provider.Name ?? "(suppressed)") + "</a><br>");
} }
await context.Response.WriteAsync("</body></html>"); await context.Response.WriteAsync("</body></html>");
}); });
@ -268,7 +250,7 @@ namespace SocialSample
signoutApp.Run(async context => signoutApp.Run(async context =>
{ {
context.Response.ContentType = "text/html"; context.Response.ContentType = "text/html";
await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await context.Response.WriteAsync("<html><body>"); await context.Response.WriteAsync("<html><body>");
await context.Response.WriteAsync("You have been logged out. Goodbye " + context.User.Identity.Name + "<br>"); await context.Response.WriteAsync("You have been logged out. Goodbye " + context.User.Identity.Name + "<br>");
await context.Response.WriteAsync("<a href=\"/\">Home</a>"); await context.Response.WriteAsync("<a href=\"/\">Home</a>");
@ -292,24 +274,24 @@ namespace SocialSample
app.Run(async context => app.Run(async context =>
{ {
// CookieAuthenticationOptions.AutomaticAuthenticate = true (default) causes User to be set // Setting DefaultAuthenticateScheme causes User to be set
var user = context.User; var user = context.User;
// This is what [Authorize] calls // This is what [Authorize] calls
// var user = await context.Authentication.AuthenticateAsync(AuthenticationManager.AutomaticScheme); // var user = await context.AuthenticateAsync();
// This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls // This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls
// var user = await context.Authentication.AuthenticateAsync(MicrosoftAccountDefaults.AuthenticationScheme); // var user = await context.AuthenticateAsync(MicrosoftAccountDefaults.AuthenticationScheme);
// Deny anonymous request beyond this point. // Deny anonymous request beyond this point.
if (user == null || !user.Identities.Any(identity => identity.IsAuthenticated)) if (user == null || !user.Identities.Any(identity => identity.IsAuthenticated))
{ {
// This is what [Authorize] calls // This is what [Authorize] calls
// The cookie middleware will intercept this 401 and redirect to /login // The cookie middleware will intercept this 401 and redirect to /login
await context.Authentication.ChallengeAsync(); await context.ChallengeAsync();
// This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls // This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls
// await context.Authentication.ChallengeAsync(MicrosoftAccountDefaults.AuthenticationScheme); // await context.ChallengeAsync(MicrosoftAccountDefaults.AuthenticationScheme);
return; return;
} }
@ -324,11 +306,11 @@ namespace SocialSample
} }
await context.Response.WriteAsync("Tokens:<br>"); await context.Response.WriteAsync("Tokens:<br>");
await context.Response.WriteAsync("Access Token: " + await context.Authentication.GetTokenAsync("access_token") + "<br>"); await context.Response.WriteAsync("Access Token: " + await context.GetTokenAsync("access_token") + "<br>");
await context.Response.WriteAsync("Refresh Token: " + await context.Authentication.GetTokenAsync("refresh_token") + "<br>"); await context.Response.WriteAsync("Refresh Token: " + await context.GetTokenAsync("refresh_token") + "<br>");
await context.Response.WriteAsync("Token Type: " + await context.Authentication.GetTokenAsync("token_type") + "<br>"); await context.Response.WriteAsync("Token Type: " + await context.GetTokenAsync("token_type") + "<br>");
await context.Response.WriteAsync("expires_at: " + await context.Authentication.GetTokenAsync("expires_at") + "<br>"); await context.Response.WriteAsync("expires_at: " + await context.GetTokenAsync("expires_at") + "<br>");
await context.Response.WriteAsync("<a href=\"/logout\">Logout</a><br>"); await context.Response.WriteAsync("<a href=\"/logout\">Logout</a><br>");
await context.Response.WriteAsync("</body></html>"); await context.Response.WriteAsync("</body></html>");
}); });

View File

@ -1,9 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Builder
{ {
@ -13,38 +12,26 @@ namespace Microsoft.AspNetCore.Builder
public static class CookieAppBuilderExtensions public static class CookieAppBuilderExtensions
{ {
/// <summary> /// <summary>
/// Adds the <see cref="CookieAuthenticationMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables cookie authentication capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseCookieAuthentication(this IApplicationBuilder app) public static IApplicationBuilder UseCookieAuthentication(this IApplicationBuilder app)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<CookieAuthenticationMiddleware>();
} }
/// <summary> /// <summary>
/// Adds the <see cref="CookieAuthenticationMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables cookie authentication capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <param name="options">A <see cref="CookieAuthenticationOptions"/> that specifies options for the middleware.</param> /// <param name="options">A <see cref="CookieAuthenticationOptions"/> that specifies options for the handler.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseCookieAuthentication(this IApplicationBuilder app, CookieAuthenticationOptions options) public static IApplicationBuilder UseCookieAuthentication(this IApplicationBuilder app, CookieAuthenticationOptions options)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
return app.UseMiddleware<CookieAuthenticationMiddleware>(Options.Create(options));
} }
} }
} }

View File

@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authentication.Cookies namespace Microsoft.AspNetCore.Authentication.Cookies
{ {
/// <summary> /// <summary>
/// Default values related to cookie-based authentication middleware /// Default values related to cookie-based authentication handler
/// </summary> /// </summary>
public static class CookieAuthenticationDefaults public static class CookieAuthenticationDefaults
{ {

View File

@ -1,32 +1,97 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Authentication.Cookies namespace Microsoft.AspNetCore.Authentication.Cookies
{ {
internal class CookieAuthenticationHandler : AuthenticationHandler<CookieAuthenticationOptions> public class CookieAuthenticationHandler : AuthenticationHandler<CookieAuthenticationOptions>
{ {
private const string HeaderValueNoCache = "no-cache"; private const string HeaderValueNoCache = "no-cache";
private const string HeaderValueMinusOne = "-1"; private const string HeaderValueMinusOne = "-1";
private const string SessionIdClaim = "Microsoft.AspNetCore.Authentication.Cookies-SessionId"; private const string SessionIdClaim = "Microsoft.AspNetCore.Authentication.Cookies-SessionId";
private bool _shouldRefresh; private bool _shouldRefresh;
private bool _signInCalled;
private bool _signOutCalled;
private DateTimeOffset? _refreshIssuedUtc; private DateTimeOffset? _refreshIssuedUtc;
private DateTimeOffset? _refreshExpiresUtc; private DateTimeOffset? _refreshExpiresUtc;
private string _sessionKey; private string _sessionKey;
private Task<AuthenticateResult> _readCookieTask; private Task<AuthenticateResult> _readCookieTask;
public CookieAuthenticationHandler(IOptionsSnapshot<CookieAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{ }
/// <summary>
/// The handler calls methods on the events which give the application control at certain points where processing is occurring.
/// If it is not provided a default instance is supplied which does nothing when the methods are called.
/// </summary>
protected new CookieAuthenticationEvents Events
{
get { return (CookieAuthenticationEvents)base.Events; }
set { base.Events = value; }
}
protected override Task InitializeHandlerAsync()
{
// Cookies needs to finish the response
Context.Response.OnStarting(FinishResponseAsync);
return TaskCache.CompletedTask;
}
/// <summary>
/// Creates a new instance of the events instance.
/// </summary>
/// <returns>A new instance of the events instance.</returns>
protected override Task<object> CreateEventsAsync() => Task.FromResult<object>(new CookieAuthenticationEvents());
protected override void InitializeOptions()
{
base.InitializeOptions();
if (String.IsNullOrEmpty(Options.CookieName))
{
Options.CookieName = CookieAuthenticationDefaults.CookiePrefix + Scheme.Name;
}
if (Options.TicketDataFormat == null)
{
var provider = Options.DataProtectionProvider ?? Context.RequestServices.GetRequiredService<IDataProtectionProvider>();
// Note: the purpose for the data protector must remain fixed for interop to work.
var dataProtector = provider.CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", Scheme.Name, "v2");
Options.TicketDataFormat = new TicketDataFormat(dataProtector);
}
if (Options.CookieManager == null)
{
Options.CookieManager = new ChunkingCookieManager();
}
if (!Options.LoginPath.HasValue)
{
Options.LoginPath = CookieAuthenticationDefaults.LoginPath;
}
if (!Options.LogoutPath.HasValue)
{
Options.LogoutPath = CookieAuthenticationDefaults.LogoutPath;
}
if (!Options.AccessDeniedPath.HasValue)
{
Options.AccessDeniedPath = CookieAuthenticationDefaults.AccessDeniedPath;
}
}
private Task<AuthenticateResult> EnsureCookieTicket() private Task<AuthenticateResult> EnsureCookieTicket()
{ {
// We only need to read the ticket once // We only need to read the ticket once
@ -39,7 +104,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
private void CheckForRefresh(AuthenticationTicket ticket) private void CheckForRefresh(AuthenticationTicket ticket)
{ {
var currentUtc = Options.SystemClock.UtcNow; var currentUtc = Clock.UtcNow;
var issuedUtc = ticket.Properties.IssuedUtc; var issuedUtc = ticket.Properties.IssuedUtc;
var expiresUtc = ticket.Properties.ExpiresUtc; var expiresUtc = ticket.Properties.ExpiresUtc;
var allowRefresh = ticket.Properties.AllowRefresh ?? true; var allowRefresh = ticket.Properties.AllowRefresh ?? true;
@ -63,7 +128,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
if (issuedUtc != null && expiresUtc != null) if (issuedUtc != null && expiresUtc != null)
{ {
_shouldRefresh = true; _shouldRefresh = true;
var currentUtc = Options.SystemClock.UtcNow; var currentUtc = Clock.UtcNow;
_refreshIssuedUtc = currentUtc; _refreshIssuedUtc = currentUtc;
var timeSpan = expiresUtc.Value.Subtract(issuedUtc.Value); var timeSpan = expiresUtc.Value.Subtract(issuedUtc.Value);
_refreshExpiresUtc = currentUtc.Add(timeSpan); _refreshExpiresUtc = currentUtc.Add(timeSpan);
@ -75,7 +140,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
var cookie = Options.CookieManager.GetRequestCookie(Context, Options.CookieName); var cookie = Options.CookieManager.GetRequestCookie(Context, Options.CookieName);
if (string.IsNullOrEmpty(cookie)) if (string.IsNullOrEmpty(cookie))
{ {
return AuthenticateResult.Skip(); return AuthenticateResult.None();
} }
var ticket = Options.TicketDataFormat.Unprotect(cookie, GetTlsTokenBinding()); var ticket = Options.TicketDataFormat.Unprotect(cookie, GetTlsTokenBinding());
@ -99,7 +164,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
} }
} }
var currentUtc = Options.SystemClock.UtcNow; var currentUtc = Clock.UtcNow;
var issuedUtc = ticket.Properties.IssuedUtc; var issuedUtc = ticket.Properties.IssuedUtc;
var expiresUtc = ticket.Properties.ExpiresUtc; var expiresUtc = ticket.Properties.ExpiresUtc;
@ -126,8 +191,8 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
return result; return result;
} }
var context = new CookieValidatePrincipalContext(Context, result.Ticket, Options); var context = new CookieValidatePrincipalContext(Context, Scheme, result.Ticket, Options);
await Options.Events.ValidatePrincipal(context); await Events.ValidatePrincipal(context);
if (context.Principal == null) if (context.Principal == null)
{ {
@ -139,7 +204,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
RequestRefresh(result.Ticket); RequestRefresh(result.Ticket);
} }
return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme)); return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name));
} }
private CookieOptions BuildCookieOptions() private CookieOptions BuildCookieOptions()
@ -163,10 +228,10 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
return cookieOptions; return cookieOptions;
} }
protected override async Task FinishResponseAsync() protected virtual async Task FinishResponseAsync()
{ {
// Only renew if requested, and neither sign in or sign out was called // Only renew if requested, and neither sign in or sign out was called
if (!_shouldRefresh || SignInAccepted || SignOutAccepted) if (!_shouldRefresh || _signInCalled || _signOutCalled)
{ {
return; return;
} }
@ -192,8 +257,8 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
var principal = new ClaimsPrincipal( var principal = new ClaimsPrincipal(
new ClaimsIdentity( new ClaimsIdentity(
new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) }, new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) },
Options.AuthenticationScheme)); Scheme.Name));
ticket = new AuthenticationTicket(principal, null, Options.AuthenticationScheme); ticket = new AuthenticationTicket(principal, null, Scheme.Name);
} }
var cookieValue = Options.TicketDataFormat.Protect(ticket, GetTlsTokenBinding()); var cookieValue = Options.TicketDataFormat.Protect(ticket, GetTlsTokenBinding());
@ -216,16 +281,18 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
protected override async Task HandleSignInAsync(SignInContext signin) protected override async Task HandleSignInAsync(SignInContext signin)
{ {
_signInCalled = true;
// Process the request cookie to initialize members like _sessionKey. // Process the request cookie to initialize members like _sessionKey.
var result = await EnsureCookieTicket(); var result = await EnsureCookieTicket();
var cookieOptions = BuildCookieOptions(); var cookieOptions = BuildCookieOptions();
var signInContext = new CookieSigningInContext( var signInContext = new CookieSigningInContext(
Context, Context,
Scheme,
Options, Options,
Options.AuthenticationScheme,
signin.Principal, signin.Principal,
new AuthenticationProperties(signin.Properties), signin.Properties,
cookieOptions); cookieOptions);
DateTimeOffset issuedUtc; DateTimeOffset issuedUtc;
@ -235,7 +302,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
} }
else else
{ {
issuedUtc = Options.SystemClock.UtcNow; issuedUtc = Clock.UtcNow;
signInContext.Properties.IssuedUtc = issuedUtc; signInContext.Properties.IssuedUtc = issuedUtc;
} }
@ -244,7 +311,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
signInContext.Properties.ExpiresUtc = issuedUtc.Add(Options.ExpireTimeSpan); signInContext.Properties.ExpiresUtc = issuedUtc.Add(Options.ExpireTimeSpan);
} }
await Options.Events.SigningIn(signInContext); await Events.SigningIn(signInContext);
if (signInContext.Properties.IsPersistent) if (signInContext.Properties.IsPersistent)
{ {
@ -264,7 +331,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
new ClaimsIdentity( new ClaimsIdentity(
new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) }, new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) },
Options.ClaimsIssuer)); Options.ClaimsIssuer));
ticket = new AuthenticationTicket(principal, null, Options.AuthenticationScheme); ticket = new AuthenticationTicket(principal, null, Scheme.Name);
} }
var cookieValue = Options.TicketDataFormat.Protect(ticket, GetTlsTokenBinding()); var cookieValue = Options.TicketDataFormat.Protect(ticket, GetTlsTokenBinding());
@ -277,12 +344,13 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
var signedInContext = new CookieSignedInContext( var signedInContext = new CookieSignedInContext(
Context, Context,
Scheme,
Options, Options,
Options.AuthenticationScheme, Scheme.Name,
signInContext.Principal, signInContext.Principal,
signInContext.Properties); signInContext.Properties);
await Options.Events.SignedIn(signedInContext); await Events.SignedIn(signedInContext);
// Only redirect on the login path // Only redirect on the login path
var shouldRedirect = Options.LoginPath.HasValue && OriginalPath == Options.LoginPath; var shouldRedirect = Options.LoginPath.HasValue && OriginalPath == Options.LoginPath;
@ -291,6 +359,8 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
protected override async Task HandleSignOutAsync(SignOutContext signOutContext) protected override async Task HandleSignOutAsync(SignOutContext signOutContext)
{ {
_signOutCalled = true;
// Process the request cookie to initialize members like _sessionKey. // Process the request cookie to initialize members like _sessionKey.
var ticket = await EnsureCookieTicket(); var ticket = await EnsureCookieTicket();
var cookieOptions = BuildCookieOptions(); var cookieOptions = BuildCookieOptions();
@ -301,11 +371,12 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
var context = new CookieSigningOutContext( var context = new CookieSigningOutContext(
Context, Context,
Scheme,
Options, Options,
new AuthenticationProperties(signOutContext.Properties), signOutContext.Properties,
cookieOptions); cookieOptions);
await Options.Events.SigningOut(context); await Events.SigningOut(context);
Options.CookieManager.DeleteCookie( Options.CookieManager.DeleteCookie(
Context, Context,
@ -343,8 +414,8 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
if (redirectUri != null) if (redirectUri != null)
{ {
await Options.Events.RedirectToReturnUrl( await Events.RedirectToReturnUrl(
new CookieRedirectContext(Context, Options, redirectUri, properties)); new CookieRedirectContext(Context, Scheme, Options, redirectUri, properties));
} }
} }
} }
@ -362,28 +433,27 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
return path[0] == '/' && path[1] != '/' && path[1] != '\\'; return path[0] == '/' && path[1] != '/' && path[1] != '\\';
} }
protected override async Task<bool> HandleForbiddenAsync(ChallengeContext context) protected override async Task HandleForbiddenAsync(ChallengeContext context)
{ {
var properties = new AuthenticationProperties(context.Properties); var properties = context.Properties;
var returnUrl = properties.RedirectUri; var returnUrl = properties.RedirectUri;
if (string.IsNullOrEmpty(returnUrl)) if (string.IsNullOrEmpty(returnUrl))
{ {
returnUrl = OriginalPathBase + Request.Path + Request.QueryString; returnUrl = OriginalPathBase + Request.Path + Request.QueryString;
} }
var accessDeniedUri = Options.AccessDeniedPath + QueryString.Create(Options.ReturnUrlParameter, returnUrl); var accessDeniedUri = Options.AccessDeniedPath + QueryString.Create(Options.ReturnUrlParameter, returnUrl);
var redirectContext = new CookieRedirectContext(Context, Options, BuildRedirectUri(accessDeniedUri), properties); var redirectContext = new CookieRedirectContext(Context, Scheme, Options, BuildRedirectUri(accessDeniedUri), properties);
await Options.Events.RedirectToAccessDenied(redirectContext); await Events.RedirectToAccessDenied(redirectContext);
return true;
} }
protected override async Task<bool> HandleUnauthorizedAsync(ChallengeContext context) protected override async Task HandleUnauthorizedAsync(ChallengeContext context)
{ {
if (context == null) if (context == null)
{ {
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
var properties = new AuthenticationProperties(context.Properties); var properties = context.Properties;
var redirectUri = properties.RedirectUri; var redirectUri = properties.RedirectUri;
if (string.IsNullOrEmpty(redirectUri)) if (string.IsNullOrEmpty(redirectUri))
{ {
@ -391,10 +461,8 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
} }
var loginUri = Options.LoginPath + QueryString.Create(Options.ReturnUrlParameter, redirectUri); var loginUri = Options.LoginPath + QueryString.Create(Options.ReturnUrlParameter, redirectUri);
var redirectContext = new CookieRedirectContext(Context, Options, BuildRedirectUri(loginUri), properties); var redirectContext = new CookieRedirectContext(Context, Scheme, Options, BuildRedirectUri(loginUri), properties);
await Options.Events.RedirectToLogin(redirectContext); await Events.RedirectToLogin(redirectContext);
return true;
} }
private string GetTlsTokenBinding() private string GetTlsTokenBinding()

View File

@ -1,66 +0,0 @@
// 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.Text.Encodings.Web;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Authentication.Cookies
{
public class CookieAuthenticationMiddleware : AuthenticationMiddleware<CookieAuthenticationOptions>
{
public CookieAuthenticationMiddleware(
RequestDelegate next,
IDataProtectionProvider dataProtectionProvider,
ILoggerFactory loggerFactory,
UrlEncoder urlEncoder,
IOptions<CookieAuthenticationOptions> options)
: base(next, options, loggerFactory, urlEncoder)
{
if (dataProtectionProvider == null)
{
throw new ArgumentNullException(nameof(dataProtectionProvider));
}
if (Options.Events == null)
{
Options.Events = new CookieAuthenticationEvents();
}
if (String.IsNullOrEmpty(Options.CookieName))
{
Options.CookieName = CookieAuthenticationDefaults.CookiePrefix + Options.AuthenticationScheme;
}
if (Options.TicketDataFormat == null)
{
var provider = Options.DataProtectionProvider ?? dataProtectionProvider;
var dataProtector = provider.CreateProtector(typeof(CookieAuthenticationMiddleware).FullName, Options.AuthenticationScheme, "v2");
Options.TicketDataFormat = new TicketDataFormat(dataProtector);
}
if (Options.CookieManager == null)
{
Options.CookieManager = new ChunkingCookieManager();
}
if (!Options.LoginPath.HasValue)
{
Options.LoginPath = CookieAuthenticationDefaults.LoginPath;
}
if (!Options.LogoutPath.HasValue)
{
Options.LogoutPath = CookieAuthenticationDefaults.LogoutPath;
}
if (!Options.AccessDeniedPath.HasValue)
{
Options.AccessDeniedPath = CookieAuthenticationDefaults.AccessDeniedPath;
}
}
protected override AuthenticationHandler<CookieAuthenticationOptions> CreateHandler()
{
return new CookieAuthenticationHandler();
}
}
}

View File

@ -2,19 +2,15 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.ComponentModel;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Authentication.Cookies
{ {
/// <summary> /// <summary>
/// Configuration options for <see cref="CookieAuthenticationMiddleware"/>. /// Configuration options for <see cref="CookieAuthenticationOptions"/>.
/// </summary> /// </summary>
public class CookieAuthenticationOptions : AuthenticationOptions, IOptions<CookieAuthenticationOptions> public class CookieAuthenticationOptions : AuthenticationSchemeOptions
{ {
private string _cookieName; private string _cookieName;
@ -23,21 +19,18 @@ namespace Microsoft.AspNetCore.Builder
/// </summary> /// </summary>
public CookieAuthenticationOptions() public CookieAuthenticationOptions()
{ {
AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme;
AutomaticAuthenticate = true;
ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter; ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
ExpireTimeSpan = TimeSpan.FromDays(14); ExpireTimeSpan = TimeSpan.FromDays(14);
SlidingExpiration = true; SlidingExpiration = true;
CookieHttpOnly = true; CookieHttpOnly = true;
CookieSecure = CookieSecurePolicy.SameAsRequest; CookieSecure = CookieSecurePolicy.SameAsRequest;
SystemClock = new SystemClock();
Events = new CookieAuthenticationEvents(); Events = new CookieAuthenticationEvents();
} }
/// <summary> /// <summary>
/// Determines the cookie name used to persist the identity. The default value is ".AspNetCore.Cookies". /// Determines the cookie name used to persist the identity. The default value is ".AspNetCore.Cookies".
/// This value should be changed if you change the name of the AuthenticationScheme, especially if your /// This value should be changed if you change the name of the AuthenticationScheme, especially if your
/// system uses the cookie authentication middleware multiple times. /// system uses the cookie authentication handler multiple times.
/// </summary> /// </summary>
public string CookieName public string CookieName
{ {
@ -90,13 +83,13 @@ namespace Microsoft.AspNetCore.Builder
public TimeSpan ExpireTimeSpan { get; set; } public TimeSpan ExpireTimeSpan { get; set; }
/// <summary> /// <summary>
/// The SlidingExpiration is set to true to instruct the middleware to re-issue a new cookie with a new /// The SlidingExpiration is set to true to instruct the handler to re-issue a new cookie with a new
/// expiration time any time it processes a request which is more than halfway through the expiration window. /// expiration time any time it processes a request which is more than halfway through the expiration window.
/// </summary> /// </summary>
public bool SlidingExpiration { get; set; } public bool SlidingExpiration { get; set; }
/// <summary> /// <summary>
/// The LoginPath property informs the middleware that it should change an outgoing 401 Unauthorized status /// The LoginPath property informs the handler that it should change an outgoing 401 Unauthorized status
/// code into a 302 redirection onto the given login path. The current url which generated the 401 is added /// code into a 302 redirection onto the given login path. The current url which generated the 401 is added
/// to the LoginPath as a query string parameter named by the ReturnUrlParameter. Once a request to the /// to the LoginPath as a query string parameter named by the ReturnUrlParameter. Once a request to the
/// LoginPath grants a new SignIn identity, the ReturnUrlParameter value is used to redirect the browser back /// LoginPath grants a new SignIn identity, the ReturnUrlParameter value is used to redirect the browser back
@ -105,18 +98,18 @@ namespace Microsoft.AspNetCore.Builder
public PathString LoginPath { get; set; } public PathString LoginPath { get; set; }
/// <summary> /// <summary>
/// If the LogoutPath is provided the middleware then a request to that path will redirect based on the ReturnUrlParameter. /// If the LogoutPath is provided the handler then a request to that path will redirect based on the ReturnUrlParameter.
/// </summary> /// </summary>
public PathString LogoutPath { get; set; } public PathString LogoutPath { get; set; }
/// <summary> /// <summary>
/// The AccessDeniedPath property informs the middleware that it should change an outgoing 403 Forbidden status /// The AccessDeniedPath property informs the handler that it should change an outgoing 403 Forbidden status
/// code into a 302 redirection onto the given path. /// code into a 302 redirection onto the given path.
/// </summary> /// </summary>
public PathString AccessDeniedPath { get; set; } public PathString AccessDeniedPath { get; set; }
/// <summary> /// <summary>
/// The ReturnUrlParameter determines the name of the query string parameter which is appended by the middleware /// The ReturnUrlParameter determines the name of the query string parameter which is appended by the handler
/// when a 401 Unauthorized status code is changed to a 302 redirect onto the login path. This is also the query /// when a 401 Unauthorized status code is changed to a 302 redirect onto the login path. This is also the query
/// string parameter looked for when a request arrives on the login path or logout path, in order to return to the /// string parameter looked for when a request arrives on the login path or logout path, in order to return to the
/// original url after the action is performed. /// original url after the action is performed.
@ -124,11 +117,15 @@ namespace Microsoft.AspNetCore.Builder
public string ReturnUrlParameter { get; set; } public string ReturnUrlParameter { get; set; }
/// <summary> /// <summary>
/// The Provider may be assigned to an instance of an object created by the application at startup time. The middleware /// The Provider may be assigned to an instance of an object created by the application at startup time. The handler
/// calls methods on the provider which give the application control at certain points where processing is occurring. /// calls methods on the provider which give the application control at certain points where processing is occurring.
/// If it is not provided a default instance is supplied which does nothing when the methods are called. /// If it is not provided a default instance is supplied which does nothing when the methods are called.
/// </summary> /// </summary>
public ICookieAuthenticationEvents Events { get; set; } public new CookieAuthenticationEvents Events
{
get { return (CookieAuthenticationEvents)base.Events; }
set { base.Events = value; }
}
/// <summary> /// <summary>
/// The TicketDataFormat is used to protect and unprotect the identity and other properties which are stored in the /// The TicketDataFormat is used to protect and unprotect the identity and other properties which are stored in the
@ -150,13 +147,5 @@ namespace Microsoft.AspNetCore.Builder
/// to the client. This can be used to mitigate potential problems with very large identities. /// to the client. This can be used to mitigate potential problems with very large identities.
/// </summary> /// </summary>
public ITicketStore SessionStore { get; set; } public ITicketStore SessionStore { get; set; }
CookieAuthenticationOptions IOptions<CookieAuthenticationOptions>.Value
{
get
{
return this;
}
}
} }
} }

View File

@ -0,0 +1,21 @@
// 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 Microsoft.AspNetCore.Authentication.Cookies;
namespace Microsoft.Extensions.DependencyInjection
{
public static class CookieExtensions
{
public static IServiceCollection AddCookieAuthentication(this IServiceCollection services) => services.AddCookieAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
public static IServiceCollection AddCookieAuthentication(this IServiceCollection services, string authenticationScheme) => services.AddCookieAuthentication(authenticationScheme, configureOptions: null);
public static IServiceCollection AddCookieAuthentication(this IServiceCollection services, Action<CookieAuthenticationOptions> configureOptions) =>
services.AddCookieAuthentication(CookieAuthenticationDefaults.AuthenticationScheme, configureOptions);
public static IServiceCollection AddCookieAuthentication(this IServiceCollection services, string authenticationScheme, Action<CookieAuthenticationOptions> configureOptions) =>
services.AddScheme<CookieAuthenticationOptions, CookieAuthenticationHandler>(authenticationScheme, configureOptions);
}
}

View File

@ -2,17 +2,18 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authentication.Cookies namespace Microsoft.AspNetCore.Authentication.Cookies
{ {
public class BaseCookieContext : BaseContext public class BaseCookieContext : BaseAuthenticationContext
{ {
public BaseCookieContext( public BaseCookieContext(
HttpContext context, HttpContext context,
CookieAuthenticationOptions options) AuthenticationScheme scheme,
: base(context) CookieAuthenticationOptions options,
AuthenticationProperties properties)
: base(context, scheme.Name, properties)
{ {
if (options == null) if (options == null)
{ {
@ -23,5 +24,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
} }
public CookieAuthenticationOptions Options { get; } public CookieAuthenticationOptions Options { get; }
public AuthenticationScheme Scheme { get; }
} }
} }

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
/// application only needs to override a few of the interface methods. This may be used as a base class /// application only needs to override a few of the interface methods. This may be used as a base class
/// or may be instantiated directly. /// or may be instantiated directly.
/// </summary> /// </summary>
public class CookieAuthenticationEvents : ICookieAuthenticationEvents public class CookieAuthenticationEvents
{ {
/// <summary> /// <summary>
/// A delegate assigned to this property will be invoked when the related method is called. /// A delegate assigned to this property will be invoked when the related method is called.

View File

@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Http.Authentication;
namespace Microsoft.AspNetCore.Authentication.Cookies namespace Microsoft.AspNetCore.Authentication.Cookies
{ {
/// <summary> /// <summary>
/// Context passed when a Challenge, SignIn, or SignOut causes a redirect in the cookie middleware /// Context passed when a Challenge, SignIn, or SignOut causes a redirect in the cookie handler
/// </summary> /// </summary>
public class CookieRedirectContext : BaseCookieContext public class CookieRedirectContext : BaseCookieContext
{ {
@ -16,21 +16,19 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
/// Creates a new context object. /// Creates a new context object.
/// </summary> /// </summary>
/// <param name="context">The HTTP request context</param> /// <param name="context">The HTTP request context</param>
/// <param name="options">The cookie middleware options</param> /// <param name="scheme">The scheme data</param>
/// <param name="options">The cookie handler options</param>
/// <param name="redirectUri">The initial redirect URI</param> /// <param name="redirectUri">The initial redirect URI</param>
/// <param name="properties">The <see cref="AuthenticationProperties"/>.</param> /// <param name="properties">The <see cref="AuthenticationProperties"/>.</param>
public CookieRedirectContext(HttpContext context, CookieAuthenticationOptions options, string redirectUri, AuthenticationProperties properties) public CookieRedirectContext(HttpContext context, AuthenticationScheme scheme, CookieAuthenticationOptions options, string redirectUri, AuthenticationProperties properties)
: base(context, options) : base(context, scheme, options, properties)
{ {
RedirectUri = redirectUri; RedirectUri = redirectUri;
Properties = properties;
} }
/// <summary> /// <summary>
/// Gets or Sets the URI used for the redirect operation. /// Gets or Sets the URI used for the redirect operation.
/// </summary> /// </summary>
public string RedirectUri { get; set; } public string RedirectUri { get; set; }
public AuthenticationProperties Properties { get; }
} }
} }

View File

@ -2,9 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
namespace Microsoft.AspNetCore.Authentication.Cookies namespace Microsoft.AspNetCore.Authentication.Cookies
{ {
@ -17,36 +15,26 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
/// Creates a new instance of the context object. /// Creates a new instance of the context object.
/// </summary> /// </summary>
/// <param name="context">The HTTP request context</param> /// <param name="context">The HTTP request context</param>
/// <param name="options">The middleware options</param> /// <param name="scheme">The scheme data</param>
/// <param name="options">The handler options</param>
/// <param name="authenticationScheme">Initializes AuthenticationScheme property</param> /// <param name="authenticationScheme">Initializes AuthenticationScheme property</param>
/// <param name="principal">Initializes Principal property</param> /// <param name="principal">Initializes Principal property</param>
/// <param name="properties">Initializes Properties property</param> /// <param name="properties">Initializes Properties property</param>
public CookieSignedInContext( public CookieSignedInContext(
HttpContext context, HttpContext context,
AuthenticationScheme scheme,
CookieAuthenticationOptions options, CookieAuthenticationOptions options,
string authenticationScheme, string authenticationScheme,
ClaimsPrincipal principal, ClaimsPrincipal principal,
AuthenticationProperties properties) AuthenticationProperties properties)
: base(context, options) : base(context, scheme, options, properties)
{ {
AuthenticationScheme = authenticationScheme;
Principal = principal; Principal = principal;
Properties = properties;
} }
/// <summary>
/// The name of the AuthenticationScheme creating a cookie
/// </summary>
public string AuthenticationScheme { get; }
/// <summary> /// <summary>
/// Contains the claims that were converted into the outgoing cookie. /// Contains the claims that were converted into the outgoing cookie.
/// </summary> /// </summary>
public ClaimsPrincipal Principal { get; } public ClaimsPrincipal Principal { get; }
/// <summary>
/// Contains the extra data that was contained in the outgoing cookie.
/// </summary>
public AuthenticationProperties Properties { get; }
} }
} }

View File

@ -2,9 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
namespace Microsoft.AspNetCore.Authentication.Cookies namespace Microsoft.AspNetCore.Authentication.Cookies
{ {
@ -17,43 +15,30 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
/// Creates a new instance of the context object. /// Creates a new instance of the context object.
/// </summary> /// </summary>
/// <param name="context">The HTTP request context</param> /// <param name="context">The HTTP request context</param>
/// <param name="options">The middleware options</param> /// <param name="scheme">The scheme data</param>
/// <param name="authenticationScheme">Initializes AuthenticationScheme property</param> /// <param name="options">The handler options</param>
/// <param name="principal">Initializes Principal property</param> /// <param name="principal">Initializes Principal property</param>
/// <param name="properties">Initializes Extra property</param> /// <param name="properties">Initializes Extra property</param>
/// <param name="cookieOptions">Initializes options for the authentication cookie.</param> /// <param name="cookieOptions">Initializes options for the authentication cookie.</param>
public CookieSigningInContext( public CookieSigningInContext(
HttpContext context, HttpContext context,
AuthenticationScheme scheme,
CookieAuthenticationOptions options, CookieAuthenticationOptions options,
string authenticationScheme,
ClaimsPrincipal principal, ClaimsPrincipal principal,
AuthenticationProperties properties, AuthenticationProperties properties,
CookieOptions cookieOptions) CookieOptions cookieOptions)
: base(context, options) : base(context, scheme, options, properties)
{ {
AuthenticationScheme = authenticationScheme;
Principal = principal; Principal = principal;
Properties = properties;
CookieOptions = cookieOptions; CookieOptions = cookieOptions;
} }
/// <summary>
/// The name of the AuthenticationScheme creating a cookie
/// </summary>
public string AuthenticationScheme { get; }
/// <summary> /// <summary>
/// Contains the claims about to be converted into the outgoing cookie. /// Contains the claims about to be converted into the outgoing cookie.
/// May be replaced or altered during the SigningIn call. /// May be replaced or altered during the SigningIn call.
/// </summary> /// </summary>
public ClaimsPrincipal Principal { get; set; } public ClaimsPrincipal Principal { get; set; }
/// <summary>
/// Contains the extra data about to be contained in the outgoing cookie.
/// May be replaced or altered during the SigningIn call.
/// </summary>
public AuthenticationProperties Properties { get; set; }
/// <summary> /// <summary>
/// The options for creating the outgoing cookie. /// The options for creating the outgoing cookie.
/// May be replace or altered during the SigningIn call. /// May be replace or altered during the SigningIn call.

View File

@ -1,9 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
namespace Microsoft.AspNetCore.Authentication.Cookies namespace Microsoft.AspNetCore.Authentication.Cookies
{ {
@ -16,18 +14,19 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
/// ///
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
/// <param name="scheme"></param>
/// <param name="options"></param> /// <param name="options"></param>
/// <param name="properties"></param> /// <param name="properties"></param>
/// <param name="cookieOptions"></param> /// <param name="cookieOptions"></param>
public CookieSigningOutContext( public CookieSigningOutContext(
HttpContext context, HttpContext context,
AuthenticationScheme scheme,
CookieAuthenticationOptions options, CookieAuthenticationOptions options,
AuthenticationProperties properties, AuthenticationProperties properties,
CookieOptions cookieOptions) CookieOptions cookieOptions)
: base(context, options) : base(context, scheme, options, properties)
{ {
CookieOptions = cookieOptions; CookieOptions = cookieOptions;
Properties = properties;
} }
/// <summary> /// <summary>
@ -35,7 +34,5 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
/// May be replace or altered during the SigningOut call. /// May be replace or altered during the SigningOut call.
/// </summary> /// </summary>
public CookieOptions CookieOptions { get; set; } public CookieOptions CookieOptions { get; set; }
public AuthenticationProperties Properties { get; set; }
} }
} }

View File

@ -3,14 +3,12 @@
using System; using System;
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
namespace Microsoft.AspNetCore.Authentication.Cookies namespace Microsoft.AspNetCore.Authentication.Cookies
{ {
/// <summary> /// <summary>
/// Context object passed to the ICookieAuthenticationProvider method ValidatePrincipal. /// Context object passed to the CookieAuthenticationEvents ValidatePrincipal method.
/// </summary> /// </summary>
public class CookieValidatePrincipalContext : BaseCookieContext public class CookieValidatePrincipalContext : BaseCookieContext
{ {
@ -18,10 +16,11 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
/// Creates a new instance of the context object. /// Creates a new instance of the context object.
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
/// <param name="scheme"></param>
/// <param name="ticket">Contains the initial values for identity and extra data</param> /// <param name="ticket">Contains the initial values for identity and extra data</param>
/// <param name="options"></param> /// <param name="options"></param>
public CookieValidatePrincipalContext(HttpContext context, AuthenticationTicket ticket, CookieAuthenticationOptions options) public CookieValidatePrincipalContext(HttpContext context, AuthenticationScheme scheme, AuthenticationTicket ticket, CookieAuthenticationOptions options)
: base(context, options) : base(context, scheme, options, ticket?.Properties)
{ {
if (context == null) if (context == null)
{ {
@ -39,7 +38,6 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
} }
Principal = ticket.Principal; Principal = ticket.Principal;
Properties = ticket.Properties;
} }
/// <summary> /// <summary>
@ -48,11 +46,6 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
/// </summary> /// </summary>
public ClaimsPrincipal Principal { get; private set; } public ClaimsPrincipal Principal { get; private set; }
/// <summary>
/// Contains the extra meta-data arriving with the request ticket. May be altered.
/// </summary>
public AuthenticationProperties Properties { get; private set; }
/// <summary> /// <summary>
/// If true, the cookie will be renewed /// If true, the cookie will be renewed
/// </summary> /// </summary>

View File

@ -1,64 +0,0 @@
// 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.Authentication.Cookies
{
/// <summary>
/// Specifies callback methods which the <see cref="CookieAuthenticationMiddleware"></see> invokes to enable developer control over the authentication process. />
/// </summary>
public interface ICookieAuthenticationEvents
{
/// <summary>
/// Called each time a request principal has been validated by the middleware. By implementing this method the
/// application may alter or reject the principal which has arrived with the request.
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
Task ValidatePrincipal(CookieValidatePrincipalContext context);
/// <summary>
/// Called when an endpoint has provided sign in information before it is converted into a cookie. By
/// implementing this method the claims and extra information that go into the ticket may be altered.
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
Task SigningIn(CookieSigningInContext context);
/// <summary>
/// Called when an endpoint has provided sign in information after it is converted into a cookie.
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
Task SignedIn(CookieSignedInContext context);
/// <summary>
/// Called when a SignOut causes a redirect in the cookie middleware.
/// </summary>
/// <param name="context">Contains information about the event</param>
Task RedirectToLogout(CookieRedirectContext context);
/// <summary>
/// Called when a SignIn causes a redirect in the cookie middleware.
/// </summary>
/// <param name="context">Contains information about the event</param>
Task RedirectToLogin(CookieRedirectContext context);
/// <summary>
/// Called when redirecting back to the return url in the cookie middleware.
/// </summary>
/// <param name="context">Contains information about the event</param>
Task RedirectToReturnUrl(CookieRedirectContext context);
/// <summary>
/// Called when an access denied causes a redirect in the cookie middleware.
/// </summary>
/// <param name="context">Contains information about the event</param>
Task RedirectToAccessDenied(CookieRedirectContext context);
/// <summary>
/// Called during the sign-out flow to augment the cookie cleanup process.
/// </summary>
/// <param name="context">Contains information about the login session as well as information about the authentication cookie.</param>
Task SigningOut(CookieSigningOutContext context);
}
}

View File

@ -17,9 +17,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.csproj" /> <ProjectReference Include="..\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.csproj" />
<PackageReference Include="Microsoft.Extensions.Options" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" /> <PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.WebEncoders" Version="$(AspNetCoreVersion)" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,9 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.Authentication.Facebook; using Microsoft.AspNetCore.Authentication.Facebook;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Builder
{ {
@ -13,38 +12,26 @@ namespace Microsoft.AspNetCore.Builder
public static class FacebookAppBuilderExtensions public static class FacebookAppBuilderExtensions
{ {
/// <summary> /// <summary>
/// Adds the <see cref="FacebookMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables Facebook authentication capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseFacebookAuthentication(this IApplicationBuilder app) public static IApplicationBuilder UseFacebookAuthentication(this IApplicationBuilder app)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<FacebookMiddleware>();
} }
/// <summary> /// <summary>
/// Adds the <see cref="FacebookMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables Facebook authentication capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <param name="options">A <see cref="FacebookOptions"/> that specifies options for the middleware.</param> /// <param name="options">A <see cref="FacebookOptions"/> that specifies options for the handler.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseFacebookAuthentication(this IApplicationBuilder app, FacebookOptions options) public static IApplicationBuilder UseFacebookAuthentication(this IApplicationBuilder app, FacebookOptions options)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
return app.UseMiddleware<FacebookMiddleware>(Options.Create(options));
} }
} }
} }

View File

@ -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 Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Authentication.Facebook
{
internal class FacebookConfigureOptions : ConfigureNamedOptions<FacebookOptions>
{
public FacebookConfigureOptions(IConfiguration config) :
base(FacebookDefaults.AuthenticationScheme,
options => config.GetSection(FacebookDefaults.AuthenticationScheme).Bind(options))
{ }
}
}

View File

@ -0,0 +1,32 @@
// 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 Microsoft.AspNetCore.Authentication.Facebook;
using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection
{
public static class FacebookAuthenticationOptionsExtensions
{
/// <summary>
/// Adds facebook authentication with options bound against the "Facebook" section
/// from the IConfiguration in the service container.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddFacebookAuthentication(this IServiceCollection services)
{
services.AddSingleton<IConfigureOptions<FacebookOptions>, FacebookConfigureOptions>();
return services.AddFacebookAuthentication(FacebookDefaults.AuthenticationScheme, _ => { });
}
public static IServiceCollection AddFacebookAuthentication(this IServiceCollection services, Action<FacebookOptions> configureOptions)
=> services.AddFacebookAuthentication(FacebookDefaults.AuthenticationScheme, configureOptions);
public static IServiceCollection AddFacebookAuthentication(this IServiceCollection services, string authenticationScheme, Action<FacebookOptions> configureOptions)
{
return services.AddScheme<FacebookOptions, FacebookHandler>(authenticationScheme, configureOptions);
}
}
}

View File

@ -1,27 +1,27 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // 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.Globalization;
using System.Net.Http; using System.Net.Http;
using System.Security.Claims; using System.Security.Claims;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.OAuth; using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.WebUtilities; using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace Microsoft.AspNetCore.Authentication.Facebook namespace Microsoft.AspNetCore.Authentication.Facebook
{ {
internal class FacebookHandler : OAuthHandler<FacebookOptions> internal class FacebookHandler : OAuthHandler<FacebookOptions>
{ {
public FacebookHandler(HttpClient httpClient) public FacebookHandler(IOptions<AuthenticationOptions> sharedOptions, IOptionsSnapshot<FacebookOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
: base(httpClient) : base(sharedOptions, options, logger, encoder, dataProtection, clock)
{ { }
}
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens) protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
{ {
@ -43,11 +43,11 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
var payload = JObject.Parse(await response.Content.ReadAsStringAsync()); var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Options.AuthenticationScheme); var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Scheme.Name);
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload); var context = new OAuthCreatingTicketContext(ticket, Context, Scheme, Options, Backchannel, tokens, payload);
context.RunClaimActions(); context.RunClaimActions();
await Options.Events.CreatingTicket(context); await Events.CreatingTicket(context);
return context.Ticket; return context.Ticket;
} }

View File

@ -1,89 +0,0 @@
// 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.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Authentication.Facebook
{
/// <summary>
/// An ASP.NET Core middleware for authenticating users using Facebook.
/// </summary>
public class FacebookMiddleware : OAuthMiddleware<FacebookOptions>
{
/// <summary>
/// Initializes a new <see cref="FacebookMiddleware"/>.
/// </summary>
/// <param name="next">The next middleware in the HTTP pipeline to invoke.</param>
/// <param name="dataProtectionProvider"></param>
/// <param name="loggerFactory"></param>
/// <param name="encoder"></param>
/// <param name="sharedOptions"></param>
/// <param name="options">Configuration options for the middleware.</param>
public FacebookMiddleware(
RequestDelegate next,
IDataProtectionProvider dataProtectionProvider,
ILoggerFactory loggerFactory,
UrlEncoder encoder,
IOptions<SharedAuthenticationOptions> sharedOptions,
IOptions<FacebookOptions> options)
: base(next, dataProtectionProvider, loggerFactory, encoder, sharedOptions, options)
{
if (next == null)
{
throw new ArgumentNullException(nameof(next));
}
if (dataProtectionProvider == null)
{
throw new ArgumentNullException(nameof(dataProtectionProvider));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
if (encoder == null)
{
throw new ArgumentNullException(nameof(encoder));
}
if (sharedOptions == null)
{
throw new ArgumentNullException(nameof(sharedOptions));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
if (string.IsNullOrEmpty(Options.AppId))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.AppId)));
}
if (string.IsNullOrEmpty(Options.AppSecret))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.AppSecret)));
}
}
/// <summary>
/// Provides the <see cref="AuthenticationHandler{T}"/> object for processing authentication-related requests.
/// </summary>
/// <returns>An <see cref="AuthenticationHandler{T}"/> configured with the <see cref="FacebookOptions"/> supplied to the constructor.</returns>
protected override AuthenticationHandler<FacebookOptions> CreateHandler()
{
return new FacebookHandler(Backchannel);
}
}
}

View File

@ -1,16 +1,18 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // 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.Collections.Generic;
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Facebook; using System.Globalization;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Authentication.Facebook
{ {
/// <summary> /// <summary>
/// Configuration options for <see cref="FacebookMiddleware"/>. /// Configuration options for <see cref="FacebookHandler"/>.
/// </summary> /// </summary>
public class FacebookOptions : OAuthOptions public class FacebookOptions : OAuthOptions
{ {
@ -19,8 +21,6 @@ namespace Microsoft.AspNetCore.Builder
/// </summary> /// </summary>
public FacebookOptions() public FacebookOptions()
{ {
AuthenticationScheme = FacebookDefaults.AuthenticationScheme;
DisplayName = AuthenticationScheme;
CallbackPath = new PathString("/signin-facebook"); CallbackPath = new PathString("/signin-facebook");
SendAppSecretProof = true; SendAppSecretProof = true;
AuthorizationEndpoint = FacebookDefaults.AuthorizationEndpoint; AuthorizationEndpoint = FacebookDefaults.AuthorizationEndpoint;
@ -49,6 +49,24 @@ namespace Microsoft.AspNetCore.Builder
ClaimActions.MapJsonKey("urn:facebook:timezone", "timezone"); ClaimActions.MapJsonKey("urn:facebook:timezone", "timezone");
} }
/// <summary>
/// Check that the options are valid. Should throw an exception if things are not ok.
/// </summary>
public override void Validate()
{
if (string.IsNullOrEmpty(AppId))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(AppId)), nameof(AppId));
}
if (string.IsNullOrEmpty(AppSecret))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(AppSecret)), nameof(AppSecret));
}
base.Validate();
}
// Facebook uses a non-standard term for this field. // Facebook uses a non-standard term for this field.
/// <summary> /// <summary>
/// Gets or sets the Facebook-assigned appId. /// Gets or sets the Facebook-assigned appId.

View File

@ -13,6 +13,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" /> <ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(AspNetCoreVersion)" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -3,6 +3,8 @@
using System; using System;
using Microsoft.AspNetCore.Authentication.Google; using Microsoft.AspNetCore.Authentication.Google;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Builder
@ -13,41 +15,24 @@ namespace Microsoft.AspNetCore.Builder
public static class GoogleAppBuilderExtensions public static class GoogleAppBuilderExtensions
{ {
/// <summary> /// <summary>
/// Adds the <see cref="GoogleMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// which enables Google authentication capabilities.
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
public static IApplicationBuilder UseGoogleAuthentication(this IApplicationBuilder app) public static IApplicationBuilder UseGoogleAuthentication(this IApplicationBuilder app)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<GoogleMiddleware>();
} }
/// <summary> /// <summary>
/// Adds the <see cref="GoogleMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// which enables Google authentication capabilities.
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <param name="options">A <see cref="GoogleOptions"/> that specifies options for the middleware.</param> /// <param name="options">A <see cref="GoogleOptions"/> that specifies options for the handler.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
public static IApplicationBuilder UseGoogleAuthentication(this IApplicationBuilder app, GoogleOptions options) public static IApplicationBuilder UseGoogleAuthentication(this IApplicationBuilder app, GoogleOptions options)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
return app.UseMiddleware<GoogleMiddleware>(Options.Create(options));
} }
} }
} }

View File

@ -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 Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Authentication.Google
{
internal class GoogleConfigureOptions : ConfigureNamedOptions<GoogleOptions>
{
public GoogleConfigureOptions(IConfiguration config) :
base(GoogleDefaults.AuthenticationScheme,
options => config.GetSection(GoogleDefaults.AuthenticationScheme).Bind(options))
{ }
}
}

View File

@ -0,0 +1,32 @@
// 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 Microsoft.AspNetCore.Authentication.Google;
using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection
{
public static class GoogleExtensions
{
/// <summary>
/// Adds google authentication with options bound against the "Google" section
/// from the IConfiguration in the service container.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddGoogleAuthentication(this IServiceCollection services)
{
services.AddSingleton<IConfigureOptions<GoogleOptions>, GoogleConfigureOptions>();
return services.AddGoogleAuthentication(GoogleDefaults.AuthenticationScheme, _ => { });
}
public static IServiceCollection AddGoogleAuthentication(this IServiceCollection services, Action<GoogleOptions> configureOptions)
=> services.AddGoogleAuthentication(GoogleDefaults.AuthenticationScheme, configureOptions);
public static IServiceCollection AddGoogleAuthentication(this IServiceCollection services, string authenticationScheme, Action<GoogleOptions> configureOptions)
{
return services.AddScheme<GoogleOptions, GoogleHandler>(authenticationScheme, configureOptions);
}
}
}

View File

@ -6,21 +6,22 @@ using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Security.Claims; using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.OAuth; using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.WebUtilities; using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace Microsoft.AspNetCore.Authentication.Google namespace Microsoft.AspNetCore.Authentication.Google
{ {
internal class GoogleHandler : OAuthHandler<GoogleOptions> internal class GoogleHandler : OAuthHandler<GoogleOptions>
{ {
public GoogleHandler(HttpClient httpClient) public GoogleHandler(IOptions<AuthenticationOptions> sharedOptions, IOptionsSnapshot<GoogleOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
: base(httpClient) : base(sharedOptions, options, logger, encoder, dataProtection, clock)
{ { }
}
protected override async Task<AuthenticationTicket> CreateTicketAsync( protected override async Task<AuthenticationTicket> CreateTicketAsync(
ClaimsIdentity identity, ClaimsIdentity identity,
@ -40,11 +41,11 @@ namespace Microsoft.AspNetCore.Authentication.Google
var payload = JObject.Parse(await response.Content.ReadAsStringAsync()); var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
var principal = new ClaimsPrincipal(identity); var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme); var ticket = new AuthenticationTicket(principal, properties, Scheme.Name);
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload); var context = new OAuthCreatingTicketContext(ticket, Context, Scheme, Options, Backchannel, tokens, payload);
context.RunClaimActions(); context.RunClaimActions();
await Options.Events.CreatingTicket(context); await Events.CreatingTicket(context);
return context.Ticket; return context.Ticket;
} }

View File

@ -1,81 +0,0 @@
// 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.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Authentication.Google
{
/// <summary>
/// An ASP.NET Core middleware for authenticating users using Google OAuth 2.0.
/// </summary>
public class GoogleMiddleware : OAuthMiddleware<GoogleOptions>
{
/// <summary>
/// Initializes a new <see cref="GoogleMiddleware"/>.
/// </summary>
/// <param name="next">The next middleware in the HTTP pipeline to invoke.</param>
/// <param name="dataProtectionProvider"></param>
/// <param name="loggerFactory"></param>
/// <param name="encoder"></param>
/// <param name="sharedOptions"></param>
/// <param name="options">Configuration options for the middleware.</param>
public GoogleMiddleware(
RequestDelegate next,
IDataProtectionProvider dataProtectionProvider,
ILoggerFactory loggerFactory,
UrlEncoder encoder,
IOptions<SharedAuthenticationOptions> sharedOptions,
IOptions<GoogleOptions> options)
: base(next, dataProtectionProvider, loggerFactory, encoder, sharedOptions, options)
{
if (next == null)
{
throw new ArgumentNullException(nameof(next));
}
if (dataProtectionProvider == null)
{
throw new ArgumentNullException(nameof(dataProtectionProvider));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
if (encoder == null)
{
throw new ArgumentNullException(nameof(encoder));
}
if (sharedOptions == null)
{
throw new ArgumentNullException(nameof(sharedOptions));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
}
/// <summary>
/// Provides the <see cref="AuthenticationHandler{T}"/> object for processing authentication-related requests.
/// </summary>
/// <returns>
/// An <see cref="AuthenticationHandler{T}"/> configured with the <see cref="GoogleOptions"/>
/// supplied to the constructor.
/// </returns>
protected override AuthenticationHandler<GoogleOptions> CreateHandler()
{
return new GoogleHandler(Backchannel);
}
}
}

View File

@ -3,13 +3,13 @@
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Google; using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Authentication.Google
{ {
/// <summary> /// <summary>
/// Configuration options for <see cref="GoogleMiddleware"/>. /// Configuration options for <see cref="GoogleHandler"/>.
/// </summary> /// </summary>
public class GoogleOptions : OAuthOptions public class GoogleOptions : OAuthOptions
{ {
@ -18,8 +18,6 @@ namespace Microsoft.AspNetCore.Builder
/// </summary> /// </summary>
public GoogleOptions() public GoogleOptions()
{ {
AuthenticationScheme = GoogleDefaults.AuthenticationScheme;
DisplayName = AuthenticationScheme;
CallbackPath = new PathString("/signin-google"); CallbackPath = new PathString("/signin-google");
AuthorizationEndpoint = GoogleDefaults.AuthorizationEndpoint; AuthorizationEndpoint = GoogleDefaults.AuthorizationEndpoint;
TokenEndpoint = GoogleDefaults.TokenEndpoint; TokenEndpoint = GoogleDefaults.TokenEndpoint;

View File

@ -13,6 +13,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" /> <ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(AspNetCoreVersion)" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -2,15 +2,14 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authentication.JwtBearer namespace Microsoft.AspNetCore.Authentication.JwtBearer
{ {
public class AuthenticationFailedContext : BaseJwtBearerContext public class AuthenticationFailedContext : BaseJwtBearerContext
{ {
public AuthenticationFailedContext(HttpContext context, JwtBearerOptions options) public AuthenticationFailedContext(HttpContext context, AuthenticationScheme scheme, JwtBearerOptions options)
: base(context, options) : base(context, scheme, options)
{ {
} }

View File

@ -2,14 +2,13 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authentication.JwtBearer namespace Microsoft.AspNetCore.Authentication.JwtBearer
{ {
public class BaseJwtBearerContext : BaseControlContext public class BaseJwtBearerContext : BaseControlContext
{ {
public BaseJwtBearerContext(HttpContext context, JwtBearerOptions options) public BaseJwtBearerContext(HttpContext context, AuthenticationScheme scheme, JwtBearerOptions options)
: base(context) : base(context)
{ {
if (options == null) if (options == null)
@ -17,9 +16,17 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
throw new ArgumentNullException(nameof(options)); throw new ArgumentNullException(nameof(options));
} }
if (scheme == null)
{
throw new ArgumentNullException(nameof(scheme));
}
Options = options; Options = options;
Scheme = scheme;
} }
public JwtBearerOptions Options { get; } public JwtBearerOptions Options { get; }
public AuthenticationScheme Scheme { get; }
} }
} }

View File

@ -1,33 +0,0 @@
// 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.Authentication.JwtBearer
{
/// <summary>
/// Specifies events which the <see cref="JwtBearerMiddleware"/> invokes to enable developer control over the authentication process.
/// </summary>
public interface IJwtBearerEvents
{
/// <summary>
/// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed.
/// </summary>
Task AuthenticationFailed(AuthenticationFailedContext context);
/// <summary>
/// Invoked when a protocol message is first received.
/// </summary>
Task MessageReceived(MessageReceivedContext context);
/// <summary>
/// Invoked after the security token has passed validation and a ClaimsIdentity has been generated.
/// </summary>
Task TokenValidated(TokenValidatedContext context);
/// <summary>
/// Invoked to apply a challenge sent back to the caller.
/// </summary>
Task Challenge(JwtBearerChallengeContext context);
}
}

View File

@ -2,16 +2,14 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
namespace Microsoft.AspNetCore.Authentication.JwtBearer namespace Microsoft.AspNetCore.Authentication.JwtBearer
{ {
public class JwtBearerChallengeContext : BaseJwtBearerContext public class JwtBearerChallengeContext : BaseJwtBearerContext
{ {
public JwtBearerChallengeContext(HttpContext context, JwtBearerOptions options, AuthenticationProperties properties) public JwtBearerChallengeContext(HttpContext context, AuthenticationScheme scheme, JwtBearerOptions options, AuthenticationProperties properties)
: base(context, options) : base(context, scheme, options)
{ {
Properties = properties; Properties = properties;
} }

View File

@ -8,9 +8,9 @@ using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Authentication.JwtBearer namespace Microsoft.AspNetCore.Authentication.JwtBearer
{ {
/// <summary> /// <summary>
/// Specifies events which the <see cref="JwtBearerMiddleware"/> invokes to enable developer control over the authentication process. /// Specifies events which the <see cref="JwtBearerHandler"/> invokes to enable developer control over the authentication process.
/// </summary> /// </summary>
public class JwtBearerEvents : IJwtBearerEvents public class JwtBearerEvents
{ {
/// <summary> /// <summary>
/// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed. /// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed.

View File

@ -1,15 +1,14 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authentication.JwtBearer namespace Microsoft.AspNetCore.Authentication.JwtBearer
{ {
public class MessageReceivedContext : BaseJwtBearerContext public class MessageReceivedContext : BaseJwtBearerContext
{ {
public MessageReceivedContext(HttpContext context, JwtBearerOptions options) public MessageReceivedContext(HttpContext context, AuthenticationScheme scheme, JwtBearerOptions options)
: base(context, options) : base(context, scheme, options)
{ {
} }

View File

@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
@ -9,8 +8,8 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
{ {
public class TokenValidatedContext : BaseJwtBearerContext public class TokenValidatedContext : BaseJwtBearerContext
{ {
public TokenValidatedContext(HttpContext context, JwtBearerOptions options) public TokenValidatedContext(HttpContext context, AuthenticationScheme scheme, JwtBearerOptions options)
: base(context, options) : base(context, scheme, options)
{ {
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -13,50 +13,26 @@ namespace Microsoft.AspNetCore.Builder
public static class JwtBearerAppBuilderExtensions public static class JwtBearerAppBuilderExtensions
{ {
/// <summary> /// <summary>
/// Adds the <see cref="JwtBearerMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables Bearer token processing capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// This middleware understands appropriately
/// formatted and secured tokens which appear in the request header. If the Options.AuthenticationMode is Active, the
/// claims within the bearer token are added to the current request's IPrincipal User. If the Options.AuthenticationMode
/// is Passive, then the current request is not modified, but IAuthenticationManager AuthenticateAsync may be used at
/// any time to obtain the claims from the request's bearer token.
/// See also http://tools.ietf.org/html/rfc6749
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseJwtBearerAuthentication(this IApplicationBuilder app) public static IApplicationBuilder UseJwtBearerAuthentication(this IApplicationBuilder app)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<JwtBearerMiddleware>();
} }
/// <summary> /// <summary>
/// Adds the <see cref="JwtBearerMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables Bearer token processing capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// This middleware understands appropriately
/// formatted and secured tokens which appear in the request header. If the Options.AuthenticationMode is Active, the
/// claims within the bearer token are added to the current request's IPrincipal User. If the Options.AuthenticationMode
/// is Passive, then the current request is not modified, but IAuthenticationManager AuthenticateAsync may be used at
/// any time to obtain the claims from the request's bearer token.
/// See also http://tools.ietf.org/html/rfc6749
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <param name="options">A <see cref="JwtBearerOptions"/> that specifies options for the middleware.</param> /// <param name="options">A <see cref="JwtBearerOptions"/> that specifies options for the handler.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseJwtBearerAuthentication(this IApplicationBuilder app, JwtBearerOptions options) public static IApplicationBuilder UseJwtBearerAuthentication(this IApplicationBuilder app, JwtBearerOptions options)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
return app.UseMiddleware<JwtBearerMiddleware>(Options.Create(options));
} }
} }
} }

View File

@ -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 Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Authentication.JwtBearer
{
internal class JwtBearerConfigureOptions : ConfigureNamedOptions<JwtBearerOptions>
{
// Bind to "Bearer" section by default
public JwtBearerConfigureOptions(IConfiguration config) :
base(JwtBearerDefaults.AuthenticationScheme,
options => config.GetSection(JwtBearerDefaults.AuthenticationScheme).Bind(options))
{ }
}
}

View File

@ -0,0 +1,32 @@
// 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 Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection
{
public static class JwtBearerExtensions
{
/// <summary>
/// Adds JwtBearer authentication with options bound against the "Bearer" section
/// from the IConfiguration in the service container.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddJwtBearerAuthentication(this IServiceCollection services)
{
services.AddSingleton<IConfigureOptions<JwtBearerOptions>, JwtBearerConfigureOptions>();
return services.AddJwtBearerAuthentication(JwtBearerDefaults.AuthenticationScheme, _ => { });
}
public static IServiceCollection AddJwtBearerAuthentication(this IServiceCollection services, Action<JwtBearerOptions> configureOptions)
=> services.AddJwtBearerAuthentication(JwtBearerDefaults.AuthenticationScheme, configureOptions);
public static IServiceCollection AddJwtBearerAuthentication(this IServiceCollection services, string authenticationScheme, Action<JwtBearerOptions> configureOptions)
{
return services.AddScheme<JwtBearerOptions, JwtBearerHandler>(authenticationScheme, configureOptions);
}
}
}

View File

@ -4,14 +4,16 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Http;
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
@ -22,6 +24,65 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
{ {
private OpenIdConnectConfiguration _configuration; private OpenIdConnectConfiguration _configuration;
public JwtBearerHandler(IOptionsSnapshot<JwtBearerOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
: base(options, logger, encoder, clock)
{ }
/// <summary>
/// The handler calls methods on the events which give the application control at certain points where processing is occurring.
/// If it is not provided a default instance is supplied which does nothing when the methods are called.
/// </summary>
protected new JwtBearerEvents Events
{
get { return (JwtBearerEvents)base.Events; }
set { base.Events = value; }
}
protected override Task<object> CreateEventsAsync() => Task.FromResult<object>(new JwtBearerEvents());
protected override void InitializeOptions()
{
base.InitializeOptions();
if (string.IsNullOrEmpty(Options.TokenValidationParameters.ValidAudience) && !string.IsNullOrEmpty(Options.Audience))
{
Options.TokenValidationParameters.ValidAudience = Options.Audience;
}
if (Options.ConfigurationManager == null)
{
if (Options.Configuration != null)
{
Options.ConfigurationManager = new StaticConfigurationManager<OpenIdConnectConfiguration>(Options.Configuration);
}
else if (!(string.IsNullOrEmpty(Options.MetadataAddress) && string.IsNullOrEmpty(Options.Authority)))
{
if (string.IsNullOrEmpty(Options.MetadataAddress) && !string.IsNullOrEmpty(Options.Authority))
{
Options.MetadataAddress = Options.Authority;
if (!Options.MetadataAddress.EndsWith("/", StringComparison.Ordinal))
{
Options.MetadataAddress += "/";
}
Options.MetadataAddress += ".well-known/openid-configuration";
}
if (Options.RequireHttpsMetadata && !Options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.");
}
var httpClient = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
httpClient.Timeout = Options.BackchannelTimeout;
httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
Options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(Options.MetadataAddress, new OpenIdConnectConfigurationRetriever(),
new HttpDocumentRetriever(httpClient) { RequireHttps = Options.RequireHttpsMetadata });
}
}
}
/// <summary> /// <summary>
/// Searches the 'Authorization' header for a 'Bearer' token. If the 'Bearer' token is found, it is validated using <see cref="TokenValidationParameters"/> set in the options. /// Searches the 'Authorization' header for a 'Bearer' token. If the 'Bearer' token is found, it is validated using <see cref="TokenValidationParameters"/> set in the options.
/// </summary> /// </summary>
@ -33,11 +94,11 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
try try
{ {
// Give application opportunity to find from a different location, adjust, or reject token // Give application opportunity to find from a different location, adjust, or reject token
var messageReceivedContext = new MessageReceivedContext(Context, Options); var messageReceivedContext = new MessageReceivedContext(Context, Scheme, Options);
// event can set the token // event can set the token
await Options.Events.MessageReceived(messageReceivedContext); await Events.MessageReceived(messageReceivedContext);
if (messageReceivedContext.CheckEventResult(out result)) if (messageReceivedContext.IsProcessingComplete(out result))
{ {
return result; return result;
} }
@ -52,7 +113,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
// If no authorization header found, nothing to process further // If no authorization header found, nothing to process further
if (string.IsNullOrEmpty(authorization)) if (string.IsNullOrEmpty(authorization))
{ {
return AuthenticateResult.Skip(); return AuthenticateResult.None();
} }
if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
@ -63,7 +124,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
// If no token found, no further work possible // If no token found, no further work possible
if (string.IsNullOrEmpty(token)) if (string.IsNullOrEmpty(token))
{ {
return AuthenticateResult.Skip(); return AuthenticateResult.None();
} }
} }
@ -120,15 +181,15 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
Logger.TokenValidationSucceeded(); Logger.TokenValidationSucceeded();
var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Options.AuthenticationScheme); var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name);
var tokenValidatedContext = new TokenValidatedContext(Context, Options) var tokenValidatedContext = new TokenValidatedContext(Context, Scheme, Options)
{ {
Ticket = ticket, Ticket = ticket,
SecurityToken = validatedToken, SecurityToken = validatedToken,
}; };
await Options.Events.TokenValidated(tokenValidatedContext); await Events.TokenValidated(tokenValidatedContext);
if (tokenValidatedContext.CheckEventResult(out result)) if (tokenValidatedContext.IsProcessingComplete(out result))
{ {
return result; return result;
} }
@ -148,13 +209,13 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
if (validationFailures != null) if (validationFailures != null)
{ {
var authenticationFailedContext = new AuthenticationFailedContext(Context, Options) var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options)
{ {
Exception = (validationFailures.Count == 1) ? validationFailures[0] : new AggregateException(validationFailures) Exception = (validationFailures.Count == 1) ? validationFailures[0] : new AggregateException(validationFailures)
}; };
await Options.Events.AuthenticationFailed(authenticationFailedContext); await Events.AuthenticationFailed(authenticationFailedContext);
if (authenticationFailedContext.CheckEventResult(out result)) if (authenticationFailedContext.IsProcessingComplete(out result))
{ {
return result; return result;
} }
@ -168,13 +229,13 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
{ {
Logger.ErrorProcessingMessage(ex); Logger.ErrorProcessingMessage(ex);
var authenticationFailedContext = new AuthenticationFailedContext(Context, Options) var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options)
{ {
Exception = ex Exception = ex
}; };
await Options.Events.AuthenticationFailed(authenticationFailedContext); await Events.AuthenticationFailed(authenticationFailedContext);
if (authenticationFailedContext.CheckEventResult(out result)) if (authenticationFailedContext.IsProcessingComplete(out result))
{ {
return result; return result;
} }
@ -183,11 +244,10 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
} }
} }
protected override async Task<bool> HandleUnauthorizedAsync(ChallengeContext context) protected override async Task HandleUnauthorizedAsync(ChallengeContext context)
{ {
var authResult = await HandleAuthenticateOnceSafeAsync(); var authResult = await HandleAuthenticateOnceSafeAsync();
var eventContext = new JwtBearerChallengeContext(Context, Scheme, Options, context.Properties)
var eventContext = new JwtBearerChallengeContext(Context, Options, new AuthenticationProperties(context.Properties))
{ {
AuthenticateFailure = authResult?.Failure AuthenticateFailure = authResult?.Failure
}; };
@ -199,14 +259,10 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
eventContext.ErrorDescription = CreateErrorDescription(eventContext.AuthenticateFailure); eventContext.ErrorDescription = CreateErrorDescription(eventContext.AuthenticateFailure);
} }
await Options.Events.Challenge(eventContext); await Events.Challenge(eventContext);
if (eventContext.HandledResponse) if (eventContext.IsProcessingComplete(out var ignored))
{ {
return true; return;
}
if (eventContext.Skipped)
{
return false;
} }
Response.StatusCode = 401; Response.StatusCode = 401;
@ -259,8 +315,6 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
Response.Headers.Append(HeaderNames.WWWAuthenticate, builder.ToString()); Response.Headers.Append(HeaderNames.WWWAuthenticate, builder.ToString());
} }
return false;
} }
private static string CreateErrorDescription(Exception authFailure) private static string CreateErrorDescription(Exception authFailure)

View File

@ -1,108 +0,0 @@
// 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.Net.Http;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
namespace Microsoft.AspNetCore.Authentication.JwtBearer
{
/// <summary>
/// Bearer authentication middleware component which is added to an HTTP pipeline. This class is not
/// created by application code directly, instead it is added by calling the the IAppBuilder UseJwtBearerAuthentication
/// extension method.
/// </summary>
public class JwtBearerMiddleware : AuthenticationMiddleware<JwtBearerOptions>
{
/// <summary>
/// Bearer authentication component which is added to an HTTP pipeline. This constructor is not
/// called by application code directly, instead it is added by calling the the IAppBuilder UseJwtBearerAuthentication
/// extension method.
/// </summary>
public JwtBearerMiddleware(
RequestDelegate next,
ILoggerFactory loggerFactory,
UrlEncoder encoder,
IOptions<JwtBearerOptions> options)
: base(next, options, loggerFactory, encoder)
{
if (next == null)
{
throw new ArgumentNullException(nameof(next));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
if (encoder == null)
{
throw new ArgumentNullException(nameof(encoder));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
if (Options.Events == null)
{
Options.Events = new JwtBearerEvents();
}
if (string.IsNullOrEmpty(Options.TokenValidationParameters.ValidAudience) && !string.IsNullOrEmpty(Options.Audience))
{
Options.TokenValidationParameters.ValidAudience = Options.Audience;
}
if (Options.ConfigurationManager == null)
{
if (Options.Configuration != null)
{
Options.ConfigurationManager = new StaticConfigurationManager<OpenIdConnectConfiguration>(Options.Configuration);
}
else if (!(string.IsNullOrEmpty(Options.MetadataAddress) && string.IsNullOrEmpty(Options.Authority)))
{
if (string.IsNullOrEmpty(Options.MetadataAddress) && !string.IsNullOrEmpty(Options.Authority))
{
Options.MetadataAddress = Options.Authority;
if (!Options.MetadataAddress.EndsWith("/", StringComparison.Ordinal))
{
Options.MetadataAddress += "/";
}
Options.MetadataAddress += ".well-known/openid-configuration";
}
if (Options.RequireHttpsMetadata && !Options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.");
}
var httpClient = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
httpClient.Timeout = Options.BackchannelTimeout;
httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
Options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(Options.MetadataAddress, new OpenIdConnectConfigurationRetriever(),
new HttpDocumentRetriever(httpClient) { RequireHttps = Options.RequireHttpsMetadata });
}
}
}
/// <summary>
/// Called by the AuthenticationMiddleware base class to create a per-request handler.
/// </summary>
/// <returns>A new instance of the request handler</returns>
protected override AuthenticationHandler<JwtBearerOptions> CreateHandler()
{
return new JwtBearerHandler();
}
}
}

View File

@ -3,32 +3,19 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Net.Http; using System.Net.Http;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Protocols; using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Authentication.JwtBearer
{ {
/// <summary> /// <summary>
/// Options class provides information needed to control Bearer Authentication middleware behavior /// Options class provides information needed to control Bearer Authentication handler behavior
/// </summary> /// </summary>
public class JwtBearerOptions : AuthenticationOptions public class JwtBearerOptions : AuthenticationSchemeOptions
{ {
/// <summary>
/// Creates an instance of bearer authentication options with default values.
/// </summary>
public JwtBearerOptions() : base()
{
AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme;
AutomaticAuthenticate = true;
AutomaticChallenge = true;
}
/// <summary> /// <summary>
/// Gets or sets if HTTPS is required for the metadata address or authority. /// Gets or sets if HTTPS is required for the metadata address or authority.
/// The default is true. This should be disabled only in development environments. /// The default is true. This should be disabled only in development environments.
@ -59,11 +46,15 @@ namespace Microsoft.AspNetCore.Builder
public string Challenge { get; set; } = JwtBearerDefaults.AuthenticationScheme; public string Challenge { get; set; } = JwtBearerDefaults.AuthenticationScheme;
/// <summary> /// <summary>
/// The object provided by the application to process events raised by the bearer authentication middleware. /// The object provided by the application to process events raised by the bearer authentication handler.
/// The application may implement the interface fully, or it may create an instance of JwtBearerAuthenticationEvents /// The application may implement the interface fully, or it may create an instance of JwtBearerAuthenticationEvents
/// and assign delegates only to the events it wants to process. /// and assign delegates only to the events it wants to process.
/// </summary> /// </summary>
public IJwtBearerEvents Events { get; set; } = new JwtBearerEvents(); public new JwtBearerEvents Events
{
get { return (JwtBearerEvents)base.Events; }
set { base.Events = value; }
}
/// <summary> /// <summary>
/// The HttpMessageHandler used to retrieve metadata. /// The HttpMessageHandler used to retrieve metadata.
@ -115,7 +106,7 @@ namespace Microsoft.AspNetCore.Builder
/// <summary> /// <summary>
/// Defines whether the token validation errors should be returned to the caller. /// Defines whether the token validation errors should be returned to the caller.
/// Enabled by default, this option can be disabled to prevent the JWT middleware /// Enabled by default, this option can be disabled to prevent the JWT handler
/// from returning an error and an error_description in the WWW-Authenticate header. /// from returning an error and an error_description in the WWW-Authenticate header.
/// </summary> /// </summary>
public bool IncludeErrorDetails { get; set; } = true; public bool IncludeErrorDetails { get; set; } = true;

View File

@ -9,8 +9,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.csproj" /> <ProjectReference Include="..\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.csproj" />
<PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="$(IdentityModelOpenIdVersion)" /> <PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="$(IdentityModelOpenIdVersion)" />
<PackageReference Include="System.Security.Claims" Version="$(CoreFxVersion)" /> <PackageReference Include="System.Security.Claims" Version="$(CoreFxVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -13,6 +13,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" /> <ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(AspNetCoreVersion)" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,9 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.Authentication.MicrosoftAccount; using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Builder
{ {
@ -13,38 +12,26 @@ namespace Microsoft.AspNetCore.Builder
public static class MicrosoftAccountAppBuilderExtensions public static class MicrosoftAccountAppBuilderExtensions
{ {
/// <summary> /// <summary>
/// Adds the <see cref="MicrosoftAccountMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables Microsoft Account authentication capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseMicrosoftAccountAuthentication(this IApplicationBuilder app) public static IApplicationBuilder UseMicrosoftAccountAuthentication(this IApplicationBuilder app)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<MicrosoftAccountMiddleware>();
} }
/// <summary> /// <summary>
/// Adds the <see cref="MicrosoftAccountMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables Microsoft Account authentication capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <param name="options">A <see cref="MicrosoftAccountOptions"/> that specifies options for the middleware.</param> /// <param name="options">A <see cref="MicrosoftAccountOptions"/> that specifies options for the handler.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseMicrosoftAccountAuthentication(this IApplicationBuilder app, MicrosoftAccountOptions options) public static IApplicationBuilder UseMicrosoftAccountAuthentication(this IApplicationBuilder app, MicrosoftAccountOptions options)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
return app.UseMiddleware<MicrosoftAccountMiddleware>(Options.Create(options));
} }
} }
} }

View File

@ -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 Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
{
internal class MicrosoftAccountConfigureOptions : ConfigureNamedOptions<MicrosoftAccountOptions>
{
// Bind to "Microsoft" section by default
public MicrosoftAccountConfigureOptions(IConfiguration config) :
base(MicrosoftAccountDefaults.AuthenticationScheme,
options => config.GetSection(MicrosoftAccountDefaults.AuthenticationScheme).Bind(options))
{ }
}
}

View File

@ -0,0 +1,32 @@
// 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 Microsoft.AspNetCore.Authentication.MicrosoftAccount;
using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection
{
public static class MicrosoftAccountExtensions
{
/// <summary>
/// Adds MicrosoftAccount authentication with options bound against the "Microsoft" section
/// from the IConfiguration in the service container.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddMicrosoftAccountAuthentication(this IServiceCollection services)
{
services.AddSingleton<IConfigureOptions<MicrosoftAccountOptions>, MicrosoftAccountConfigureOptions>();
return services.AddMicrosoftAccountAuthentication(MicrosoftAccountDefaults.AuthenticationScheme, o => { });
}
public static IServiceCollection AddMicrosoftAccountAuthentication(this IServiceCollection services, Action<MicrosoftAccountOptions> configureOptions) =>
services.AddMicrosoftAccountAuthentication(MicrosoftAccountDefaults.AuthenticationScheme, configureOptions);
public static IServiceCollection AddMicrosoftAccountAuthentication(this IServiceCollection services, string authenticationScheme, Action<MicrosoftAccountOptions> configureOptions)
{
return services.AddScheme<MicrosoftAccountOptions, MicrosoftAccountHandler>(authenticationScheme, configureOptions);
}
}
}

View File

@ -1,24 +1,24 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Security.Claims; using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.OAuth; using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http.Authentication; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
{ {
internal class MicrosoftAccountHandler : OAuthHandler<MicrosoftAccountOptions> internal class MicrosoftAccountHandler : OAuthHandler<MicrosoftAccountOptions>
{ {
public MicrosoftAccountHandler(HttpClient httpClient) public MicrosoftAccountHandler(IOptions<AuthenticationOptions> sharedOptions, IOptionsSnapshot<MicrosoftAccountOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
: base(httpClient) : base(sharedOptions, options, logger, encoder, dataProtection, clock)
{ { }
}
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens) protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
{ {
@ -33,11 +33,11 @@ namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
var payload = JObject.Parse(await response.Content.ReadAsStringAsync()); var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Options.AuthenticationScheme); var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Scheme.Name);
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload); var context = new OAuthCreatingTicketContext(ticket, Context, Scheme, Options, Backchannel, tokens, payload);
context.RunClaimActions(); context.RunClaimActions();
await Options.Events.CreatingTicket(context); await Events.CreatingTicket(context);
return context.Ticket; return context.Ticket;
} }
} }

View File

@ -1,78 +0,0 @@
// 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.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
{
/// <summary>
/// An ASP.NET Core middleware for authenticating users using the Microsoft Account service.
/// </summary>
public class MicrosoftAccountMiddleware : OAuthMiddleware<MicrosoftAccountOptions>
{
/// <summary>
/// Initializes a new <see cref="MicrosoftAccountMiddleware"/>.
/// </summary>
/// <param name="next">The next middleware in the HTTP pipeline to invoke.</param>
/// <param name="dataProtectionProvider"></param>
/// <param name="loggerFactory"></param>
/// <param name="encoder"></param>
/// <param name="sharedOptions"></param>
/// <param name="options">Configuration options for the middleware.</param>
public MicrosoftAccountMiddleware(
RequestDelegate next,
IDataProtectionProvider dataProtectionProvider,
ILoggerFactory loggerFactory,
UrlEncoder encoder,
IOptions<SharedAuthenticationOptions> sharedOptions,
IOptions<MicrosoftAccountOptions> options)
: base(next, dataProtectionProvider, loggerFactory, encoder, sharedOptions, options)
{
if (next == null)
{
throw new ArgumentNullException(nameof(next));
}
if (dataProtectionProvider == null)
{
throw new ArgumentNullException(nameof(dataProtectionProvider));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
if (encoder == null)
{
throw new ArgumentNullException(nameof(encoder));
}
if (sharedOptions == null)
{
throw new ArgumentNullException(nameof(sharedOptions));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
}
/// <summary>
/// Provides the <see cref="AuthenticationHandler{T}"/> object for processing authentication-related requests.
/// </summary>
/// <returns>An <see cref="AuthenticationHandler{T}"/> configured with the <see cref="MicrosoftAccountOptions"/> supplied to the constructor.</returns>
protected override AuthenticationHandler<MicrosoftAccountOptions> CreateHandler()
{
return new MicrosoftAccountHandler(Backchannel);
}
}
}

View File

@ -5,11 +5,12 @@ using System.Security.Claims;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.MicrosoftAccount; using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Authentication.OAuth;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
{ {
/// <summary> /// <summary>
/// Configuration options for <see cref="MicrosoftAccountMiddleware"/>. /// Configuration options for <see cref="MicrosoftAccountHandler"/>.
/// </summary> /// </summary>
public class MicrosoftAccountOptions : OAuthOptions public class MicrosoftAccountOptions : OAuthOptions
{ {
@ -18,8 +19,6 @@ namespace Microsoft.AspNetCore.Builder
/// </summary> /// </summary>
public MicrosoftAccountOptions() public MicrosoftAccountOptions()
{ {
AuthenticationScheme = MicrosoftAccountDefaults.AuthenticationScheme;
DisplayName = AuthenticationScheme;
CallbackPath = new PathString("/signin-microsoft"); CallbackPath = new PathString("/signin-microsoft");
AuthorizationEndpoint = MicrosoftAccountDefaults.AuthorizationEndpoint; AuthorizationEndpoint = MicrosoftAccountDefaults.AuthorizationEndpoint;
TokenEndpoint = MicrosoftAccountDefaults.TokenEndpoint; TokenEndpoint = MicrosoftAccountDefaults.TokenEndpoint;

View File

@ -1,27 +0,0 @@
// 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.Authentication.OAuth
{
/// <summary>
/// Specifies callback methods which the <see cref="OAuthMiddleware{T}"/> invokes to enable developer control over the authentication process.
/// </summary>
public interface IOAuthEvents : IRemoteAuthenticationEvents
{
/// <summary>
/// Invoked after the provider successfully authenticates a user. This can be used to retrieve user information.
/// This event may not be invoked by sub-classes of OAuthAuthenticationHandler if they override CreateTicketAsync.
/// </summary>
/// <param name="context">Contains information about the login session.</param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
Task CreatingTicket(OAuthCreatingTicketContext context);
/// <summary>
/// Called when a Challenge causes a redirect to the authorize endpoint.
/// </summary>
/// <param name="context">Contains redirect URI and <see cref="Http.Authentication.AuthenticationProperties"/> of the challenge.</param>
Task RedirectToAuthorizationEndpoint(OAuthRedirectToAuthorizationContext context);
}
}

View File

@ -5,7 +5,6 @@ using System;
using System.Globalization; using System.Globalization;
using System.Net.Http; using System.Net.Http;
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -14,23 +13,25 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
/// <summary> /// <summary>
/// Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>. /// Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.
/// </summary> /// </summary>
public class OAuthCreatingTicketContext : BaseContext public class OAuthCreatingTicketContext : BaseAuthenticationContext
{ {
/// <summary> /// <summary>
/// Initializes a new <see cref="OAuthCreatingTicketContext"/>. /// Initializes a new <see cref="OAuthCreatingTicketContext"/>.
/// </summary> /// </summary>
/// <param name="ticket">The <see cref="AuthenticationTicket"/>.</param> /// <param name="ticket">The <see cref="AuthenticationTicket"/>.</param>
/// <param name="context">The HTTP environment.</param> /// <param name="context">The HTTP environment.</param>
/// <param name="scheme">The authentication scheme.</param>
/// <param name="options">The options used by the authentication middleware.</param> /// <param name="options">The options used by the authentication middleware.</param>
/// <param name="backchannel">The HTTP client used by the authentication middleware</param> /// <param name="backchannel">The HTTP client used by the authentication middleware</param>
/// <param name="tokens">The tokens returned from the token endpoint.</param> /// <param name="tokens">The tokens returned from the token endpoint.</param>
public OAuthCreatingTicketContext( public OAuthCreatingTicketContext(
AuthenticationTicket ticket, AuthenticationTicket ticket,
HttpContext context, HttpContext context,
AuthenticationScheme scheme,
OAuthOptions options, OAuthOptions options,
HttpClient backchannel, HttpClient backchannel,
OAuthTokenResponse tokens) OAuthTokenResponse tokens)
: this(ticket, context, options, backchannel, tokens, user: new JObject()) : this(ticket, context, scheme, options, backchannel, tokens, user: new JObject())
{ {
} }
@ -39,6 +40,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
/// </summary> /// </summary>
/// <param name="ticket">The <see cref="AuthenticationTicket"/>.</param> /// <param name="ticket">The <see cref="AuthenticationTicket"/>.</param>
/// <param name="context">The HTTP environment.</param> /// <param name="context">The HTTP environment.</param>
/// <param name="scheme">The authentication scheme.</param>
/// <param name="options">The options used by the authentication middleware.</param> /// <param name="options">The options used by the authentication middleware.</param>
/// <param name="backchannel">The HTTP client used by the authentication middleware</param> /// <param name="backchannel">The HTTP client used by the authentication middleware</param>
/// <param name="tokens">The tokens returned from the token endpoint.</param> /// <param name="tokens">The tokens returned from the token endpoint.</param>
@ -46,11 +48,12 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
public OAuthCreatingTicketContext( public OAuthCreatingTicketContext(
AuthenticationTicket ticket, AuthenticationTicket ticket,
HttpContext context, HttpContext context,
AuthenticationScheme scheme,
OAuthOptions options, OAuthOptions options,
HttpClient backchannel, HttpClient backchannel,
OAuthTokenResponse tokens, OAuthTokenResponse tokens,
JObject user) JObject user)
: base(context) : base(context, scheme.Name, ticket.Properties)
{ {
if (context == null) if (context == null)
{ {
@ -77,15 +80,23 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
throw new ArgumentNullException(nameof(user)); throw new ArgumentNullException(nameof(user));
} }
if (scheme == null)
{
throw new ArgumentNullException(nameof(scheme));
}
TokenResponse = tokens; TokenResponse = tokens;
Backchannel = backchannel; Backchannel = backchannel;
User = user; User = user;
Options = options; Options = options;
Scheme = scheme;
Ticket = ticket; Ticket = ticket;
} }
public OAuthOptions Options { get; } public OAuthOptions Options { get; }
public AuthenticationScheme Scheme { get; }
/// <summary> /// <summary>
/// Gets the JSON-serialized user or an empty /// Gets the JSON-serialized user or an empty
/// <see cref="JObject"/> if it is not available. /// <see cref="JObject"/> if it is not available.

View File

@ -8,9 +8,9 @@ using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Authentication.OAuth namespace Microsoft.AspNetCore.Authentication.OAuth
{ {
/// <summary> /// <summary>
/// Default <see cref="IOAuthEvents"/> implementation. /// Default implementation.
/// </summary> /// </summary>
public class OAuthEvents : RemoteAuthenticationEvents, IOAuthEvents public class OAuthEvents : RemoteAuthenticationEvents
{ {
/// <summary> /// <summary>
/// Gets or sets the function that is invoked when the CreatingTicket method is invoked. /// Gets or sets the function that is invoked when the CreatingTicket method is invoked.
@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
public virtual Task CreatingTicket(OAuthCreatingTicketContext context) => OnCreatingTicket(context); public virtual Task CreatingTicket(OAuthCreatingTicketContext context) => OnCreatingTicket(context);
/// <summary> /// <summary>
/// Called when a Challenge causes a redirect to authorize endpoint in the OAuth middleware. /// Called when a Challenge causes a redirect to authorize endpoint in the OAuth handler.
/// </summary> /// </summary>
/// <param name="context">Contains redirect URI and <see cref="Http.Authentication.AuthenticationProperties"/> of the challenge.</param> /// <param name="context">Contains redirect URI and <see cref="Http.Authentication.AuthenticationProperties"/> of the challenge.</param>
public virtual Task RedirectToAuthorizationEndpoint(OAuthRedirectToAuthorizationContext context) => OnRedirectToAuthorizationEndpoint(context); public virtual Task RedirectToAuthorizationEndpoint(OAuthRedirectToAuthorizationContext context) => OnRedirectToAuthorizationEndpoint(context);

View File

@ -3,12 +3,11 @@
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
namespace Microsoft.AspNetCore.Authentication.OAuth namespace Microsoft.AspNetCore.Authentication.OAuth
{ {
/// <summary> /// <summary>
/// Context passed when a Challenge causes a redirect to authorize endpoint in the middleware. /// Context passed when a Challenge causes a redirect to authorize endpoint in the handler.
/// </summary> /// </summary>
public class OAuthRedirectToAuthorizationContext : BaseContext public class OAuthRedirectToAuthorizationContext : BaseContext
{ {

View File

@ -1,9 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.Authentication.OAuth; using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Builder
{ {
@ -13,38 +12,26 @@ namespace Microsoft.AspNetCore.Builder
public static class OAuthAppBuilderExtensions public static class OAuthAppBuilderExtensions
{ {
/// <summary> /// <summary>
/// Adds the <see cref="OAuthMiddleware{TOptions}"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables OAuth 2.0 authentication capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseOAuthAuthentication(this IApplicationBuilder app) public static IApplicationBuilder UseOAuthAuthentication(this IApplicationBuilder app)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<OAuthMiddleware<OAuthOptions>>();
} }
/// <summary> /// <summary>
/// Adds the <see cref="OAuthMiddleware{TOptions}"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables OAuth 2.0 authentication capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <param name="options">A <see cref="OAuthOptions"/> that specifies options for the middleware.</param> /// <param name="options">A <see cref="OAuthOptions"/> that specifies options for the handler.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseOAuthAuthentication(this IApplicationBuilder app, OAuthOptions options) public static IApplicationBuilder UseOAuthAuthentication(this IApplicationBuilder app, OAuthOptions options)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
return app.UseMiddleware<OAuthMiddleware<OAuthOptions>>(Options.Create(options));
} }
} }
} }

View File

@ -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;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Builder
{
public static class OAuthExtensions
{
public static IServiceCollection AddOAuthAuthentication(this IServiceCollection services, string authenticationScheme, Action<OAuthOptions> configureOptions) =>
services.AddScheme<OAuthOptions, OAuthHandler<OAuthOptions>>(authenticationScheme, configureOptions);
}
}

View File

@ -8,24 +8,60 @@ using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.AspNetCore.WebUtilities; using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace Microsoft.AspNetCore.Authentication.OAuth namespace Microsoft.AspNetCore.Authentication.OAuth
{ {
public class OAuthHandler<TOptions> : RemoteAuthenticationHandler<TOptions> where TOptions : OAuthOptions public class OAuthHandler<TOptions> : RemoteAuthenticationHandler<TOptions> where TOptions : OAuthOptions, new()
{ {
public OAuthHandler(HttpClient backchannel) protected HttpClient Backchannel => Options.Backchannel;
/// <summary>
/// The handler calls methods on the events which give the application control at certain points where processing is occurring.
/// If it is not provided a default instance is supplied which does nothing when the methods are called.
/// </summary>
protected new OAuthEvents Events
{ {
Backchannel = backchannel; get { return (OAuthEvents)base.Events; }
set { base.Events = value; }
} }
protected HttpClient Backchannel { get; private set; } public OAuthHandler(IOptions<AuthenticationOptions> sharedOptions, IOptionsSnapshot<TOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
: base(sharedOptions, options, dataProtection, logger, encoder, clock)
{ }
protected override void InitializeOptions()
{
base.InitializeOptions();
if (Options.Backchannel == null)
{
Options.Backchannel = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
Options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OAuth handler");
Options.Backchannel.Timeout = Options.BackchannelTimeout;
Options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
}
if (Options.StateDataFormat == null)
{
var dataProtector = DataProtection.CreateProtector(
GetType().FullName, Scheme.Name, "v1");
Options.StateDataFormat = new PropertiesDataFormat(dataProtector);
}
}
/// <summary>
/// Creates a new instance of the events instance.
/// </summary>
/// <returns>A new instance of the events instance.</returns>
protected override Task<object> CreateEventsAsync() => Task.FromResult<object>(new OAuthEvents());
protected override async Task<AuthenticateResult> HandleRemoteAuthenticateAsync() protected override async Task<AuthenticateResult> HandleRemoteAuthenticateAsync()
{ {
@ -107,7 +143,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
{ {
// https://www.w3.org/TR/xmlschema-2/#dateTime // https://www.w3.org/TR/xmlschema-2/#dateTime
// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx
var expiresAt = Options.SystemClock.UtcNow + TimeSpan.FromSeconds(value); var expiresAt = Clock.UtcNow + TimeSpan.FromSeconds(value);
authTokens.Add(new AuthenticationToken authTokens.Add(new AuthenticationToken
{ {
Name = "expires_at", Name = "expires_at",
@ -170,21 +206,20 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
protected virtual async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens) protected virtual async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
{ {
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Options.AuthenticationScheme); var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Scheme.Name);
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens); var context = new OAuthCreatingTicketContext(ticket, Context, Scheme, Options, Backchannel, tokens);
await Options.Events.CreatingTicket(context); await Events.CreatingTicket(context);
return context.Ticket; return context.Ticket;
} }
protected override async Task<bool> HandleUnauthorizedAsync(ChallengeContext context) protected override async Task HandleUnauthorizedAsync(ChallengeContext context)
{ {
if (context == null) if (context == null)
{ {
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
var properties = new AuthenticationProperties(context.Properties); var properties = context.Properties;
if (string.IsNullOrEmpty(properties.RedirectUri)) if (string.IsNullOrEmpty(properties.RedirectUri))
{ {
properties.RedirectUri = CurrentUri; properties.RedirectUri = CurrentUri;
@ -197,8 +232,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
var redirectContext = new OAuthRedirectToAuthorizationContext( var redirectContext = new OAuthRedirectToAuthorizationContext(
Context, Options, Context, Options,
properties, authorizationEndpoint); properties, authorizationEndpoint);
await Options.Events.RedirectToAuthorizationEndpoint(redirectContext); await Events.RedirectToAuthorizationEndpoint(redirectContext);
return true;
} }
protected virtual string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri) protected virtual string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)

View File

@ -1,138 +0,0 @@
// 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.Net.Http;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Authentication.OAuth
{
/// <summary>
/// An ASP.NET Core middleware for authenticating users using OAuth services.
/// </summary>
public class OAuthMiddleware<TOptions> : AuthenticationMiddleware<TOptions> where TOptions : OAuthOptions, new()
{
/// <summary>
/// Initializes a new <see cref="OAuthMiddleware{T}"/>.
/// </summary>
/// <param name="next">The next middleware in the HTTP pipeline to invoke.</param>
/// <param name="dataProtectionProvider"></param>
/// <param name="loggerFactory"></param>
/// <param name="encoder">The <see cref="UrlEncoder"/>.</param>
/// <param name="sharedOptions">The <see cref="SharedAuthenticationOptions"/> configuration options for this middleware.</param>
/// <param name="options">Configuration options for the middleware.</param>
public OAuthMiddleware(
RequestDelegate next,
IDataProtectionProvider dataProtectionProvider,
ILoggerFactory loggerFactory,
UrlEncoder encoder,
IOptions<SharedAuthenticationOptions> sharedOptions,
IOptions<TOptions> options)
: base(next, options, loggerFactory, encoder)
{
if (next == null)
{
throw new ArgumentNullException(nameof(next));
}
if (dataProtectionProvider == null)
{
throw new ArgumentNullException(nameof(dataProtectionProvider));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
if (encoder == null)
{
throw new ArgumentNullException(nameof(encoder));
}
if (sharedOptions == null)
{
throw new ArgumentNullException(nameof(sharedOptions));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
// todo: review error handling
if (string.IsNullOrEmpty(Options.AuthenticationScheme))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.AuthenticationScheme)));
}
if (string.IsNullOrEmpty(Options.ClientId))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.ClientId)));
}
if (string.IsNullOrEmpty(Options.ClientSecret))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.ClientSecret)));
}
if (string.IsNullOrEmpty(Options.AuthorizationEndpoint))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.AuthorizationEndpoint)));
}
if (string.IsNullOrEmpty(Options.TokenEndpoint))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.TokenEndpoint)));
}
if (!Options.CallbackPath.HasValue)
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.CallbackPath)));
}
if (Options.Events == null)
{
Options.Events = new OAuthEvents();
}
if (Options.StateDataFormat == null)
{
var dataProtector = dataProtectionProvider.CreateProtector(
GetType().FullName, Options.AuthenticationScheme, "v1");
Options.StateDataFormat = new PropertiesDataFormat(dataProtector);
}
Backchannel = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OAuth middleware");
Backchannel.Timeout = Options.BackchannelTimeout;
Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
if (string.IsNullOrEmpty(Options.SignInScheme))
{
Options.SignInScheme = sharedOptions.Value.SignInScheme;
}
if (string.IsNullOrEmpty(Options.SignInScheme))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.SignInScheme)));
}
}
protected HttpClient Backchannel { get; private set; }
/// <summary>
/// Provides the <see cref="AuthenticationHandler{T}"/> object for processing authentication-related requests.
/// </summary>
/// <returns>An <see cref="AuthenticationHandler{T}"/> configured with the <see cref="OAuthOptions"/> supplied to the constructor.</returns>
protected override AuthenticationHandler<TOptions> CreateHandler()
{
return new OAuthHandler<TOptions>(Backchannel);
}
}
}

View File

@ -1,16 +1,18 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // 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.Collections.Generic;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OAuth; using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Authentication.OAuth.Claims; using Microsoft.AspNetCore.Authentication.OAuth.Claims;
using Microsoft.AspNetCore.Http.Authentication; using Microsoft.AspNetCore.Http.Authentication;
using System.Globalization;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Authentication.OAuth
{ {
/// <summary> /// <summary>
/// Configuration options for <see cref="OAuthMiddleware{T}"/>. /// Configuration options OAuth.
/// </summary> /// </summary>
public class OAuthOptions : RemoteAuthenticationOptions public class OAuthOptions : RemoteAuthenticationOptions
{ {
@ -19,6 +21,39 @@ namespace Microsoft.AspNetCore.Builder
Events = new OAuthEvents(); Events = new OAuthEvents();
} }
/// <summary>
/// Check that the options are valid. Should throw an exception if things are not ok.
/// </summary>
public override void Validate()
{
base.Validate();
if (string.IsNullOrEmpty(ClientId))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(ClientId)), nameof(ClientId));
}
if (string.IsNullOrEmpty(ClientSecret))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(ClientSecret)), nameof(ClientSecret));
}
if (string.IsNullOrEmpty(AuthorizationEndpoint))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(AuthorizationEndpoint)), nameof(AuthorizationEndpoint));
}
if (string.IsNullOrEmpty(TokenEndpoint))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(TokenEndpoint)), nameof(TokenEndpoint));
}
if (!CallbackPath.HasValue)
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(CallbackPath)), nameof(CallbackPath));
}
}
/// <summary> /// <summary>
/// Gets or sets the provider-assigned client id. /// Gets or sets the provider-assigned client id.
/// </summary> /// </summary>
@ -47,11 +82,11 @@ namespace Microsoft.AspNetCore.Builder
public string UserInformationEndpoint { get; set; } public string UserInformationEndpoint { get; set; }
/// <summary> /// <summary>
/// Gets or sets the <see cref="IOAuthEvents"/> used to handle authentication events. /// Gets or sets the <see cref="OAuthEvents"/> used to handle authentication events.
/// </summary> /// </summary>
public new IOAuthEvents Events public new OAuthEvents Events
{ {
get { return (IOAuthEvents)base.Events; } get { return (OAuthEvents)base.Events; }
set { base.Events = value; } set { base.Events = value; }
} }

View File

@ -9,8 +9,8 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{ {
public class AuthenticationFailedContext : BaseOpenIdConnectContext public class AuthenticationFailedContext : BaseOpenIdConnectContext
{ {
public AuthenticationFailedContext(HttpContext context, OpenIdConnectOptions options) public AuthenticationFailedContext(HttpContext context, AuthenticationScheme scheme, OpenIdConnectOptions options)
: base(context, options) : base(context, scheme, options)
{ {
} }

View File

@ -18,8 +18,8 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// <summary> /// <summary>
/// Creates a <see cref="AuthorizationCodeReceivedContext"/> /// Creates a <see cref="AuthorizationCodeReceivedContext"/>
/// </summary> /// </summary>
public AuthorizationCodeReceivedContext(HttpContext context, OpenIdConnectOptions options) public AuthorizationCodeReceivedContext(HttpContext context, AuthenticationScheme scheme, OpenIdConnectOptions options)
: base(context, options) : base(context, scheme, options)
{ {
} }
@ -42,23 +42,23 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// <summary> /// <summary>
/// If the developer chooses to redeem the code themselves then they can provide the resulting tokens here. This is the /// If the developer chooses to redeem the code themselves then they can provide the resulting tokens here. This is the
/// same as calling HandleCodeRedemption. If set then the middleware will not attempt to redeem the code. An IdToken /// same as calling HandleCodeRedemption. If set then the handler will not attempt to redeem the code. An IdToken
/// is required if one had not been previously received in the authorization response. An access token is optional /// is required if one had not been previously received in the authorization response. An access token is optional
/// if the middleware is to contact the user-info endpoint. /// if the handler is to contact the user-info endpoint.
/// </summary> /// </summary>
public OpenIdConnectMessage TokenEndpointResponse { get; set; } public OpenIdConnectMessage TokenEndpointResponse { get; set; }
/// <summary> /// <summary>
/// Indicates if the developer choose to handle (or skip) the code redemption. If true then the middleware will not attempt /// Indicates if the developer choose to handle (or skip) the code redemption. If true then the handler will not attempt
/// to redeem the code. See HandleCodeRedemption and TokenEndpointResponse. /// to redeem the code. See HandleCodeRedemption and TokenEndpointResponse.
/// </summary> /// </summary>
public bool HandledCodeRedemption => TokenEndpointResponse != null; public bool HandledCodeRedemption => TokenEndpointResponse != null;
/// <summary> /// <summary>
/// Tells the middleware to skip the code redemption process. The developer may have redeemed the code themselves, or /// Tells the handler to skip the code redemption process. The developer may have redeemed the code themselves, or
/// decided that the redemption was not required. If tokens were retrieved that are needed for further processing then /// decided that the redemption was not required. If tokens were retrieved that are needed for further processing then
/// call one of the overloads that allows providing tokens. An IdToken is required if one had not been previously received /// call one of the overloads that allows providing tokens. An IdToken is required if one had not been previously received
/// in the authorization response. An access token can optionally be provided for the middleware to contact the /// in the authorization response. An access token can optionally be provided for the handler to contact the
/// user-info endpoint. Calling this is the same as setting TokenEndpointResponse. /// user-info endpoint. Calling this is the same as setting TokenEndpointResponse.
/// </summary> /// </summary>
public void HandleCodeRedemption() public void HandleCodeRedemption()
@ -67,10 +67,10 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
} }
/// <summary> /// <summary>
/// Tells the middleware to skip the code redemption process. The developer may have redeemed the code themselves, or /// Tells the handler to skip the code redemption process. The developer may have redeemed the code themselves, or
/// decided that the redemption was not required. If tokens were retrieved that are needed for further processing then /// decided that the redemption was not required. If tokens were retrieved that are needed for further processing then
/// call one of the overloads that allows providing tokens. An IdToken is required if one had not been previously received /// call one of the overloads that allows providing tokens. An IdToken is required if one had not been previously received
/// in the authorization response. An access token can optionally be provided for the middleware to contact the /// in the authorization response. An access token can optionally be provided for the handler to contact the
/// user-info endpoint. Calling this is the same as setting TokenEndpointResponse. /// user-info endpoint. Calling this is the same as setting TokenEndpointResponse.
/// </summary> /// </summary>
public void HandleCodeRedemption(string accessToken, string idToken) public void HandleCodeRedemption(string accessToken, string idToken)
@ -79,10 +79,10 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
} }
/// <summary> /// <summary>
/// Tells the middleware to skip the code redemption process. The developer may have redeemed the code themselves, or /// Tells the handler to skip the code redemption process. The developer may have redeemed the code themselves, or
/// decided that the redemption was not required. If tokens were retrieved that are needed for further processing then /// decided that the redemption was not required. If tokens were retrieved that are needed for further processing then
/// call one of the overloads that allows providing tokens. An IdToken is required if one had not been previously received /// call one of the overloads that allows providing tokens. An IdToken is required if one had not been previously received
/// in the authorization response. An access token can optionally be provided for the middleware to contact the /// in the authorization response. An access token can optionally be provided for the handler to contact the
/// user-info endpoint. Calling this is the same as setting TokenEndpointResponse. /// user-info endpoint. Calling this is the same as setting TokenEndpointResponse.
/// </summary> /// </summary>
public void HandleCodeRedemption(OpenIdConnectMessage tokenEndpointResponse) public void HandleCodeRedemption(OpenIdConnectMessage tokenEndpointResponse)

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Protocols.OpenIdConnect;
@ -10,19 +9,17 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{ {
public class BaseOpenIdConnectContext : BaseControlContext public class BaseOpenIdConnectContext : BaseControlContext
{ {
public BaseOpenIdConnectContext(HttpContext context, OpenIdConnectOptions options) public BaseOpenIdConnectContext(HttpContext context, AuthenticationScheme scheme, OpenIdConnectOptions options)
: base(context) : base(context)
{ {
if (options == null) Options = options ?? throw new ArgumentNullException(nameof(options));
{ Scheme = scheme ?? throw new ArgumentNullException(nameof(scheme));
throw new ArgumentNullException(nameof(options));
}
Options = options;
} }
public OpenIdConnectOptions Options { get; } public OpenIdConnectOptions Options { get; }
public AuthenticationScheme Scheme { get; }
public OpenIdConnectMessage ProtocolMessage { get; set; } public OpenIdConnectMessage ProtocolMessage { get; set; }
} }
} }

View File

@ -1,58 +0,0 @@
// 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.Authentication.OpenIdConnect
{
/// <summary>
/// Specifies events which the <see cref="OpenIdConnectMiddleware" />invokes to enable developer control over the authentication process.
/// </summary>
public interface IOpenIdConnectEvents : IRemoteAuthenticationEvents
{
/// <summary>
/// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed.
/// </summary>
Task AuthenticationFailed(AuthenticationFailedContext context);
/// <summary>
/// Invoked after security token validation if an authorization code is present in the protocol message.
/// </summary>
Task AuthorizationCodeReceived(AuthorizationCodeReceivedContext context);
/// <summary>
/// Invoked when a protocol message is first received.
/// </summary>
Task MessageReceived(MessageReceivedContext context);
/// <summary>
/// Invoked before redirecting to the identity provider to authenticate.
/// </summary>
Task RedirectToIdentityProvider(RedirectContext context);
/// <summary>
/// Invoked before redirecting to the identity provider to sign out.
/// </summary>
Task RedirectToIdentityProviderForSignOut(RedirectContext context);
/// <summary>
/// Invoked when a request is received on the RemoteSignOutPath.
/// </summary>
Task RemoteSignOut(RemoteSignOutContext context);
/// <summary>
/// Invoked after "authorization code" is redeemed for tokens at the token endpoint.
/// </summary>
Task TokenResponseReceived(TokenResponseReceivedContext context);
/// <summary>
/// Invoked when an IdToken has been validated and produced an AuthenticationTicket.
/// </summary>
Task TokenValidated(TokenValidatedContext context);
/// <summary>
/// Invoked when user information is retrieved from the UserInfoEndpoint.
/// </summary>
Task UserInformationReceived(UserInformationReceivedContext context);
}
}

View File

@ -1,16 +1,14 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{ {
public class MessageReceivedContext : BaseOpenIdConnectContext public class MessageReceivedContext : BaseOpenIdConnectContext
{ {
public MessageReceivedContext(HttpContext context, OpenIdConnectOptions options) public MessageReceivedContext(HttpContext context, AuthenticationScheme scheme, OpenIdConnectOptions options)
: base(context, options) : base(context, scheme, options)
{ {
} }

View File

@ -8,9 +8,9 @@ using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{ {
/// <summary> /// <summary>
/// Specifies events which the <see cref="OpenIdConnectMiddleware" />invokes to enable developer control over the authentication process. /// Specifies events which the <see cref="OpenIdConnectHandler" />invokes to enable developer control over the authentication process.
/// </summary> /// </summary>
public class OpenIdConnectEvents : RemoteAuthenticationEvents, IOpenIdConnectEvents public class OpenIdConnectEvents : RemoteAuthenticationEvents
{ {
/// <summary> /// <summary>
/// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed. /// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed.

View File

@ -1,20 +1,18 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{ {
/// <summary> /// <summary>
/// When a user configures the <see cref="OpenIdConnectMiddleware"/> to be notified prior to redirecting to an IdentityProvider /// When a user configures the <see cref="OpenIdConnectHandler"/> to be notified prior to redirecting to an IdentityProvider
/// an instance of <see cref="RedirectContext"/> is passed to the 'RedirectToAuthenticationEndpoint' or 'RedirectToEndSessionEndpoint' events. /// an instance of <see cref="RedirectContext"/> is passed to the 'RedirectToAuthenticationEndpoint' or 'RedirectToEndSessionEndpoint' events.
/// </summary> /// </summary>
public class RedirectContext : BaseOpenIdConnectContext public class RedirectContext : BaseOpenIdConnectContext
{ {
public RedirectContext(HttpContext context, OpenIdConnectOptions options, AuthenticationProperties properties) public RedirectContext(HttpContext context, AuthenticationScheme scheme, OpenIdConnectOptions options, AuthenticationProperties properties)
: base(context, options) : base(context, scheme, options)
{ {
Properties = properties; Properties = properties;
} }

View File

@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Protocols.OpenIdConnect;
@ -11,9 +10,10 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{ {
public RemoteSignOutContext( public RemoteSignOutContext(
HttpContext context, HttpContext context,
AuthenticationScheme scheme,
OpenIdConnectOptions options, OpenIdConnectOptions options,
OpenIdConnectMessage message) OpenIdConnectMessage message)
: base(context, options) : base(context, scheme, options)
{ {
ProtocolMessage = message; ProtocolMessage = message;
} }

View File

@ -1,9 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Protocols.OpenIdConnect;
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
@ -16,8 +14,8 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// <summary> /// <summary>
/// Creates a <see cref="TokenResponseReceivedContext"/> /// Creates a <see cref="TokenResponseReceivedContext"/>
/// </summary> /// </summary>
public TokenResponseReceivedContext(HttpContext context, OpenIdConnectOptions options, AuthenticationProperties properties) public TokenResponseReceivedContext(HttpContext context, AuthenticationScheme scheme, OpenIdConnectOptions options, AuthenticationProperties properties)
: base(context, options) : base(context, scheme, options)
{ {
Properties = properties; Properties = properties;
} }

View File

@ -15,8 +15,8 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// <summary> /// <summary>
/// Creates a <see cref="TokenValidatedContext"/> /// Creates a <see cref="TokenValidatedContext"/>
/// </summary> /// </summary>
public TokenValidatedContext(HttpContext context, OpenIdConnectOptions options) public TokenValidatedContext(HttpContext context, AuthenticationScheme scheme, OpenIdConnectOptions options)
: base(context, options) : base(context, scheme, options)
{ {
} }

View File

@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -9,8 +8,8 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{ {
public class UserInformationReceivedContext : BaseOpenIdConnectContext public class UserInformationReceivedContext : BaseOpenIdConnectContext
{ {
public UserInformationReceivedContext(HttpContext context, OpenIdConnectOptions options) public UserInformationReceivedContext(HttpContext context, AuthenticationScheme scheme, OpenIdConnectOptions options)
: base(context, options) : base(context, scheme, options)
{ {
} }

View File

@ -11,6 +11,7 @@
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" /> <ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" />
<PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" /> <PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="$(IdentityModelOpenIdVersion)" /> <PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="$(IdentityModelOpenIdVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(AspNetCoreVersion)" />
<PackageReference Include="System.Security.Claims" Version="$(CoreFxVersion)" /> <PackageReference Include="System.Security.Claims" Version="$(CoreFxVersion)" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,9 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Builder
{ {
@ -13,38 +12,26 @@ namespace Microsoft.AspNetCore.Builder
public static class OpenIdConnectAppBuilderExtensions public static class OpenIdConnectAppBuilderExtensions
{ {
/// <summary> /// <summary>
/// Adds the <see cref="OpenIdConnectMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables OpenID Connect authentication capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseOpenIdConnectAuthentication(this IApplicationBuilder app) public static IApplicationBuilder UseOpenIdConnectAuthentication(this IApplicationBuilder app)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<OpenIdConnectMiddleware>();
} }
/// <summary> /// <summary>
/// Adds the <see cref="OpenIdConnectMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables OpenID Connect authentication capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <param name="options">A <see cref="OpenIdConnectOptions"/> that specifies options for the middleware.</param> /// <param name="options">A <see cref="OpenIdConnectOptions"/> that specifies options for the handler.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseOpenIdConnectAuthentication(this IApplicationBuilder app, OpenIdConnectOptions options) public static IApplicationBuilder UseOpenIdConnectAuthentication(this IApplicationBuilder app, OpenIdConnectOptions options)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
return app.UseMiddleware<OpenIdConnectMiddleware>(Options.Create(options));
} }
} }
} }

View File

@ -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 Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{
internal class OpenIdConnectConfigureOptions : ConfigureNamedOptions<OpenIdConnectOptions>
{
// Bind to "OpenIdConnect" section by default
public OpenIdConnectConfigureOptions(IConfiguration config) :
base(OpenIdConnectDefaults.AuthenticationScheme,
options => config.GetSection(OpenIdConnectDefaults.AuthenticationScheme).Bind(options))
{ }
}
}

View File

@ -4,7 +4,7 @@
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{ {
/// <summary> /// <summary>
/// Default values related to OpenIdConnect authentication middleware /// Default values related to OpenIdConnect authentication handler
/// </summary> /// </summary>
public static class OpenIdConnectDefaults public static class OpenIdConnectDefaults
{ {

View File

@ -0,0 +1,32 @@
// 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 Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection
{
public static class OpenIdConnectExtensions
{
/// <summary>
/// Adds OpenIdConnect authentication with options bound against the "OpenIdConnect" section
/// from the IConfiguration in the service container.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddOpenIdConnectAuthentication(this IServiceCollection services)
{
services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, OpenIdConnectConfigureOptions>();
return services.AddOpenIdConnectAuthentication(OpenIdConnectDefaults.AuthenticationScheme, _ => { });
}
public static IServiceCollection AddOpenIdConnectAuthentication(this IServiceCollection services, Action<OpenIdConnectOptions> configureOptions)
=> services.AddOpenIdConnectAuthentication(OpenIdConnectDefaults.AuthenticationScheme, configureOptions);
public static IServiceCollection AddOpenIdConnectAuthentication(this IServiceCollection services, string authenticationScheme, Action<OpenIdConnectOptions> configureOptions)
{
return services.AddScheme<OpenIdConnectOptions, OpenIdConnectHandler>(authenticationScheme, configureOptions);
}
}
}

View File

@ -13,12 +13,12 @@ using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
@ -53,28 +53,110 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
private OpenIdConnectConfiguration _configuration; private OpenIdConnectConfiguration _configuration;
protected HttpClient Backchannel { get; private set; } protected HttpClient Backchannel => Options.Backchannel;
protected HtmlEncoder HtmlEncoder { get; private set; } protected HtmlEncoder HtmlEncoder { get; }
public OpenIdConnectHandler(HttpClient backchannel, HtmlEncoder htmlEncoder) public OpenIdConnectHandler(IOptions<AuthenticationOptions> sharedOptions, IOptionsSnapshot<OpenIdConnectOptions> options, ILoggerFactory logger, HtmlEncoder htmlEncoder, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
: base(sharedOptions, options, dataProtection, logger, encoder, clock)
{ {
Backchannel = backchannel;
HtmlEncoder = htmlEncoder; HtmlEncoder = htmlEncoder;
} }
public override async Task<bool> HandleRequestAsync() /// <summary>
/// The handler calls methods on the events which give the application control at certain points where processing is occurring.
/// If it is not provided a default instance is supplied which does nothing when the methods are called.
/// </summary>
protected new OpenIdConnectEvents Events
{
get { return (OpenIdConnectEvents)base.Events; }
set { base.Events = value; }
}
protected override Task<object> CreateEventsAsync() => Task.FromResult<object>(new OpenIdConnectEvents());
protected override void InitializeOptions()
{
base.InitializeOptions();
if (string.IsNullOrEmpty(Options.SignOutScheme))
{
Options.SignOutScheme = SignInScheme;
}
if (Options.StateDataFormat == null)
{
var dataProtector = DataProtection.CreateProtector(
GetType().FullName, Scheme.Name, "v1");
Options.StateDataFormat = new PropertiesDataFormat(dataProtector);
}
if (Options.StringDataFormat == null)
{
var dataProtector = DataProtection.CreateProtector(
GetType().FullName,
typeof(string).FullName,
Scheme.Name,
"v1");
Options.StringDataFormat = new SecureDataFormat<string>(new StringSerializer(), dataProtector);
}
if (string.IsNullOrEmpty(Options.TokenValidationParameters.ValidAudience) && !string.IsNullOrEmpty(Options.ClientId))
{
Options.TokenValidationParameters.ValidAudience = Options.ClientId;
}
if (Options.Backchannel == null)
{
Options.Backchannel = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
Options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OpenIdConnect handler");
Options.Backchannel.Timeout = Options.BackchannelTimeout;
Options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
}
if (Options.ConfigurationManager == null)
{
if (Options.Configuration != null)
{
Options.ConfigurationManager = new StaticConfigurationManager<OpenIdConnectConfiguration>(Options.Configuration);
}
else if (!(string.IsNullOrEmpty(Options.MetadataAddress) && string.IsNullOrEmpty(Options.Authority)))
{
if (string.IsNullOrEmpty(Options.MetadataAddress) && !string.IsNullOrEmpty(Options.Authority))
{
Options.MetadataAddress = Options.Authority;
if (!Options.MetadataAddress.EndsWith("/", StringComparison.Ordinal))
{
Options.MetadataAddress += "/";
}
Options.MetadataAddress += ".well-known/openid-configuration";
}
if (Options.RequireHttpsMetadata && !Options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.");
}
Options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(Options.MetadataAddress, new OpenIdConnectConfigurationRetriever(),
new HttpDocumentRetriever(Backchannel) { RequireHttps = Options.RequireHttpsMetadata });
}
}
}
public override Task<bool> HandleRequestAsync()
{ {
if (Options.RemoteSignOutPath.HasValue && Options.RemoteSignOutPath == Request.Path) if (Options.RemoteSignOutPath.HasValue && Options.RemoteSignOutPath == Request.Path)
{ {
return await HandleRemoteSignOutAsync(); return HandleRemoteSignOutAsync();
} }
else if (Options.SignedOutCallbackPath.HasValue && Options.SignedOutCallbackPath == Request.Path) else if (Options.SignedOutCallbackPath.HasValue && Options.SignedOutCallbackPath == Request.Path)
{ {
return await HandleSignOutCallbackAsync(); return HandleSignOutCallbackAsync();
} }
return await base.HandleRequestAsync(); return base.HandleRequestAsync();
} }
protected virtual async Task<bool> HandleRemoteSignOutAsync() protected virtual async Task<bool> HandleRemoteSignOutAsync()
@ -97,8 +179,8 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
message = new OpenIdConnectMessage(form.Select(pair => new KeyValuePair<string, string[]>(pair.Key, pair.Value))); message = new OpenIdConnectMessage(form.Select(pair => new KeyValuePair<string, string[]>(pair.Key, pair.Value)));
} }
var remoteSignOutContext = new RemoteSignOutContext(Context, Options, message); var remoteSignOutContext = new RemoteSignOutContext(Context, Scheme, Options, message);
await Options.Events.RemoteSignOut(remoteSignOutContext); await Events.RemoteSignOut(remoteSignOutContext);
if (remoteSignOutContext.HandledResponse) if (remoteSignOutContext.HandledResponse)
{ {
@ -120,7 +202,8 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
// If the identifier cannot be found, bypass the session identifier checks: this may indicate that the // If the identifier cannot be found, bypass the session identifier checks: this may indicate that the
// authentication cookie was already cleared, that the session identifier was lost because of a lossy // authentication cookie was already cleared, that the session identifier was lost because of a lossy
// external/application cookie conversion or that the identity provider doesn't support sessions. // external/application cookie conversion or that the identity provider doesn't support sessions.
var sid = (await Context.Authentication.AuthenticateAsync(Options.SignOutScheme)) var sid = (await Context.AuthenticateAsync(Options.SignOutScheme))
?.Principal
?.FindFirst(JwtRegisteredClaimNames.Sid) ?.FindFirst(JwtRegisteredClaimNames.Sid)
?.Value; ?.Value;
if (!string.IsNullOrEmpty(sid)) if (!string.IsNullOrEmpty(sid))
@ -142,7 +225,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
Logger.RemoteSignOut(); Logger.RemoteSignOut();
// We've received a remote sign-out request // We've received a remote sign-out request
await Context.Authentication.SignOutAsync(Options.SignOutScheme); await Context.SignOutAsync(Options.SignOutScheme);
return true; return true;
} }
@ -169,7 +252,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
}; };
// Get the post redirect URI. // Get the post redirect URI.
var properties = new AuthenticationProperties(signout.Properties); var properties = signout.Properties;
if (string.IsNullOrEmpty(properties.RedirectUri)) if (string.IsNullOrEmpty(properties.RedirectUri))
{ {
properties.RedirectUri = BuildRedirectUriIfRelative(Options.PostLogoutRedirectUri); properties.RedirectUri = BuildRedirectUriIfRelative(Options.PostLogoutRedirectUri);
@ -181,14 +264,14 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
Logger.PostSignOutRedirect(properties.RedirectUri); Logger.PostSignOutRedirect(properties.RedirectUri);
// Attach the identity token to the logout request when possible. // Attach the identity token to the logout request when possible.
message.IdTokenHint = await Context.Authentication.GetTokenAsync(Options.SignOutScheme, OpenIdConnectParameterNames.IdToken); message.IdTokenHint = await Context.GetTokenAsync(Options.SignOutScheme, OpenIdConnectParameterNames.IdToken);
var redirectContext = new RedirectContext(Context, Options, properties) var redirectContext = new RedirectContext(Context, Scheme, Options, properties)
{ {
ProtocolMessage = message ProtocolMessage = message
}; };
await Options.Events.RedirectToIdentityProviderForSignOut(redirectContext); await Events.RedirectToIdentityProviderForSignOut(redirectContext);
if (redirectContext.HandledResponse) if (redirectContext.HandledResponse)
{ {
Logger.RedirectToIdentityProviderForSignOutHandledResponse(); Logger.RedirectToIdentityProviderForSignOutHandledResponse();
@ -271,7 +354,6 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
if (!string.IsNullOrEmpty(properties?.RedirectUri)) if (!string.IsNullOrEmpty(properties?.RedirectUri))
{ {
Response.Redirect(properties.RedirectUri); Response.Redirect(properties.RedirectUri);
return Task.FromResult(true);
} }
} }
@ -282,7 +364,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// Responds to a 401 Challenge. Sends an OpenIdConnect message to the 'identity authority' to obtain an identity. /// Responds to a 401 Challenge. Sends an OpenIdConnect message to the 'identity authority' to obtain an identity.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
protected override async Task<bool> HandleUnauthorizedAsync(ChallengeContext context) protected override async Task HandleUnauthorizedAsync(ChallengeContext context)
{ {
if (context == null) if (context == null)
{ {
@ -294,8 +376,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
// order for local RedirectUri // order for local RedirectUri
// 1. challenge.Properties.RedirectUri // 1. challenge.Properties.RedirectUri
// 2. CurrentUri if RedirectUri is not set) // 2. CurrentUri if RedirectUri is not set)
var properties = new AuthenticationProperties(context.Properties); var properties = context.Properties;
if (string.IsNullOrEmpty(properties.RedirectUri)) if (string.IsNullOrEmpty(properties.RedirectUri))
{ {
properties.RedirectUri = CurrentUri; properties.RedirectUri = CurrentUri;
@ -335,21 +416,21 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
GenerateCorrelationId(properties); GenerateCorrelationId(properties);
var redirectContext = new RedirectContext(Context, Options, properties) var redirectContext = new RedirectContext(Context, Scheme, Options, properties)
{ {
ProtocolMessage = message ProtocolMessage = message
}; };
await Options.Events.RedirectToIdentityProvider(redirectContext); await Events.RedirectToIdentityProvider(redirectContext);
if (redirectContext.HandledResponse) if (redirectContext.HandledResponse)
{ {
Logger.RedirectToIdentityProviderHandledResponse(); Logger.RedirectToIdentityProviderHandledResponse();
return true; return;
} }
else if (redirectContext.Skipped) else if (redirectContext.Skipped)
{ {
Logger.RedirectToIdentityProviderSkipped(); Logger.RedirectToIdentityProviderSkipped();
return false; return;
} }
message = redirectContext.ProtocolMessage; message = redirectContext.ProtocolMessage;
@ -379,7 +460,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
} }
Response.Redirect(redirectUri); Response.Redirect(redirectUri);
return true; return;
} }
else if (Options.AuthenticationMethod == OpenIdConnectRedirectBehavior.FormPost) else if (Options.AuthenticationMethod == OpenIdConnectRedirectBehavior.FormPost)
{ {
@ -407,7 +488,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
Response.Headers[HeaderNames.Expires] = "-1"; Response.Headers[HeaderNames.Expires] = "-1";
await Response.Body.WriteAsync(buffer, 0, buffer.Length); await Response.Body.WriteAsync(buffer, 0, buffer.Length);
return true; return;
} }
throw new NotImplementedException($"An unsupported authentication method has been configured: {Options.AuthenticationMethod}"); throw new NotImplementedException($"An unsupported authentication method has been configured: {Options.AuthenticationMethod}");
@ -435,7 +516,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
if (Options.SkipUnrecognizedRequests) if (Options.SkipUnrecognizedRequests)
{ {
// Not for us? // Not for us?
return AuthenticateResult.Skip(); return AuthenticateResult.None();
} }
return AuthenticateResult.Fail("An OpenID Connect response cannot contain an " + return AuthenticateResult.Fail("An OpenID Connect response cannot contain an " +
"identity token or an access token when using response_mode=query"); "identity token or an access token when using response_mode=query");
@ -457,7 +538,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
if (Options.SkipUnrecognizedRequests) if (Options.SkipUnrecognizedRequests)
{ {
// Not for us? // Not for us?
return AuthenticateResult.Skip(); return AuthenticateResult.None();
} }
return AuthenticateResult.Fail("No message."); return AuthenticateResult.Fail("No message.");
} }
@ -473,7 +554,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
} }
var messageReceivedContext = await RunMessageReceivedEventAsync(authorizationResponse, properties); var messageReceivedContext = await RunMessageReceivedEventAsync(authorizationResponse, properties);
if (messageReceivedContext.CheckEventResult(out result)) if (messageReceivedContext.IsProcessingComplete(out result))
{ {
return result; return result;
} }
@ -489,7 +570,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
Logger.NullOrEmptyAuthorizationResponseState(); Logger.NullOrEmptyAuthorizationResponseState();
if (Options.SkipUnrecognizedRequests) if (Options.SkipUnrecognizedRequests)
{ {
return AuthenticateResult.Skip(); return AuthenticateResult.None();
} }
return AuthenticateResult.Fail(Resources.MessageStateIsNullOrEmpty); return AuthenticateResult.Fail(Resources.MessageStateIsNullOrEmpty);
} }
@ -504,7 +585,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
if (Options.SkipUnrecognizedRequests) if (Options.SkipUnrecognizedRequests)
{ {
// Not for us? // Not for us?
return AuthenticateResult.Skip(); return AuthenticateResult.None();
} }
return AuthenticateResult.Fail(Resources.MessageStateIsInvalid); return AuthenticateResult.Fail(Resources.MessageStateIsInvalid);
} }
@ -550,7 +631,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
} }
var tokenValidatedContext = await RunTokenValidatedEventAsync(authorizationResponse, null, properties, ticket, jwt, nonce); var tokenValidatedContext = await RunTokenValidatedEventAsync(authorizationResponse, null, properties, ticket, jwt, nonce);
if (tokenValidatedContext.CheckEventResult(out result)) if (tokenValidatedContext.IsProcessingComplete(out result))
{ {
return result; return result;
} }
@ -575,7 +656,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
if (!string.IsNullOrEmpty(authorizationResponse.Code)) if (!string.IsNullOrEmpty(authorizationResponse.Code))
{ {
var authorizationCodeReceivedContext = await RunAuthorizationCodeReceivedEventAsync(authorizationResponse, properties, ticket, jwt); var authorizationCodeReceivedContext = await RunAuthorizationCodeReceivedEventAsync(authorizationResponse, properties, ticket, jwt);
if (authorizationCodeReceivedContext.CheckEventResult(out result)) if (authorizationCodeReceivedContext.IsProcessingComplete(out result))
{ {
return result; return result;
} }
@ -593,7 +674,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
} }
var tokenResponseReceivedContext = await RunTokenResponseReceivedEventAsync(authorizationResponse, tokenEndpointResponse, properties, ticket); var tokenResponseReceivedContext = await RunTokenResponseReceivedEventAsync(authorizationResponse, tokenEndpointResponse, properties, ticket);
if (tokenResponseReceivedContext.CheckEventResult(out result)) if (tokenResponseReceivedContext.IsProcessingComplete(out result))
{ {
return result; return result;
} }
@ -620,7 +701,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
} }
var tokenValidatedContext = await RunTokenValidatedEventAsync(authorizationResponse, tokenEndpointResponse, properties, tokenEndpointTicket, tokenEndpointJwt, nonce); var tokenValidatedContext = await RunTokenValidatedEventAsync(authorizationResponse, tokenEndpointResponse, properties, tokenEndpointTicket, tokenEndpointJwt, nonce);
if (tokenValidatedContext.CheckEventResult(out result)) if (tokenValidatedContext.IsProcessingComplete(out result))
{ {
return result; return result;
} }
@ -689,7 +770,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
} }
var authenticationFailedContext = await RunAuthenticationFailedEventAsync(authorizationResponse, exception); var authenticationFailedContext = await RunAuthenticationFailedEventAsync(authorizationResponse, exception);
if (authenticationFailedContext.CheckEventResult(out result)) if (authenticationFailedContext.IsProcessingComplete(out result))
{ {
return result; return result;
} }
@ -804,7 +885,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
var userInformationReceivedContext = await RunUserInformationReceivedEventAsync(ticket, message, user); var userInformationReceivedContext = await RunUserInformationReceivedEventAsync(ticket, message, user);
AuthenticateResult result; AuthenticateResult result;
if (userInformationReceivedContext.CheckEventResult(out result)) if (userInformationReceivedContext.IsProcessingComplete(out result))
{ {
return result; return result;
} }
@ -861,7 +942,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
int value; int value;
if (int.TryParse(message.ExpiresIn, NumberStyles.Integer, CultureInfo.InvariantCulture, out value)) if (int.TryParse(message.ExpiresIn, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
{ {
var expiresAt = Options.SystemClock.UtcNow + TimeSpan.FromSeconds(value); var expiresAt = Clock.UtcNow + TimeSpan.FromSeconds(value);
// https://www.w3.org/TR/xmlschema-2/#dateTime // https://www.w3.org/TR/xmlschema-2/#dateTime
// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx
tokens.Add(new AuthenticationToken { Name = "expires_at", Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) }); tokens.Add(new AuthenticationToken { Name = "expires_at", Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) });
@ -891,7 +972,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{ {
HttpOnly = true, HttpOnly = true,
Secure = Request.IsHttps, Secure = Request.IsHttps,
Expires = Options.SystemClock.UtcNow.Add(Options.ProtocolValidator.NonceLifetime) Expires = Clock.UtcNow.Add(Options.ProtocolValidator.NonceLifetime)
}); });
} }
@ -971,13 +1052,13 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
private async Task<MessageReceivedContext> RunMessageReceivedEventAsync(OpenIdConnectMessage message, AuthenticationProperties properties) private async Task<MessageReceivedContext> RunMessageReceivedEventAsync(OpenIdConnectMessage message, AuthenticationProperties properties)
{ {
Logger.MessageReceived(message.BuildRedirectUrl()); Logger.MessageReceived(message.BuildRedirectUrl());
var messageReceivedContext = new MessageReceivedContext(Context, Options) var messageReceivedContext = new MessageReceivedContext(Context, Scheme, Options)
{ {
ProtocolMessage = message, ProtocolMessage = message,
Properties = properties, Properties = properties,
}; };
await Options.Events.MessageReceived(messageReceivedContext); await Events.MessageReceived(messageReceivedContext);
if (messageReceivedContext.HandledResponse) if (messageReceivedContext.HandledResponse)
{ {
Logger.MessageReceivedContextHandledResponse(); Logger.MessageReceivedContextHandledResponse();
@ -992,7 +1073,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
private async Task<TokenValidatedContext> RunTokenValidatedEventAsync(OpenIdConnectMessage authorizationResponse, OpenIdConnectMessage tokenEndpointResponse, AuthenticationProperties properties, AuthenticationTicket ticket, JwtSecurityToken jwt, string nonce) private async Task<TokenValidatedContext> RunTokenValidatedEventAsync(OpenIdConnectMessage authorizationResponse, OpenIdConnectMessage tokenEndpointResponse, AuthenticationProperties properties, AuthenticationTicket ticket, JwtSecurityToken jwt, string nonce)
{ {
var tokenValidatedContext = new TokenValidatedContext(Context, Options) var tokenValidatedContext = new TokenValidatedContext(Context, Scheme, Options)
{ {
ProtocolMessage = authorizationResponse, ProtocolMessage = authorizationResponse,
TokenEndpointResponse = tokenEndpointResponse, TokenEndpointResponse = tokenEndpointResponse,
@ -1002,7 +1083,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
Nonce = nonce, Nonce = nonce,
}; };
await Options.Events.TokenValidated(tokenValidatedContext); await Events.TokenValidated(tokenValidatedContext);
if (tokenValidatedContext.HandledResponse) if (tokenValidatedContext.HandledResponse)
{ {
Logger.TokenValidatedHandledResponse(); Logger.TokenValidatedHandledResponse();
@ -1029,7 +1110,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
RedirectUri = properties.Items[OpenIdConnectDefaults.RedirectUriForCodePropertiesKey] RedirectUri = properties.Items[OpenIdConnectDefaults.RedirectUriForCodePropertiesKey]
}; };
var authorizationCodeReceivedContext = new AuthorizationCodeReceivedContext(Context, Options) var authorizationCodeReceivedContext = new AuthorizationCodeReceivedContext(Context, Scheme, Options)
{ {
ProtocolMessage = authorizationResponse, ProtocolMessage = authorizationResponse,
Properties = properties, Properties = properties,
@ -1039,7 +1120,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
Backchannel = Backchannel, Backchannel = Backchannel,
}; };
await Options.Events.AuthorizationCodeReceived(authorizationCodeReceivedContext); await Events.AuthorizationCodeReceived(authorizationCodeReceivedContext);
if (authorizationCodeReceivedContext.HandledResponse) if (authorizationCodeReceivedContext.HandledResponse)
{ {
Logger.AuthorizationCodeReceivedContextHandledResponse(); Logger.AuthorizationCodeReceivedContextHandledResponse();
@ -1059,14 +1140,14 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
AuthenticationTicket ticket) AuthenticationTicket ticket)
{ {
Logger.TokenResponseReceived(); Logger.TokenResponseReceived();
var eventContext = new TokenResponseReceivedContext(Context, Options, properties) var eventContext = new TokenResponseReceivedContext(Context, Scheme, Options, properties)
{ {
ProtocolMessage = message, ProtocolMessage = message,
TokenEndpointResponse = tokenEndpointResponse, TokenEndpointResponse = tokenEndpointResponse,
Ticket = ticket Ticket = ticket
}; };
await Options.Events.TokenResponseReceived(eventContext); await Events.TokenResponseReceived(eventContext);
if (eventContext.HandledResponse) if (eventContext.HandledResponse)
{ {
Logger.TokenResponseReceivedHandledResponse(); Logger.TokenResponseReceivedHandledResponse();
@ -1083,14 +1164,14 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{ {
Logger.UserInformationReceived(user.ToString()); Logger.UserInformationReceived(user.ToString());
var userInformationReceivedContext = new UserInformationReceivedContext(Context, Options) var userInformationReceivedContext = new UserInformationReceivedContext(Context, Scheme, Options)
{ {
Ticket = ticket, Ticket = ticket,
ProtocolMessage = message, ProtocolMessage = message,
User = user, User = user,
}; };
await Options.Events.UserInformationReceived(userInformationReceivedContext); await Events.UserInformationReceived(userInformationReceivedContext);
if (userInformationReceivedContext.HandledResponse) if (userInformationReceivedContext.HandledResponse)
{ {
Logger.UserInformationReceivedHandledResponse(); Logger.UserInformationReceivedHandledResponse();
@ -1105,13 +1186,13 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
private async Task<AuthenticationFailedContext> RunAuthenticationFailedEventAsync(OpenIdConnectMessage message, Exception exception) private async Task<AuthenticationFailedContext> RunAuthenticationFailedEventAsync(OpenIdConnectMessage message, Exception exception)
{ {
var authenticationFailedContext = new AuthenticationFailedContext(Context, Options) var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options)
{ {
ProtocolMessage = message, ProtocolMessage = message,
Exception = exception Exception = exception
}; };
await Options.Events.AuthenticationFailed(authenticationFailedContext); await Events.AuthenticationFailed(authenticationFailedContext);
if (authenticationFailedContext.HandledResponse) if (authenticationFailedContext.HandledResponse)
{ {
Logger.AuthenticationFailedContextHandledResponse(); Logger.AuthenticationFailedContextHandledResponse();
@ -1161,7 +1242,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
throw new SecurityTokenException(string.Format(CultureInfo.InvariantCulture, Resources.UnableToValidateToken, idToken)); throw new SecurityTokenException(string.Format(CultureInfo.InvariantCulture, Resources.UnableToValidateToken, idToken));
} }
var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme); var ticket = new AuthenticationTicket(principal, properties, Scheme.Name);
if (Options.UseTokenLifetime) if (Options.UseTokenLifetime)
{ {
@ -1220,5 +1301,18 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
description, description,
errorUri)); errorUri));
} }
private class StringSerializer : IDataSerializer<string>
{
public string Deserialize(byte[] data)
{
return Encoding.UTF8.GetString(data);
}
public byte[] Serialize(string model)
{
return Encoding.UTF8.GetBytes(model);
}
}
} }
} }

View File

@ -1,209 +0,0 @@
// 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.Net.Http;
using System.Text;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{
/// <summary>
/// ASP.NET Core middleware for obtaining identities using OpenIdConnect protocol.
/// </summary>
public class OpenIdConnectMiddleware : AuthenticationMiddleware<OpenIdConnectOptions>
{
/// <summary>
/// Initializes a <see cref="OpenIdConnectMiddleware"/>
/// </summary>
/// <param name="next">The next middleware in the middleware pipeline to invoke.</param>
/// <param name="dataProtectionProvider"> provider for creating a data protector.</param>
/// <param name="loggerFactory">factory for creating a <see cref="ILogger"/>.</param>
/// <param name="encoder"></param>
/// <param name="services"></param>
/// <param name="sharedOptions"></param>
/// <param name="options"></param>
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/>.</param>
public OpenIdConnectMiddleware(
RequestDelegate next,
IDataProtectionProvider dataProtectionProvider,
ILoggerFactory loggerFactory,
UrlEncoder encoder,
IServiceProvider services,
IOptions<SharedAuthenticationOptions> sharedOptions,
IOptions<OpenIdConnectOptions> options,
HtmlEncoder htmlEncoder)
: base(next, options, loggerFactory, encoder)
{
if (next == null)
{
throw new ArgumentNullException(nameof(next));
}
if (dataProtectionProvider == null)
{
throw new ArgumentNullException(nameof(dataProtectionProvider));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
if (encoder == null)
{
throw new ArgumentNullException(nameof(encoder));
}
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (sharedOptions == null)
{
throw new ArgumentNullException(nameof(sharedOptions));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
if (htmlEncoder == null)
{
throw new ArgumentNullException(nameof(htmlEncoder));
}
if (string.IsNullOrEmpty(Options.ClientId))
{
throw new ArgumentException("Options.ClientId must be provided", nameof(Options.ClientId));
}
if (!Options.CallbackPath.HasValue)
{
throw new ArgumentException("Options.CallbackPath must be provided.");
}
if (string.IsNullOrEmpty(Options.SignInScheme))
{
Options.SignInScheme = sharedOptions.Value.SignInScheme;
}
if (string.IsNullOrEmpty(Options.SignInScheme))
{
throw new ArgumentException("Options.SignInScheme is required.");
}
if (string.IsNullOrEmpty(Options.SignOutScheme))
{
Options.SignOutScheme = Options.SignInScheme;
}
HtmlEncoder = htmlEncoder;
if (Options.StateDataFormat == null)
{
var dataProtector = dataProtectionProvider.CreateProtector(
typeof(OpenIdConnectMiddleware).FullName,
typeof(string).FullName,
Options.AuthenticationScheme,
"v1");
Options.StateDataFormat = new PropertiesDataFormat(dataProtector);
}
if (Options.StringDataFormat == null)
{
var dataProtector = dataProtectionProvider.CreateProtector(
typeof(OpenIdConnectMiddleware).FullName,
typeof(string).FullName,
Options.AuthenticationScheme,
"v1");
Options.StringDataFormat = new SecureDataFormat<string>(new StringSerializer(), dataProtector);
}
if (Options.Events == null)
{
Options.Events = new OpenIdConnectEvents();
}
if (string.IsNullOrEmpty(Options.TokenValidationParameters.ValidAudience) && !string.IsNullOrEmpty(Options.ClientId))
{
Options.TokenValidationParameters.ValidAudience = Options.ClientId;
}
Backchannel = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OpenIdConnect middleware");
Backchannel.Timeout = Options.BackchannelTimeout;
Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
if (Options.ConfigurationManager == null)
{
if (Options.Configuration != null)
{
Options.ConfigurationManager = new StaticConfigurationManager<OpenIdConnectConfiguration>(Options.Configuration);
}
else if (!(string.IsNullOrEmpty(Options.MetadataAddress) && string.IsNullOrEmpty(Options.Authority)))
{
if (string.IsNullOrEmpty(Options.MetadataAddress) && !string.IsNullOrEmpty(Options.Authority))
{
Options.MetadataAddress = Options.Authority;
if (!Options.MetadataAddress.EndsWith("/", StringComparison.Ordinal))
{
Options.MetadataAddress += "/";
}
Options.MetadataAddress += ".well-known/openid-configuration";
}
if (Options.RequireHttpsMetadata && !Options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.");
}
Options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(Options.MetadataAddress, new OpenIdConnectConfigurationRetriever(),
new HttpDocumentRetriever(Backchannel) { RequireHttps = Options.RequireHttpsMetadata });
}
}
if (Options.ConfigurationManager == null)
{
throw new InvalidOperationException($"Provide {nameof(Options.Authority)}, {nameof(Options.MetadataAddress)}, "
+ $"{nameof(Options.Configuration)}, or {nameof(Options.ConfigurationManager)} to {nameof(OpenIdConnectOptions)}");
}
}
protected HttpClient Backchannel { get; private set; }
protected HtmlEncoder HtmlEncoder { get; private set; }
/// <summary>
/// Provides the <see cref="AuthenticationHandler{T}"/> object for processing authentication-related requests.
/// </summary>
/// <returns>An <see cref="AuthenticationHandler{T}"/> configured with the <see cref="OpenIdConnectOptions"/> supplied to the constructor.</returns>
protected override AuthenticationHandler<OpenIdConnectOptions> CreateHandler()
{
return new OpenIdConnectHandler(Backchannel, HtmlEncoder);
}
private class StringSerializer : IDataSerializer<string>
{
public string Deserialize(byte[] data)
{
return Encoding.UTF8.GetString(data);
}
public byte[] Serialize(string model)
{
return Encoding.UTF8.GetBytes(model);
}
}
}
}

View File

@ -8,27 +8,20 @@ using System.Security.Claims;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OAuth.Claims; using Microsoft.AspNetCore.Authentication.OAuth.Claims;
using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication; using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Protocols; using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{ {
/// <summary> /// <summary>
/// Configuration options for <see cref="OpenIdConnectMiddleware"/> /// Configuration options for <see cref="OpenIdConnectHandler"/>
/// </summary> /// </summary>
public class OpenIdConnectOptions : RemoteAuthenticationOptions public class OpenIdConnectOptions : RemoteAuthenticationOptions
{ {
/// <summary>
/// Initializes a new <see cref="OpenIdConnectOptions"/>
/// </summary>
public OpenIdConnectOptions()
: this(OpenIdConnectDefaults.AuthenticationScheme)
{
}
/// <summary> /// <summary>
/// Initializes a new <see cref="OpenIdConnectOptions"/> /// Initializes a new <see cref="OpenIdConnectOptions"/>
/// </summary> /// </summary>
@ -44,11 +37,8 @@ namespace Microsoft.AspNetCore.Builder
/// <para>TokenValidationParameters: new <see cref="TokenValidationParameters"/> with AuthenticationScheme = authenticationScheme.</para> /// <para>TokenValidationParameters: new <see cref="TokenValidationParameters"/> with AuthenticationScheme = authenticationScheme.</para>
/// <para>UseTokenLifetime: false.</para> /// <para>UseTokenLifetime: false.</para>
/// </remarks> /// </remarks>
/// <param name="authenticationScheme"> will be used to when creating the <see cref="System.Security.Claims.ClaimsIdentity"/> for the AuthenticationScheme property.</param> public OpenIdConnectOptions()
public OpenIdConnectOptions(string authenticationScheme)
{ {
AuthenticationScheme = authenticationScheme;
AutomaticChallenge = true;
DisplayName = OpenIdConnectDefaults.Caption; DisplayName = OpenIdConnectDefaults.Caption;
CallbackPath = new PathString("/signin-oidc"); CallbackPath = new PathString("/signin-oidc");
SignedOutCallbackPath = new PathString("/signout-callback-oidc"); SignedOutCallbackPath = new PathString("/signout-callback-oidc");
@ -83,6 +73,30 @@ namespace Microsoft.AspNetCore.Builder
ClaimActions.MapUniqueJsonKey("email", "email"); ClaimActions.MapUniqueJsonKey("email", "email");
} }
/// <summary>
/// Check that the options are valid. Should throw an exception if things are not ok.
/// </summary>
public override void Validate()
{
base.Validate();
if (string.IsNullOrEmpty(ClientId))
{
throw new ArgumentException("Options.ClientId must be provided", nameof(ClientId));
}
if (!CallbackPath.HasValue)
{
throw new ArgumentException("Options.CallbackPath must be provided.", nameof(CallbackPath));
}
if (ConfigurationManager == null)
{
throw new InvalidOperationException($"Provide {nameof(Authority)}, {nameof(MetadataAddress)}, "
+ $"{nameof(Configuration)}, or {nameof(ConfigurationManager)} to {nameof(OpenIdConnectOptions)}");
}
}
/// <summary> /// <summary>
/// Gets or sets the Authority to use when making OpenIdConnect calls. /// Gets or sets the Authority to use when making OpenIdConnect calls.
/// </summary> /// </summary>
@ -111,7 +125,7 @@ namespace Microsoft.AspNetCore.Builder
public IConfigurationManager<OpenIdConnectConfiguration> ConfigurationManager { get; set; } public IConfigurationManager<OpenIdConnectConfiguration> ConfigurationManager { get; set; }
/// <summary> /// <summary>
/// Boolean to set whether the middleware should go to user info endpoint to retrieve additional claims or not after creating an identity from id_token received from token endpoint. /// Boolean to set whether the handler should go to user info endpoint to retrieve additional claims or not after creating an identity from id_token received from token endpoint.
/// The default is 'false'. /// The default is 'false'.
/// </summary> /// </summary>
public bool GetClaimsFromUserInfoEndpoint { get; set; } public bool GetClaimsFromUserInfoEndpoint { get; set; }
@ -133,11 +147,11 @@ namespace Microsoft.AspNetCore.Builder
public string MetadataAddress { get; set; } public string MetadataAddress { get; set; }
/// <summary> /// <summary>
/// Gets or sets the <see cref="IOpenIdConnectEvents"/> to notify when processing OpenIdConnect messages. /// Gets or sets the <see cref="OpenIdConnectEvents"/> to notify when processing OpenIdConnect messages.
/// </summary> /// </summary>
public new IOpenIdConnectEvents Events public new OpenIdConnectEvents Events
{ {
get { return (IOpenIdConnectEvents)base.Events; } get { return (OpenIdConnectEvents)base.Events; }
set { base.Events = value; } set { base.Events = value; }
} }
@ -196,7 +210,7 @@ namespace Microsoft.AspNetCore.Builder
public ICollection<string> Scope { get; } = new HashSet<string>(); public ICollection<string> Scope { get; } = new HashSet<string>();
/// <summary> /// <summary>
/// Requests received on this path will cause the middleware to invoke SignOut using the SignInScheme. /// Requests received on this path will cause the handler to invoke SignOut using the SignInScheme.
/// </summary> /// </summary>
public PathString RemoteSignOutPath { get; set; } public PathString RemoteSignOutPath { get; set; }
@ -207,12 +221,12 @@ namespace Microsoft.AspNetCore.Builder
public string SignOutScheme { get; set; } public string SignOutScheme { get; set; }
/// <summary> /// <summary>
/// Gets or sets the type used to secure data handled by the middleware. /// Gets or sets the type used to secure data handled by the handler.
/// </summary> /// </summary>
public ISecureDataFormat<AuthenticationProperties> StateDataFormat { get; set; } public ISecureDataFormat<AuthenticationProperties> StateDataFormat { get; set; }
/// <summary> /// <summary>
/// Gets or sets the type used to secure strings used by the middleware. /// Gets or sets the type used to secure strings used by the handler.
/// </summary> /// </summary>
public ISecureDataFormat<string> StringDataFormat { get; set; } public ISecureDataFormat<string> StringDataFormat { get; set; }
@ -235,7 +249,7 @@ namespace Microsoft.AspNetCore.Builder
public bool UseTokenLifetime { get; set; } public bool UseTokenLifetime { get; set; }
/// <summary> /// <summary>
/// Indicates if requests to the CallbackPath may also be for other components. If enabled the middleware will pass /// Indicates if requests to the CallbackPath may also be for other components. If enabled the handler will pass
/// requests through that do not contain OpenIdConnect authentication responses. Disabling this and setting the /// requests through that do not contain OpenIdConnect authentication responses. Disabling this and setting the
/// CallbackPath to a dedicated endpoint may provide better error handling. /// CallbackPath to a dedicated endpoint may provide better error handling.
/// This is disabled by default. /// This is disabled by default.

View File

@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authentication.Twitter namespace Microsoft.AspNetCore.Authentication.Twitter
@ -9,19 +8,23 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
/// <summary> /// <summary>
/// Base class for other Twitter contexts. /// Base class for other Twitter contexts.
/// </summary> /// </summary>
public class BaseTwitterContext : BaseContext public class BaseTwitterContext : BaseAuthenticationContext
{ {
/// <summary> /// <summary>
/// Initializes a <see cref="BaseTwitterContext"/> /// Initializes a <see cref="BaseTwitterContext"/>
/// </summary> /// </summary>
/// <param name="context">The HTTP environment</param> /// <param name="context">The HTTP environment</param>
/// <param name="scheme">The scheme data</param>
/// <param name="options">The options for Twitter</param> /// <param name="options">The options for Twitter</param>
public BaseTwitterContext(HttpContext context, TwitterOptions options) /// <param name="properties">The AuthenticationProperties</param>
: base(context) public BaseTwitterContext(HttpContext context, AuthenticationScheme scheme, TwitterOptions options, AuthenticationProperties properties)
: base(context, scheme.Name, properties)
{ {
Options = options; Options = options;
} }
public TwitterOptions Options { get; } public TwitterOptions Options { get; }
public AuthenticationScheme Scheme { get; }
} }
} }

View File

@ -1,26 +0,0 @@
// 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.Authentication.Twitter
{
/// <summary>
/// Specifies callback methods which the <see cref="TwitterMiddleware"></see> invokes to enable developer control over the authentication process. />
/// </summary>
public interface ITwitterEvents : IRemoteAuthenticationEvents
{
/// <summary>
/// Invoked whenever Twitter succesfully authenticates a user
/// </summary>
/// <param name="context">Contains information about the login session as well as the user <see cref="System.Security.Claims.ClaimsIdentity"/>.</param>
/// <returns>A <see cref="Task"/> representing the completed operation.</returns>
Task CreatingTicket(TwitterCreatingTicketContext context);
/// <summary>
/// Called when a Challenge causes a redirect to authorize endpoint in the Twitter middleware
/// </summary>
/// <param name="context">Contains redirect URI and <see cref="Http.Authentication.AuthenticationProperties"/> of the challenge </param>
Task RedirectToAuthorizationEndpoint(TwitterRedirectToAuthorizationEndpointContext context);
}
}

View File

@ -3,9 +3,7 @@
using System; using System;
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace Microsoft.AspNetCore.Authentication.Twitter namespace Microsoft.AspNetCore.Authentication.Twitter
@ -19,21 +17,25 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
/// Initializes a <see cref="TwitterCreatingTicketContext"/> /// Initializes a <see cref="TwitterCreatingTicketContext"/>
/// </summary> /// </summary>
/// <param name="context">The HTTP environment</param> /// <param name="context">The HTTP environment</param>
/// <param name="scheme">The scheme data</param>
/// <param name="options">The options for Twitter</param> /// <param name="options">The options for Twitter</param>
/// <param name="userId">Twitter user ID</param> /// <param name="userId">Twitter user ID</param>
/// <param name="screenName">Twitter screen name</param> /// <param name="screenName">Twitter screen name</param>
/// <param name="accessToken">Twitter access token</param> /// <param name="accessToken">Twitter access token</param>
/// <param name="accessTokenSecret">Twitter access token secret</param> /// <param name="accessTokenSecret">Twitter access token secret</param>
/// <param name="user">User details</param> /// <param name="user">User details</param>
/// <param name="properties">AuthenticationProperties.</param>
public TwitterCreatingTicketContext( public TwitterCreatingTicketContext(
HttpContext context, HttpContext context,
AuthenticationScheme scheme,
TwitterOptions options, TwitterOptions options,
AuthenticationProperties properties,
string userId, string userId,
string screenName, string screenName,
string accessToken, string accessToken,
string accessTokenSecret, string accessTokenSecret,
JObject user) JObject user)
: base(context, options) : base(context, scheme, options, properties)
{ {
UserId = userId; UserId = userId;
ScreenName = screenName; ScreenName = screenName;
@ -72,10 +74,5 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
/// Gets the <see cref="ClaimsPrincipal"/> representing the user /// Gets the <see cref="ClaimsPrincipal"/> representing the user
/// </summary> /// </summary>
public ClaimsPrincipal Principal { get; set; } public ClaimsPrincipal Principal { get; set; }
/// <summary>
/// Gets or sets a property bag for common authentication properties
/// </summary>
public AuthenticationProperties Properties { get; set; }
} }
} }

View File

@ -8,9 +8,9 @@ using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Authentication.Twitter namespace Microsoft.AspNetCore.Authentication.Twitter
{ {
/// <summary> /// <summary>
/// Default <see cref="ITwitterEvents"/> implementation. /// Default <see cref="TwitterEvents"/> implementation.
/// </summary> /// </summary>
public class TwitterEvents : RemoteAuthenticationEvents, ITwitterEvents public class TwitterEvents : RemoteAuthenticationEvents
{ {
/// <summary> /// <summary>
/// Gets or sets the function that is invoked when the Authenticated method is invoked. /// Gets or sets the function that is invoked when the Authenticated method is invoked.
@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
public virtual Task CreatingTicket(TwitterCreatingTicketContext context) => OnCreatingTicket(context); public virtual Task CreatingTicket(TwitterCreatingTicketContext context) => OnCreatingTicket(context);
/// <summary> /// <summary>
/// Called when a Challenge causes a redirect to authorize endpoint in the Twitter middleware /// Called when a Challenge causes a redirect to authorize endpoint in the Twitter handler
/// </summary> /// </summary>
/// <param name="context">Contains redirect URI and <see cref="Http.Authentication.AuthenticationProperties"/> of the challenge </param> /// <param name="context">Contains redirect URI and <see cref="Http.Authentication.AuthenticationProperties"/> of the challenge </param>
public virtual Task RedirectToAuthorizationEndpoint(TwitterRedirectToAuthorizationEndpointContext context) => OnRedirectToAuthorizationEndpoint(context); public virtual Task RedirectToAuthorizationEndpoint(TwitterRedirectToAuthorizationEndpointContext context) => OnRedirectToAuthorizationEndpoint(context);

View File

@ -1,14 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
namespace Microsoft.AspNetCore.Authentication.Twitter namespace Microsoft.AspNetCore.Authentication.Twitter
{ {
/// <summary> /// <summary>
/// The Context passed when a Challenge causes a redirect to authorize endpoint in the Twitter middleware. /// The Context passed when a Challenge causes a redirect to authorize endpoint in the Twitter handler.
/// </summary> /// </summary>
public class TwitterRedirectToAuthorizationEndpointContext : BaseTwitterContext public class TwitterRedirectToAuthorizationEndpointContext : BaseTwitterContext
{ {
@ -16,12 +14,14 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
/// Creates a new context object. /// Creates a new context object.
/// </summary> /// </summary>
/// <param name="context">The HTTP request context.</param> /// <param name="context">The HTTP request context.</param>
/// <param name="options">The Twitter middleware options.</param> /// <param name="scheme">The scheme data</param>
/// <param name="options">The Twitter handler options.</param>
/// <param name="properties">The authentication properties of the challenge.</param> /// <param name="properties">The authentication properties of the challenge.</param>
/// <param name="redirectUri">The initial redirect URI.</param> /// <param name="redirectUri">The initial redirect URI.</param>
public TwitterRedirectToAuthorizationEndpointContext(HttpContext context, TwitterOptions options, public TwitterRedirectToAuthorizationEndpointContext(HttpContext context, AuthenticationScheme scheme,
AuthenticationProperties properties, string redirectUri)
: base(context, options) TwitterOptions options, AuthenticationProperties properties, string redirectUri)
: base(context, scheme, options, properties)
{ {
RedirectUri = redirectUri; RedirectUri = redirectUri;
Properties = properties; Properties = properties;
@ -31,10 +31,5 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
/// Gets the URI used for the redirect operation. /// Gets the URI used for the redirect operation.
/// </summary> /// </summary>
public string RedirectUri { get; private set; } public string RedirectUri { get; private set; }
/// <summary>
/// Gets the authentication properties of the challenge.
/// </summary>
public AuthenticationProperties Properties { get; private set; }
} }
} }

View File

@ -12,6 +12,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" /> <ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" /> <PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" />
</ItemGroup> </ItemGroup>

View File

@ -1,9 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.Authentication.Twitter; using Microsoft.AspNetCore.Authentication.Twitter;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Builder
{ {
@ -13,38 +12,26 @@ namespace Microsoft.AspNetCore.Builder
public static class TwitterAppBuilderExtensions public static class TwitterAppBuilderExtensions
{ {
/// <summary> /// <summary>
/// Adds the <see cref="TwitterMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables Twitter authentication capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseTwitterAuthentication(this IApplicationBuilder app) public static IApplicationBuilder UseTwitterAuthentication(this IApplicationBuilder app)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<TwitterMiddleware>();
} }
/// <summary> /// <summary>
/// Adds the <see cref="TwitterMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables Twitter authentication capabilities. /// Obsolete, see https://go.microsoft.com/fwlink/?linkid=845470
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
/// <param name="options">An action delegate to configure the provided <see cref="TwitterOptions"/>.</param> /// <param name="options">An action delegate to configure the provided <see cref="TwitterOptions"/>.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
[Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)]
public static IApplicationBuilder UseTwitterAuthentication(this IApplicationBuilder app, TwitterOptions options) public static IApplicationBuilder UseTwitterAuthentication(this IApplicationBuilder app, TwitterOptions options)
{ {
if (app == null) throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
{
throw new ArgumentNullException(nameof(app));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
return app.UseMiddleware<TwitterMiddleware>(Options.Create(options));
} }
} }
} }

View File

@ -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 Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Authentication.Twitter
{
internal class TwitterConfigureOptions : ConfigureNamedOptions<TwitterOptions>
{
// Bind to "Twitter" section by default
public TwitterConfigureOptions(IConfiguration config) :
base(TwitterDefaults.AuthenticationScheme,
options => config.GetSection(TwitterDefaults.AuthenticationScheme).Bind(options))
{ }
}
}

View File

@ -0,0 +1,32 @@
// 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 Microsoft.AspNetCore.Authentication.Twitter;
using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection
{
public static class TwitterExtensions
{
/// <summary>
/// Adds Twitter authentication with options bound against the "Twitter" section
/// from the IConfiguration in the service container.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddTwitterAuthentication(this IServiceCollection services)
{
services.AddSingleton<IConfigureOptions<TwitterOptions>, TwitterConfigureOptions>();
return services.AddTwitterAuthentication(TwitterDefaults.AuthenticationScheme, _ => { });
}
public static IServiceCollection AddTwitterAuthentication(this IServiceCollection services, Action<TwitterOptions> configureOptions)
=> services.AddTwitterAuthentication(TwitterDefaults.AuthenticationScheme, configureOptions);
public static IServiceCollection AddTwitterAuthentication(this IServiceCollection services, string authenticationScheme, Action<TwitterOptions> configureOptions)
{
return services.AddScheme<TwitterOptions, TwitterHandler>(authenticationScheme, configureOptions);
}
}
}

View File

@ -8,13 +8,13 @@ using System.Net.Http;
using System.Security.Claims; using System.Security.Claims;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.AspNetCore.WebUtilities; using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -28,11 +28,46 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
private const string AuthenticationEndpoint = "https://api.twitter.com/oauth/authenticate?oauth_token="; private const string AuthenticationEndpoint = "https://api.twitter.com/oauth/authenticate?oauth_token=";
private const string AccessTokenEndpoint = "https://api.twitter.com/oauth/access_token"; private const string AccessTokenEndpoint = "https://api.twitter.com/oauth/access_token";
private readonly HttpClient _httpClient; private HttpClient Backchannel => Options.Backchannel;
public TwitterHandler(HttpClient httpClient) /// <summary>
/// The handler calls methods on the events which give the application control at certain points where processing is occurring.
/// If it is not provided a default instance is supplied which does nothing when the methods are called.
/// </summary>
protected new TwitterEvents Events
{ {
_httpClient = httpClient; get { return (TwitterEvents)base.Events; }
set { base.Events = value; }
}
public TwitterHandler(IOptions<AuthenticationOptions> sharedOptions, IOptionsSnapshot<TwitterOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
: base(sharedOptions, options, dataProtection, logger, encoder, clock)
{ }
protected override Task<object> CreateEventsAsync() => Task.FromResult<object>(new TwitterEvents());
protected override void InitializeOptions()
{
base.InitializeOptions();
if (Options.StateDataFormat == null)
{
var dataProtector = DataProtection.CreateProtector(
GetType().FullName, Scheme.Name, "v1");
Options.StateDataFormat = new SecureDataFormat<RequestToken>(
new RequestTokenSerializer(),
dataProtector);
}
if (Options.Backchannel == null)
{
Options.Backchannel = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
Options.Backchannel.Timeout = Options.BackchannelTimeout;
Options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
Options.Backchannel.DefaultRequestHeaders.Accept.ParseAdd("*/*");
Options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core Twitter handler");
Options.Backchannel.DefaultRequestHeaders.ExpectContinue = false;
}
} }
protected override async Task<AuthenticateResult> HandleRemoteAuthenticateAsync() protected override async Task<AuthenticateResult> HandleRemoteAuthenticateAsync()
@ -113,30 +148,29 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
action.Run(user, identity, Options.ClaimsIssuer); action.Run(user, identity, Options.ClaimsIssuer);
} }
var context = new TwitterCreatingTicketContext(Context, Options, token.UserId, token.ScreenName, token.Token, token.TokenSecret, user) var context = new TwitterCreatingTicketContext(Context, Scheme, Options, properties, token.UserId, token.ScreenName, token.Token, token.TokenSecret, user)
{ {
Principal = new ClaimsPrincipal(identity), Principal = new ClaimsPrincipal(identity)
Properties = properties
}; };
await Options.Events.CreatingTicket(context); await Events.CreatingTicket(context);
if (context.Principal?.Identity == null) if (context.Principal?.Identity == null)
{ {
return null; return null;
} }
return new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme); return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
} }
protected override async Task<bool> HandleUnauthorizedAsync(ChallengeContext context) protected override async Task HandleUnauthorizedAsync(ChallengeContext context)
{ {
if (context == null) if (context == null)
{ {
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
var properties = new AuthenticationProperties(context.Properties); var properties = context.Properties;
if (string.IsNullOrEmpty(properties.RedirectUri)) if (string.IsNullOrEmpty(properties.RedirectUri))
{ {
@ -151,16 +185,13 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
{ {
HttpOnly = true, HttpOnly = true,
Secure = Request.IsHttps, Secure = Request.IsHttps,
Expires = Options.SystemClock.UtcNow.Add(Options.RemoteAuthenticationTimeout), Expires = Clock.UtcNow.Add(Options.RemoteAuthenticationTimeout),
}; };
Response.Cookies.Append(StateCookie, Options.StateDataFormat.Protect(requestToken), cookieOptions); Response.Cookies.Append(StateCookie, Options.StateDataFormat.Protect(requestToken), cookieOptions);
var redirectContext = new TwitterRedirectToAuthorizationEndpointContext( var redirectContext = new TwitterRedirectToAuthorizationEndpointContext(Context, Scheme, Options, properties, twitterAuthenticationEndpoint);
Context, Options, await Events.RedirectToAuthorizationEndpoint(redirectContext);
properties, twitterAuthenticationEndpoint);
await Options.Events.RedirectToAuthorizationEndpoint(redirectContext);
return true;
} }
private async Task<RequestToken> ObtainRequestTokenAsync(string callBackUri, AuthenticationProperties properties) private async Task<RequestToken> ObtainRequestTokenAsync(string callBackUri, AuthenticationProperties properties)
@ -209,7 +240,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
var request = new HttpRequestMessage(HttpMethod.Post, RequestTokenEndpoint); var request = new HttpRequestMessage(HttpMethod.Post, RequestTokenEndpoint);
request.Headers.Add("Authorization", authorizationHeaderBuilder.ToString()); request.Headers.Add("Authorization", authorizationHeaderBuilder.ToString());
var response = await _httpClient.SendAsync(request, Context.RequestAborted); var response = await Backchannel.SendAsync(request, Context.RequestAborted);
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
var responseText = await response.Content.ReadAsStringAsync(); var responseText = await response.Content.ReadAsStringAsync();
@ -279,7 +310,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
request.Content = new FormUrlEncodedContent(formPairs); request.Content = new FormUrlEncodedContent(formPairs);
var response = await _httpClient.SendAsync(request, Context.RequestAborted); var response = await Backchannel.SendAsync(request, Context.RequestAborted);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
@ -350,7 +381,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
var request = new HttpRequestMessage(HttpMethod.Get, resource_url + "?include_email=true"); var request = new HttpRequestMessage(HttpMethod.Get, resource_url + "?include_email=true");
request.Headers.Add("Authorization", authorizationHeaderBuilder.ToString()); request.Headers.Add("Authorization", authorizationHeaderBuilder.ToString());
var response = await _httpClient.SendAsync(request, Context.RequestAborted); var response = await Backchannel.SendAsync(request, Context.RequestAborted);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
Logger.LogError("Email request failed with a status code of " + response.StatusCode); Logger.LogError("Email request failed with a status code of " + response.StatusCode);

Some files were not shown because too many files have changed in this diff Show More