Merge remote-tracking branch 'Security/rybrande/release21ToSrc' into rybrande/Mondo2.1
This commit is contained in:
commit
db7b28d475
|
|
@ -0,0 +1,32 @@
|
|||
[Oo]bj/
|
||||
[Bb]in/
|
||||
TestResults/
|
||||
.nuget/
|
||||
_ReSharper.*/
|
||||
packages/
|
||||
artifacts/
|
||||
PublishProfiles/
|
||||
*.user
|
||||
*.suo
|
||||
*.cache
|
||||
*.docstates
|
||||
_ReSharper.*
|
||||
nuget.exe
|
||||
*net45.csproj
|
||||
*net451.csproj
|
||||
*k10.csproj
|
||||
*.psess
|
||||
*.vsp
|
||||
*.pidb
|
||||
*.userprefs
|
||||
*DS_Store
|
||||
*.ncrunchsolution
|
||||
*.*sdf
|
||||
*.ipch
|
||||
*.sln.ide
|
||||
project.lock.json
|
||||
.build/
|
||||
.testPublish/
|
||||
/.vs/
|
||||
.vscode/
|
||||
global.json
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<Project>
|
||||
<Import
|
||||
Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), AspNetCoreSettings.props))\AspNetCoreSettings.props"
|
||||
Condition=" '$(CI)' != 'true' AND '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), AspNetCoreSettings.props))' != '' " />
|
||||
|
||||
<Import Project="version.props" />
|
||||
<Import Project="build\dependencies.props" />
|
||||
<Import Project="build\sources.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<Product>Microsoft ASP.NET Core</Product>
|
||||
<RepositoryUrl>https://github.com/aspnet/Security</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>
|
||||
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)build\Key.snk</AssemblyOriginatorKeyFile>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<PublicSign Condition="'$(OS)' != 'Windows_NT'">true</PublicSign>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">$(MicrosoftNETCoreApp20PackageVersion)</RuntimeFrameworkVersion>
|
||||
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">$(MicrosoftNETCoreApp21PackageVersion)</RuntimeFrameworkVersion>
|
||||
<NETStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard2.0' ">$(NETStandardLibrary20PackageVersion)</NETStandardImplicitPackageVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"adx-nonshipping": {
|
||||
"rules": [],
|
||||
"packages": {
|
||||
"Microsoft.AspNetCore.ChunkingCookieManager.Sources": {}
|
||||
}
|
||||
},
|
||||
"Default": {
|
||||
"rules": [
|
||||
"DefaultCompositeRule"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
ASP.NET Security
|
||||
========
|
||||
|
||||
AppVeyor: [](https://ci.appveyor.com/project/aspnetci/Security/branch/dev)
|
||||
|
||||
Travis: [](https://travis-ci.org/aspnet/Security)
|
||||
|
||||
Contains the security and authorization middlewares for ASP.NET Core.
|
||||
|
||||
A list of community projects related to authentication and security for ASP.NET Core are listed in the [documentation](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/community).
|
||||
|
||||
### Notes
|
||||
|
||||
ASP.NET Security will not include Basic Authentication middleware due to its potential insecurity and performance problems. If you host under IIS you can enable it via IIS configuration.
|
||||
|
||||
|
||||
This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo.
|
||||
|
|
@ -0,0 +1,556 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2027
|
||||
MinimumVisualStudioVersion = 15.0.26730.03
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4D2B6A51-2F9F-44F5-8131-EA5CAC053652}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
src\Directory.Build.props = src\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CookieSample", "samples\CookieSample\CookieSample.csproj", "{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{7BF11F3A-60B6-4796-B504-579C67FFBA34}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
test\Directory.Build.props = test\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SocialSample", "samples\SocialSample\SocialSample.csproj", "{8C73D216-332D-41D8-BFD0-45BC4BC36552}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CookieSessionSample", "samples\CookieSessionSample\CookieSessionSample.csproj", "{19711880-46DA-4A26-9E0F-9B2E41D27651}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIdConnectSample", "samples\OpenIdConnectSample\OpenIdConnectSample.csproj", "{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}"
|
||||
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}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication", "src\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.csproj", "{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}"
|
||||
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}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Google", "src\Microsoft.AspNetCore.Authentication.Google\Microsoft.AspNetCore.Authentication.Google.csproj", "{76579C39-B829-490D-B8BE-1BD35FE8412E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.OpenIdConnect", "src\Microsoft.AspNetCore.Authentication.OpenIdConnect\Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj", "{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.MicrosoftAccount", "src\Microsoft.AspNetCore.Authentication.MicrosoftAccount\Microsoft.AspNetCore.Authentication.MicrosoftAccount.csproj", "{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Twitter", "src\Microsoft.AspNetCore.Authentication.Twitter\Microsoft.AspNetCore.Authentication.Twitter.csproj", "{0330FFF6-B4B5-42DD-8C99-26A789569000}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.OAuth", "src\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj", "{1657C79E-7755-4AEE-9D61-571295B69A30}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Test", "test\Microsoft.AspNetCore.Authentication.Test\Microsoft.AspNetCore.Authentication.Test.csproj", "{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authorization.Test", "test\Microsoft.AspNetCore.Authorization.Test\Microsoft.AspNetCore.Authorization.Test.csproj", "{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authorization", "src\Microsoft.AspNetCore.Authorization\Microsoft.AspNetCore.Authorization.csproj", "{6AB3E514-5894-4131-9399-DC7D5284ADDB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.CookiePolicy", "src\Microsoft.AspNetCore.CookiePolicy\Microsoft.AspNetCore.CookiePolicy.csproj", "{86183DC3-02A8-4A68-8B60-71ECEC066E79}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.CookiePolicy.Test", "test\Microsoft.AspNetCore.CookiePolicy.Test\Microsoft.AspNetCore.CookiePolicy.Test.csproj", "{1790E052-646F-4529-B90E-6FEA95520D69}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.JwtBearer", "src\Microsoft.AspNetCore.Authentication.JwtBearer\Microsoft.AspNetCore.Authentication.JwtBearer.csproj", "{2755BFE5-7421-4A31-A644-F817DF5CAA98}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JwtBearerSample", "samples\JwtBearerSample\JwtBearerSample.csproj", "{D399B84F-591B-4E98-92BA-B0F63E7B6957}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Owin.Security.Interop", "src\Microsoft.Owin.Security.Interop\Microsoft.Owin.Security.Interop.csproj", "{A7922DD8-09F1-43E4-938B-CC523EA08898}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Owin.Security.Interop.Test", "test\Microsoft.Owin.Security.Interop.Test\Microsoft.Owin.Security.Interop.Test.csproj", "{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIdConnect.AzureAdSample", "samples\OpenIdConnect.AzureAdSample\OpenIdConnect.AzureAdSample.csproj", "{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test", "test\Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test\Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.csproj", "{51563775-C659-4907-9BAF-9995BAB87D01}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{86BD08B1-F978-4F58-9982-2A017807F01C}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
build\dependencies.props = build\dependencies.props
|
||||
Directory.Build.props = Directory.Build.props
|
||||
Directory.Build.targets = Directory.Build.targets
|
||||
build\Key.snk = build\Key.snk
|
||||
NuGet.config = NuGet.config
|
||||
build\repo.props = build\repo.props
|
||||
build\sources.props = build\sources.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authorization.Policy", "src\Microsoft.AspNetCore.Authorization.Policy\Microsoft.AspNetCore.Authorization.Policy.csproj", "{58194599-F07D-47A3-9DF2-E21A22C5EF9E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CookiePolicySample", "samples\CookiePolicySample\CookiePolicySample.csproj", "{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.WsFederation", "src\Microsoft.AspNetCore.Authentication.WsFederation\Microsoft.AspNetCore.Authentication.WsFederation.csproj", "{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WsFedSample", "samples\WsFedSample\WsFedSample.csproj", "{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|Mixed Platforms = Release|Mixed Platforms
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|Any CPU.ActiveCfg = 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.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}.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|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|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
|
||||
{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|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|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}.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|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|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
|
||||
{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|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|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}.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|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|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
|
||||
{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|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|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.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.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.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.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.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.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.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.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.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.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
|
||||
{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|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|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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.Build.0 = Release|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|x86.Build.0 = Release|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|x64.Build.0 = Release|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{558C2C2A-AED8-49DE-BB60-D5F8AE06C714} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
|
||||
{8C73D216-332D-41D8-BFD0-45BC4BC36552} = {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}
|
||||
{FC152CC4-054B-457E-8D91-389C5DE3C561} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB} = {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}
|
||||
{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{ACB45E19-F520-4D0C-8916-B0CEB9C017FE} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{0330FFF6-B4B5-42DD-8C99-26A789569000} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{1657C79E-7755-4AEE-9D61-571295B69A30} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
|
||||
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
|
||||
{6AB3E514-5894-4131-9399-DC7D5284ADDB} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{86183DC3-02A8-4A68-8B60-71ECEC066E79} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{1790E052-646F-4529-B90E-6FEA95520D69} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
|
||||
{2755BFE5-7421-4A31-A644-F817DF5CAA98} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{D399B84F-591B-4E98-92BA-B0F63E7B6957} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
|
||||
{A7922DD8-09F1-43E4-938B-CC523EA08898} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
|
||||
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
|
||||
{51563775-C659-4907-9BAF-9995BAB87D01} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
|
||||
{58194599-F07D-47A3-9DF2-E21A22C5EF9E} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
|
||||
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
|
||||
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {ABF8089E-43D0-4010-84A7-7A9DCFE49357}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Binary file not shown.
|
|
@ -0,0 +1,58 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- These package versions may be overridden or updated by automation. -->
|
||||
<PropertyGroup Label="Package Versions: Auto">
|
||||
<InternalAspNetCoreSdkPackageVersion>2.1.3-rtm-15802</InternalAspNetCoreSdkPackageVersion>
|
||||
<MicrosoftIdentityModelClientsActiveDirectoryPackageVersion>3.14.2</MicrosoftIdentityModelClientsActiveDirectoryPackageVersion>
|
||||
<MicrosoftIdentityModelProtocolsOpenIdConnectPackageVersion>5.2.0</MicrosoftIdentityModelProtocolsOpenIdConnectPackageVersion>
|
||||
<MicrosoftIdentityModelProtocolsWsFederationPackageVersion>5.2.0</MicrosoftIdentityModelProtocolsWsFederationPackageVersion>
|
||||
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
|
||||
<MicrosoftNETCoreApp21PackageVersion>2.1.2</MicrosoftNETCoreApp21PackageVersion>
|
||||
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
|
||||
<MicrosoftOwinSecurityCookiesPackageVersion>3.0.1</MicrosoftOwinSecurityCookiesPackageVersion>
|
||||
<MicrosoftOwinSecurityPackageVersion>3.0.1</MicrosoftOwinSecurityPackageVersion>
|
||||
<MicrosoftOwinTestingPackageVersion>3.0.1</MicrosoftOwinTestingPackageVersion>
|
||||
<NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
|
||||
<NewtonsoftJsonPackageVersion>11.0.2</NewtonsoftJsonPackageVersion>
|
||||
<SystemIdentityModelTokensJwtPackageVersion>5.2.0</SystemIdentityModelTokensJwtPackageVersion>
|
||||
<XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion>
|
||||
<XunitPackageVersion>2.3.1</XunitPackageVersion>
|
||||
<XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- This may import a generated file which may override the variables above. -->
|
||||
<Import Project="$(DotNetPackageVersionPropsPath)" Condition=" '$(DotNetPackageVersionPropsPath)' != '' " />
|
||||
|
||||
<!-- These are package versions that should not be overridden or updated by automation. -->
|
||||
<PropertyGroup Label="Package Versions: Pinned">
|
||||
<MicrosoftAspNetCoreAuthenticationAbstractionsPackageVersion>2.1.1</MicrosoftAspNetCoreAuthenticationAbstractionsPackageVersion>
|
||||
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.1.1</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
|
||||
<MicrosoftAspNetCoreDataProtectionExtensionsPackageVersion>2.1.1</MicrosoftAspNetCoreDataProtectionExtensionsPackageVersion>
|
||||
<MicrosoftAspNetCoreDataProtectionPackageVersion>2.1.1</MicrosoftAspNetCoreDataProtectionPackageVersion>
|
||||
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.1.1</MicrosoftAspNetCoreDiagnosticsPackageVersion>
|
||||
<MicrosoftAspNetCoreHostingPackageVersion>2.1.1</MicrosoftAspNetCoreHostingPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.1.1</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpPackageVersion>2.1.1</MicrosoftAspNetCoreHttpPackageVersion>
|
||||
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.1.1</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
|
||||
<MicrosoftAspNetCoreServerKestrelHttpsPackageVersion>2.1.2</MicrosoftAspNetCoreServerKestrelHttpsPackageVersion>
|
||||
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.1.2</MicrosoftAspNetCoreServerKestrelPackageVersion>
|
||||
<MicrosoftAspNetCoreStaticFilesPackageVersion>2.1.1</MicrosoftAspNetCoreStaticFilesPackageVersion>
|
||||
<MicrosoftAspNetCoreTestHostPackageVersion>2.1.1</MicrosoftAspNetCoreTestHostPackageVersion>
|
||||
<MicrosoftAspNetCoreTestingPackageVersion>2.1.0</MicrosoftAspNetCoreTestingPackageVersion>
|
||||
<MicrosoftExtensionsCachingMemoryPackageVersion>2.1.1</MicrosoftExtensionsCachingMemoryPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>2.1.1</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationUserSecretsPackageVersion>2.1.1</MicrosoftExtensionsConfigurationUserSecretsPackageVersion>
|
||||
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.1.1</MicrosoftExtensionsDependencyInjectionPackageVersion>
|
||||
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>2.1.1</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
|
||||
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.1</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsLoggingConsolePackageVersion>2.1.1</MicrosoftExtensionsLoggingConsolePackageVersion>
|
||||
<MicrosoftExtensionsLoggingDebugPackageVersion>2.1.1</MicrosoftExtensionsLoggingDebugPackageVersion>
|
||||
<MicrosoftExtensionsLoggingPackageVersion>2.1.1</MicrosoftExtensionsLoggingPackageVersion>
|
||||
<MicrosoftExtensionsOptionsPackageVersion>2.1.1</MicrosoftExtensionsOptionsPackageVersion>
|
||||
<MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.1.1</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
|
||||
<MicrosoftExtensionsWebEncodersPackageVersion>2.1.1</MicrosoftExtensionsWebEncodersPackageVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<Project>
|
||||
<Import Project="dependencies.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.Owin.Security.Interop.Test\*.csproj" Condition="'$(OS)' != 'Windows_NT'" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!-- These properties are use by the automation that updates dependencies.props -->
|
||||
<LineupPackageId>Internal.AspNetCore.Universe.Lineup</LineupPackageId>
|
||||
<LineupPackageVersion>2.1.0-rc1-*</LineupPackageVersion>
|
||||
<LineupPackageRestoreSource>https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json</LineupPackageRestoreSource>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp20PackageVersion)" />
|
||||
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp21PackageVersion)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<Project>
|
||||
<Import Project="$(DotNetRestoreSourcePropsPath)" Condition="'$(DotNetRestoreSourcePropsPath)' != ''"/>
|
||||
|
||||
<PropertyGroup Label="RestoreSources">
|
||||
<RestoreSources>$(DotNetRestoreSources)</RestoreSources>
|
||||
<RestoreSources Condition="'$(DotNetBuildOffline)' != 'true' AND '$(AspNetUniverseBuildOffline)' != 'true' ">
|
||||
$(RestoreSources);
|
||||
https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;
|
||||
https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
|
||||
https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json;
|
||||
</RestoreSources>
|
||||
<RestoreSources Condition="'$(DotNetBuildOffline)' != 'true'">
|
||||
$(RestoreSources);
|
||||
https://api.nuget.org/v3/index.json;
|
||||
</RestoreSources>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.CookiePolicy\Microsoft.AspNetCore.CookiePolicy.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CookiePolicySample
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.ConfigureLogging(factory =>
|
||||
{
|
||||
factory.AddConsole();
|
||||
factory.AddFilter("Microsoft", LogLevel.Trace);
|
||||
})
|
||||
.UseKestrel()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:1788/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"CookieSample": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:12345",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace CookiePolicySample
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie();
|
||||
services.Configure<CookiePolicyOptions>(options =>
|
||||
{
|
||||
options.CheckConsentNeeded = context => context.Request.PathBase.Equals("/NeedsConsent");
|
||||
|
||||
options.OnAppendCookie = context => { };
|
||||
});
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseCookiePolicy();
|
||||
app.UseAuthentication();
|
||||
|
||||
app.Map("/NeedsConsent", NestedApp);
|
||||
app.Map("/NeedsNoConsent", NestedApp);
|
||||
NestedApp(app);
|
||||
}
|
||||
|
||||
private void NestedApp(IApplicationBuilder app)
|
||||
{
|
||||
app.Run(async context =>
|
||||
{
|
||||
var path = context.Request.Path;
|
||||
switch (path)
|
||||
{
|
||||
case "/Login":
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "bob") },
|
||||
CookieAuthenticationDefaults.AuthenticationScheme));
|
||||
await context.SignInAsync(user);
|
||||
break;
|
||||
case "/Logout":
|
||||
await context.SignOutAsync();
|
||||
break;
|
||||
case "/CreateTempCookie":
|
||||
context.Response.Cookies.Append("Temp", "1");
|
||||
break;
|
||||
case "/RemoveTempCookie":
|
||||
context.Response.Cookies.Delete("Temp");
|
||||
break;
|
||||
case "/GrantConsent":
|
||||
context.Features.Get<ITrackingConsentFeature>().GrantConsent();
|
||||
break;
|
||||
case "/WithdrawConsent":
|
||||
context.Features.Get<ITrackingConsentFeature>().WithdrawConsent();
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Debug log when cookie is suppressed
|
||||
|
||||
await HomePage(context);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task HomePage(HttpContext context)
|
||||
{
|
||||
var response = context.Response;
|
||||
var cookies = context.Request.Cookies;
|
||||
response.ContentType = "text/html";
|
||||
await response.WriteAsync("<html><body>\r\n");
|
||||
|
||||
await response.WriteAsync($"<a href=\"{context.Request.PathBase}/\">Home</a><br>\r\n");
|
||||
await response.WriteAsync($"<a href=\"{context.Request.PathBase}/Login\">Login</a><br>\r\n");
|
||||
await response.WriteAsync($"<a href=\"{context.Request.PathBase}/Logout\">Logout</a><br>\r\n");
|
||||
await response.WriteAsync($"<a href=\"{context.Request.PathBase}/CreateTempCookie\">Create Temp Cookie</a><br>\r\n");
|
||||
await response.WriteAsync($"<a href=\"{context.Request.PathBase}/RemoveTempCookie\">Remove Temp Cookie</a><br>\r\n");
|
||||
await response.WriteAsync($"<a href=\"{context.Request.PathBase}/GrantConsent\">Grant Consent</a><br>\r\n");
|
||||
await response.WriteAsync($"<a href=\"{context.Request.PathBase}/WithdrawConsent\">Withdraw Consent</a><br>\r\n");
|
||||
await response.WriteAsync("<br>\r\n");
|
||||
await response.WriteAsync($"<a href=\"/NeedsConsent{context.Request.Path}\">Needs Consent</a><br>\r\n");
|
||||
await response.WriteAsync($"<a href=\"/NeedsNoConsent{context.Request.Path}\">Needs No Consent</a><br>\r\n");
|
||||
await response.WriteAsync("<br>\r\n");
|
||||
|
||||
var feature = context.Features.Get<ITrackingConsentFeature>();
|
||||
await response.WriteAsync($"Consent: <br>\r\n");
|
||||
await response.WriteAsync($" - IsNeeded: {feature.IsConsentNeeded} <br>\r\n");
|
||||
await response.WriteAsync($" - Has: {feature.HasConsent} <br>\r\n");
|
||||
await response.WriteAsync($" - Can Track: {feature.CanTrack} <br>\r\n");
|
||||
await response.WriteAsync("<br>\r\n");
|
||||
|
||||
await response.WriteAsync($"{cookies.Count} Request Cookies:<br>\r\n");
|
||||
foreach (var cookie in cookies)
|
||||
{
|
||||
await response.WriteAsync($" - {cookie.Key} = {cookie.Value} <br>\r\n");
|
||||
}
|
||||
await response.WriteAsync("<br>\r\n");
|
||||
|
||||
var responseCookies = response.Headers[HeaderNames.SetCookie];
|
||||
await response.WriteAsync($"{responseCookies.Count} Response Cookies:<br>\r\n");
|
||||
foreach (var cookie in responseCookies)
|
||||
{
|
||||
await response.WriteAsync($" - {cookie} <br>\r\n");
|
||||
}
|
||||
|
||||
await response.WriteAsync("</body></html>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection" Version="$(MicrosoftAspNetCoreDataProtectionPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CookieSample
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.ConfigureLogging(factory =>
|
||||
{
|
||||
factory.AddConsole();
|
||||
factory.AddFilter("Console", level => level >= LogLevel.Information);
|
||||
})
|
||||
.UseKestrel()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:1788/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"CookieSample": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:12345",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace CookieSample
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// This can be removed after https://github.com/aspnet/IISIntegration/issues/371
|
||||
services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
}).AddCookie();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseAuthentication();
|
||||
|
||||
app.Run(async context =>
|
||||
{
|
||||
if (!context.User.Identities.Any(identity => identity.IsAuthenticated))
|
||||
{
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "bob") }, CookieAuthenticationDefaults.AuthenticationScheme));
|
||||
await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);
|
||||
|
||||
context.Response.ContentType = "text/plain";
|
||||
await context.Response.WriteAsync("Hello First timer");
|
||||
return;
|
||||
}
|
||||
|
||||
context.Response.ContentType = "text/plain";
|
||||
await context.Response.WriteAsync("Hello old timer");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection" Version="$(MicrosoftAspNetCoreDataProtectionPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(MicrosoftExtensionsCachingMemoryPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace CookieSessionSample
|
||||
{
|
||||
public class MemoryCacheTicketStore : ITicketStore
|
||||
{
|
||||
private const string KeyPrefix = "AuthSessionStore-";
|
||||
private IMemoryCache _cache;
|
||||
|
||||
public MemoryCacheTicketStore()
|
||||
{
|
||||
_cache = new MemoryCache(new MemoryCacheOptions());
|
||||
}
|
||||
|
||||
public async Task<string> StoreAsync(AuthenticationTicket ticket)
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
var key = KeyPrefix + guid.ToString();
|
||||
await RenewAsync(key, ticket);
|
||||
return key;
|
||||
}
|
||||
|
||||
public Task RenewAsync(string key, AuthenticationTicket ticket)
|
||||
{
|
||||
var options = new MemoryCacheEntryOptions();
|
||||
var expiresUtc = ticket.Properties.ExpiresUtc;
|
||||
if (expiresUtc.HasValue)
|
||||
{
|
||||
options.SetAbsoluteExpiration(expiresUtc.Value);
|
||||
}
|
||||
options.SetSlidingExpiration(TimeSpan.FromHours(1)); // TODO: configurable.
|
||||
|
||||
_cache.Set(key, ticket, options);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task<AuthenticationTicket> RetrieveAsync(string key)
|
||||
{
|
||||
AuthenticationTicket ticket;
|
||||
_cache.TryGetValue(key, out ticket);
|
||||
return Task.FromResult(ticket);
|
||||
}
|
||||
|
||||
public Task RemoveAsync(string key)
|
||||
{
|
||||
_cache.Remove(key);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CookieSessionSample
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.ConfigureLogging(factory =>
|
||||
{
|
||||
factory.AddConsole();
|
||||
factory.AddFilter("Console", level => level >= LogLevel.Information);
|
||||
})
|
||||
.UseKestrel()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:1790/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"CookieSessionSample": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:12345",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace CookieSessionSample
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// This can be removed after https://github.com/aspnet/IISIntegration/issues/371
|
||||
services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
}).AddCookie(o => o.SessionStore = new MemoryCacheTicketStore());
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseAuthentication();
|
||||
|
||||
app.Run(async context =>
|
||||
{
|
||||
if (!context.User.Identities.Any(identity => identity.IsAuthenticated))
|
||||
{
|
||||
// Make a large identity
|
||||
var claims = new List<Claim>(1001);
|
||||
claims.Add(new Claim(ClaimTypes.Name, "bob"));
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
claims.Add(new Claim(ClaimTypes.Role, "SomeRandomGroup" + i, ClaimValueTypes.String, "IssuedByBob", "OriginalIssuerJoe"));
|
||||
}
|
||||
|
||||
await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
|
||||
new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme)));
|
||||
|
||||
context.Response.ContentType = "text/plain";
|
||||
await context.Response.WriteAsync("Hello First timer");
|
||||
return;
|
||||
}
|
||||
|
||||
context.Response.ContentType = "text/plain";
|
||||
await context.Response.WriteAsync("Hello old timer");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
|
||||
<UserSecretsId>aspnet5-JwtBearerSample-20151210102827</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.JwtBearer\Microsoft.AspNetCore.Authentication.JwtBearer.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="$(MicrosoftAspNetCoreStaticFilesPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(MicrosoftExtensionsConfigurationUserSecretsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace JwtBearerSample
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:42023",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"JwtBearer": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:42023",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace JwtBearerSample
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IHostingEnvironment env)
|
||||
{
|
||||
Environment = env;
|
||||
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(env.ContentRootPath);
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
|
||||
builder.AddUserSecrets<Startup>();
|
||||
}
|
||||
|
||||
builder.AddEnvironmentVariables();
|
||||
Configuration = builder.Build();
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; set; }
|
||||
|
||||
public IHostingEnvironment Environment { get; set; }
|
||||
|
||||
// Shared between users in memory
|
||||
public IList<Todo> Todos { get; } = new List<Todo>();
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(o =>
|
||||
{
|
||||
// You also need to update /wwwroot/app/scripts/app.js
|
||||
o.Authority = Configuration["oidc:authority"];
|
||||
o.Audience = Configuration["oidc:clientid"];
|
||||
});
|
||||
}
|
||||
|
||||
// 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
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
// Use this if there are multiple authentication schemes
|
||||
var authResult = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
|
||||
if (authResult.Succeeded && authResult.Principal.Identity.IsAuthenticated)
|
||||
{
|
||||
await next();
|
||||
}
|
||||
else if (authResult.Failure != null)
|
||||
{
|
||||
// Rethrow, let the exception page handle it.
|
||||
ExceptionDispatchInfo.Capture(authResult.Failure).Throw();
|
||||
}
|
||||
else
|
||||
{
|
||||
await context.ChallengeAsync();
|
||||
}
|
||||
});
|
||||
|
||||
// MVC would usually handle this:
|
||||
app.Map("/api/TodoList", todoApp =>
|
||||
{
|
||||
todoApp.Run(async context =>
|
||||
{
|
||||
var response = context.Response;
|
||||
if (context.Request.Method.Equals("POST", System.StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var reader = new StreamReader(context.Request.Body);
|
||||
var body = await reader.ReadToEndAsync();
|
||||
var obj = JObject.Parse(body);
|
||||
var todo = new Todo() { Description = obj["Description"].Value<string>(), Owner = context.User.Identity.Name };
|
||||
Todos.Add(todo);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.ContentType = "application/json";
|
||||
response.Headers[HeaderNames.CacheControl] = "no-cache";
|
||||
var json = JToken.FromObject(Todos);
|
||||
await response.WriteAsync(json.ToString());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace JwtBearerSample
|
||||
{
|
||||
public class Todo
|
||||
{
|
||||
public string Description { get; set; }
|
||||
public string Owner { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
'use strict';
|
||||
angular.module('todoApp', ['ngRoute','AdalAngular'])
|
||||
.config(['$routeProvider', '$httpProvider', 'adalAuthenticationServiceProvider', function ($routeProvider, $httpProvider, adalProvider) {
|
||||
|
||||
$routeProvider.when("/Home", {
|
||||
controller: "homeCtrl",
|
||||
templateUrl: "/App/Views/Home.html",
|
||||
}).when("/TodoList", {
|
||||
controller: "todoListCtrl",
|
||||
templateUrl: "/App/Views/TodoList.html",
|
||||
requireADLogin: true,
|
||||
}).when("/UserData", {
|
||||
controller: "userDataCtrl",
|
||||
templateUrl: "/App/Views/UserData.html",
|
||||
}).otherwise({ redirectTo: "/Home" });
|
||||
|
||||
adalProvider.init(
|
||||
{
|
||||
instance: 'https://login.microsoftonline.com/',
|
||||
tenant: 'tratcheroutlook.onmicrosoft.com',
|
||||
clientId: '63a87a83-64b9-4ac1-b2c5-092126f8474f',
|
||||
extraQueryParameter: 'nux=1',
|
||||
// cacheLocation: 'localStorage', // enable this for IE, as sessionStorage does not work for localhost.
|
||||
},
|
||||
$httpProvider
|
||||
);
|
||||
|
||||
}]);
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
'use strict';
|
||||
angular.module('todoApp')
|
||||
.controller('homeCtrl', ['$scope', 'adalAuthenticationService','$location', function ($scope, adalService, $location) {
|
||||
$scope.login = function () {
|
||||
adalService.login();
|
||||
};
|
||||
$scope.logout = function () {
|
||||
adalService.logOut();
|
||||
};
|
||||
$scope.isActive = function (viewLocation) {
|
||||
return viewLocation === $location.path();
|
||||
};
|
||||
}]);
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
'use strict';
|
||||
angular.module('todoApp')
|
||||
.controller('indexCtrl', ['$scope', 'adalAuthenticationService', function ($scope, adalService) {
|
||||
|
||||
}]);
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
'use strict';
|
||||
angular.module('todoApp')
|
||||
.controller('todoListCtrl', ['$scope', '$location', 'todoListSvc', 'adalAuthenticationService', function ($scope, $location, todoListSvc, adalService) {
|
||||
$scope.error = "";
|
||||
$scope.loadingMessage = "Loading...";
|
||||
$scope.todoList = null;
|
||||
$scope.editingInProgress = false;
|
||||
$scope.newTodoCaption = "";
|
||||
|
||||
|
||||
$scope.editInProgressTodo = {
|
||||
Description: "",
|
||||
ID: 0
|
||||
};
|
||||
|
||||
|
||||
|
||||
$scope.editSwitch = function (todo) {
|
||||
todo.edit = !todo.edit;
|
||||
if (todo.edit) {
|
||||
$scope.editInProgressTodo.Description = todo.Description;
|
||||
$scope.editInProgressTodo.ID = todo.ID;
|
||||
$scope.editingInProgress = true;
|
||||
} else {
|
||||
$scope.editingInProgress = false;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.populate = function () {
|
||||
todoListSvc.getItems().success(function (results) {
|
||||
$scope.todoList = results;
|
||||
$scope.loadingMessage = "";
|
||||
}).error(function (err) {
|
||||
$scope.error = err;
|
||||
$scope.loadingMessage = "";
|
||||
})
|
||||
};
|
||||
$scope.delete = function (id) {
|
||||
todoListSvc.deleteItem(id).success(function (results) {
|
||||
$scope.loadingMessage = "";
|
||||
$scope.populate();
|
||||
}).error(function (err) {
|
||||
$scope.error = err;
|
||||
$scope.loadingMessage = "";
|
||||
})
|
||||
};
|
||||
$scope.update = function (todo) {
|
||||
todoListSvc.putItem($scope.editInProgressTodo).success(function (results) {
|
||||
$scope.loadingMsg = "";
|
||||
$scope.populate();
|
||||
$scope.editSwitch(todo);
|
||||
}).error(function (err) {
|
||||
$scope.error = err;
|
||||
$scope.loadingMessage = "";
|
||||
})
|
||||
};
|
||||
$scope.add = function () {
|
||||
|
||||
todoListSvc.postItem({
|
||||
'Description': $scope.newTodoCaption,
|
||||
'Owner': adalService.userInfo.userName
|
||||
}).success(function (results) {
|
||||
$scope.loadingMsg = "";
|
||||
$scope.newTodoCaption = "";
|
||||
$scope.populate();
|
||||
}).error(function (err) {
|
||||
$scope.error = err;
|
||||
$scope.loadingMsg = "";
|
||||
})
|
||||
};
|
||||
}]);
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
'use strict';
|
||||
angular.module('todoApp')
|
||||
.factory('todoListSvc', ['$http', function ($http) {
|
||||
return {
|
||||
getItems : function(){
|
||||
return $http.get('/api/TodoList');
|
||||
},
|
||||
getItem : function(id){
|
||||
return $http.get('/api/TodoList/' + id);
|
||||
},
|
||||
postItem : function(item){
|
||||
return $http.post('/api/TodoList/',item);
|
||||
},
|
||||
putItem : function(item){
|
||||
return $http.put('/api/TodoList/', item);
|
||||
},
|
||||
deleteItem : function(id){
|
||||
return $http({
|
||||
method: 'DELETE',
|
||||
url: '/api/TodoList/' + id
|
||||
});
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
'use strict';
|
||||
angular.module('todoApp')
|
||||
.controller('userDataCtrl', ['$scope', 'adalAuthenticationService', function ($scope, adalService) {
|
||||
|
||||
|
||||
}]);
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<div>
|
||||
home sweet home
|
||||
</div>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<div ng-init="populate()">
|
||||
<p class="error">{{error}}</p>
|
||||
<p>{{loadingMessage}}</p>
|
||||
<div class="panel">
|
||||
<div class="input-group">
|
||||
<input ng-model="newTodoCaption" class="form-control" />
|
||||
<span class="input-group-btn">
|
||||
<button ng-click="add();" class="btn btn-default">Add</button>
|
||||
</span>
|
||||
</div>
|
||||
<table class="table table-striped">
|
||||
<tbody>
|
||||
<tr data-ng-repeat="item in todoList">
|
||||
<td>
|
||||
<p data-ng-hide="item.edit">{{item.Description}}</p>
|
||||
</td>
|
||||
<td>
|
||||
<p data-ng-hide="item.edit">{{item.Owner}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<div>
|
||||
<h3>
|
||||
Id_token content
|
||||
</h3>
|
||||
<p>{{userInfo.userName}}</p>
|
||||
<p>aud:{{userInfo.profile.aud}}</p>
|
||||
<p>iss:{{userInfo.profile.iss}}</p>
|
||||
<p>iat:{{userInfo.profile.iat}}</p>
|
||||
<p>nbf:{{userInfo.profile.nbf}}</p>
|
||||
<p>exp:{{userInfo.profile.exp}}</p>
|
||||
<p>ver:{{userInfo.profile.ver}}</p>
|
||||
<p>tid:{{userInfo.profile.tid}}</p>
|
||||
<p>amr:{{userInfo.profile.amr}}</p>
|
||||
<p>oid:{{userInfo.profile.oid}}</p>
|
||||
<p>upn:{{userInfo.profile.upn}}</p>
|
||||
<p>unique_name:{{userInfo.profile.unique_name}}</p>
|
||||
<p>sub:{{userInfo.profile.sub}}</p>
|
||||
<p>family_name:{{userInfo.profile.family_name}}</p>
|
||||
<p>given_name:{{userInfo.profile.given_name}}</p>
|
||||
<p>pwd_exp:{{userInfo.profile.pwd_exp}}</p>
|
||||
<p>pwd_url:{{userInfo.profile.pwd_url}}</p>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Todo List: a SPA sample demonstrating Azure AD and ADAL JS</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
|
||||
</head>
|
||||
<body ng-app="todoApp" ng-controller="homeCtrl" role="document">
|
||||
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed"
|
||||
data-toggle="collapse"
|
||||
data-target=".navbar-collapse">
|
||||
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#/Home">ADAL JS Sample</a>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li ng-class="{ active: isActive('/Home') }"><a href="#/Home">Home</a></li>
|
||||
<li ng-class="{ active: isActive('/TodoList') }"><a href="#/TodoList">Todo List</a></li>
|
||||
<li ng-class="{ active: isActive('/UserData') }"><a href="#/UserData" ng-show="userInfo.isAuthenticated">User</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a class="btn btn-link" ng-show="userInfo.isAuthenticated" ng-click="logout()">Logout</a></li>
|
||||
<li><a class="btn btn-link" ng-hide="userInfo.isAuthenticated" ng-click="login()">Login</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<br />
|
||||
<div class="container" role="main">
|
||||
<div class="row">
|
||||
<div class="col-xs-10 col-xs-offset-1" style="background-color:azure">
|
||||
<div class="page-header">
|
||||
<h1>Todo List</h1>
|
||||
</div>
|
||||
<p>This sample demonstrates how to take advantage of ADAL JS for adding Azure AD authentication to your AngularJS apps.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-10 col-xs-offset-1">
|
||||
<div ng-view class="panel-body">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular.min.js"></script>
|
||||
<script src="https://code.angularjs.org/1.2.25/angular-route.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
|
||||
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal.min.js"></script>
|
||||
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal-angular.min.js"></script>
|
||||
<script src="App/Scripts/app.js"></script>
|
||||
<script src="App/Scripts/homeCtrl.js"></script>
|
||||
<script src="App/Scripts/userDataCtrl.js"></script>
|
||||
<script src="App/Scripts/todoListCtrl.js"></script>
|
||||
<script src="App/Scripts/todoListSvc.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
using System;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
|
||||
namespace OpenIdConnect.AzureAdSample
|
||||
{
|
||||
public class AuthPropertiesTokenCache : TokenCache
|
||||
{
|
||||
private const string TokenCacheKey = ".TokenCache";
|
||||
|
||||
private HttpContext _httpContext;
|
||||
private ClaimsPrincipal _principal;
|
||||
private AuthenticationProperties _authProperties;
|
||||
private string _signInScheme;
|
||||
|
||||
private AuthPropertiesTokenCache(AuthenticationProperties authProperties) : base()
|
||||
{
|
||||
_authProperties = authProperties;
|
||||
BeforeAccess = BeforeAccessNotificationWithProperties;
|
||||
AfterAccess = AfterAccessNotificationWithProperties;
|
||||
BeforeWrite = BeforeWriteNotification;
|
||||
}
|
||||
|
||||
private AuthPropertiesTokenCache(HttpContext httpContext, string signInScheme) : base()
|
||||
{
|
||||
_httpContext = httpContext;
|
||||
_signInScheme = signInScheme;
|
||||
BeforeAccess = BeforeAccessNotificationWithContext;
|
||||
AfterAccess = AfterAccessNotificationWithContext;
|
||||
BeforeWrite = BeforeWriteNotification;
|
||||
}
|
||||
|
||||
public static TokenCache ForCodeRedemption(AuthenticationProperties authProperties)
|
||||
{
|
||||
return new AuthPropertiesTokenCache(authProperties);
|
||||
}
|
||||
|
||||
public static TokenCache ForApiCalls(HttpContext httpContext,
|
||||
string signInScheme = CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
{
|
||||
return new AuthPropertiesTokenCache(httpContext, signInScheme);
|
||||
}
|
||||
|
||||
private void BeforeAccessNotificationWithProperties(TokenCacheNotificationArgs args)
|
||||
{
|
||||
string cachedTokensText;
|
||||
if (_authProperties.Items.TryGetValue(TokenCacheKey, out cachedTokensText))
|
||||
{
|
||||
var cachedTokens = Convert.FromBase64String(cachedTokensText);
|
||||
Deserialize(cachedTokens);
|
||||
}
|
||||
}
|
||||
|
||||
private void BeforeAccessNotificationWithContext(TokenCacheNotificationArgs args)
|
||||
{
|
||||
// Retrieve the auth session with the cached tokens
|
||||
var result = _httpContext.AuthenticateAsync(_signInScheme).Result;
|
||||
_authProperties = result.Ticket.Properties;
|
||||
_principal = result.Ticket.Principal;
|
||||
|
||||
BeforeAccessNotificationWithProperties(args);
|
||||
}
|
||||
|
||||
private void AfterAccessNotificationWithProperties(TokenCacheNotificationArgs args)
|
||||
{
|
||||
// if state changed
|
||||
if (HasStateChanged)
|
||||
{
|
||||
var cachedTokens = Serialize();
|
||||
var cachedTokensText = Convert.ToBase64String(cachedTokens);
|
||||
_authProperties.Items[TokenCacheKey] = cachedTokensText;
|
||||
}
|
||||
}
|
||||
|
||||
private void AfterAccessNotificationWithContext(TokenCacheNotificationArgs args)
|
||||
{
|
||||
// if state changed
|
||||
if (HasStateChanged)
|
||||
{
|
||||
AfterAccessNotificationWithProperties(args);
|
||||
|
||||
var cachedTokens = Serialize();
|
||||
var cachedTokensText = Convert.ToBase64String(cachedTokens);
|
||||
_authProperties.Items[TokenCacheKey] = cachedTokensText;
|
||||
_httpContext.SignInAsync(_signInScheme, _principal, _authProperties).Wait();
|
||||
}
|
||||
}
|
||||
|
||||
private void BeforeWriteNotification(TokenCacheNotificationArgs args)
|
||||
{
|
||||
// if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
|
||||
<UserSecretsId>aspnet5-OpenIdConnectSample-20151210110318</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.OpenIdConnect\Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(MicrosoftExtensionsConfigurationUserSecretsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="$(MicrosoftIdentityModelClientsActiveDirectoryPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace OpenIdConnect.AzureAdSample
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.ConfigureLogging(factory =>
|
||||
{
|
||||
factory.AddConsole();
|
||||
factory.AddFilter("Console", level => level >= LogLevel.Information);
|
||||
})
|
||||
.UseKestrel()
|
||||
.UseUrls("http://localhost:42023")
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:42023",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"OpenIdConnect": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:42023",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# How to set up the sample locally
|
||||
|
||||
## Set up [Azure Active Directory](https://azure.microsoft.com/en-us/documentation/services/active-directory/)
|
||||
|
||||
1. Create your own Azure Active Directory (AD). Save the "tenent name".
|
||||
2. Add a new Application: in the Azure AD portal, select Application, and click Add in the drawer.
|
||||
3. Set the sign-on url to `http://localhost:42023`.
|
||||
4. Select the newly created Application, navigate to the Configure tab.
|
||||
5. Find and save the "Client Id"
|
||||
8. In the keys section add a new key. A key value will be generated. Save the value as "Client Secret"
|
||||
|
||||
## Configure the local environment
|
||||
1. Set environment ASPNETCORE_ENVIRONMENT to DEVELOPMENT. ([Working with Multiple Environments](https://docs.asp.net/en/latest/fundamentals/environments.html))
|
||||
2. Set up user secrets:
|
||||
```
|
||||
dotnet user-secrets set oidc:clientid <Client Id>
|
||||
dotnet user-secrets set oidc:clientsecret <Client Secret>
|
||||
dotnet user-secrets set oidc:authority https://login.windows.net/<Tenent Name>.onmicrosoft.com
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.IdentityModel.Clients.ActiveDirectory;
|
||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
|
||||
namespace OpenIdConnect.AzureAdSample
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IHostingEnvironment env)
|
||||
{
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(env.ContentRootPath);
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
|
||||
builder.AddUserSecrets<Startup>();
|
||||
}
|
||||
|
||||
builder.AddEnvironmentVariables();
|
||||
Configuration = builder.Build();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
services.AddAuthentication(sharedOptions =>
|
||||
{
|
||||
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddCookie()
|
||||
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, "AAD", o =>
|
||||
{
|
||||
o.ClientId = ClientId;
|
||||
o.ClientSecret = ClientSecret; // for code flow
|
||||
o.Authority = Authority;
|
||||
o.ResponseType = OpenIdConnectResponseType.CodeIdToken;
|
||||
o.SignedOutRedirectUri = "/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)
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
|
||||
app.UseAuthentication();
|
||||
|
||||
app.Run(async context =>
|
||||
{
|
||||
if (context.Request.Path.Equals("/signin"))
|
||||
{
|
||||
if (context.User.Identities.Any(identity => identity.IsAuthenticated))
|
||||
{
|
||||
// User has already signed in
|
||||
context.Response.Redirect("/");
|
||||
return;
|
||||
}
|
||||
|
||||
await context.ChallengeAsync(new AuthenticationProperties { RedirectUri = "/" });
|
||||
}
|
||||
else if (context.Request.Path.Equals("/signout"))
|
||||
{
|
||||
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
await WriteHtmlAsync(context.Response,
|
||||
async response =>
|
||||
{
|
||||
await response.WriteAsync($"<h1>Signed out locally: {HtmlEncode(context.User.Identity.Name)}</h1>");
|
||||
await response.WriteAsync("<a class=\"btn btn-primary\" href=\"/\">Sign In</a>");
|
||||
});
|
||||
}
|
||||
else if (context.Request.Path.Equals("/signout-remote"))
|
||||
{
|
||||
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
|
||||
}
|
||||
else if (context.Request.Path.Equals("/signed-out"))
|
||||
{
|
||||
await WriteHtmlAsync(context.Response,
|
||||
async response =>
|
||||
{
|
||||
await response.WriteAsync($"<h1>You have been signed out.</h1>");
|
||||
await response.WriteAsync("<a class=\"btn btn-primary\" href=\"/signin\">Sign In</a>");
|
||||
});
|
||||
}
|
||||
else if (context.Request.Path.Equals("/remote-signedout"))
|
||||
{
|
||||
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
await WriteHtmlAsync(context.Response,
|
||||
async response =>
|
||||
{
|
||||
await response.WriteAsync($"<h1>Signed out remotely: {HtmlEncode(context.User.Identity.Name)}</h1>");
|
||||
await response.WriteAsync("<a class=\"btn btn-primary\" href=\"/\">Sign In</a>");
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!context.User.Identities.Any(identity => identity.IsAuthenticated))
|
||||
{
|
||||
await context.ChallengeAsync(new AuthenticationProperties { RedirectUri = "/" });
|
||||
return;
|
||||
}
|
||||
|
||||
await WriteHtmlAsync(context.Response, async response =>
|
||||
{
|
||||
await response.WriteAsync($"<h1>Hello Authenticated User {HtmlEncode(context.User.Identity.Name)}</h1>");
|
||||
await response.WriteAsync("<a class=\"btn btn-default\" href=\"/signout\">Sign Out Locally</a>");
|
||||
await response.WriteAsync("<a class=\"btn btn-default\" href=\"/signout-remote\">Sign Out Remotely</a>");
|
||||
|
||||
await response.WriteAsync("<h2>Claims:</h2>");
|
||||
await WriteTableHeader(response, new string[] { "Claim Type", "Value" }, context.User.Claims.Select(c => new string[] { c.Type, c.Value }));
|
||||
|
||||
await response.WriteAsync("<h2>Tokens:</h2>");
|
||||
try
|
||||
{
|
||||
// Use ADAL to get the right token
|
||||
var authContext = new AuthenticationContext(Authority, AuthPropertiesTokenCache.ForApiCalls(context, CookieAuthenticationDefaults.AuthenticationScheme));
|
||||
var credential = new ClientCredential(ClientId, ClientSecret);
|
||||
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));
|
||||
|
||||
await response.WriteAsync($"<h3>access_token</h3><code>{HtmlEncode(result.AccessToken)}</code><br>");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await response.WriteAsync($"AquireToken error: {ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static async Task WriteHtmlAsync(HttpResponse response, Func<HttpResponse, Task> writeContent)
|
||||
{
|
||||
var bootstrap = "<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u\" crossorigin=\"anonymous\">";
|
||||
|
||||
response.ContentType = "text/html";
|
||||
await response.WriteAsync($"<html><head>{bootstrap}</head><body><div class=\"container\">");
|
||||
await writeContent(response);
|
||||
await response.WriteAsync("</div></body></html>");
|
||||
}
|
||||
|
||||
private static async Task WriteTableHeader(HttpResponse response, IEnumerable<string> columns, IEnumerable<IEnumerable<string>> data)
|
||||
{
|
||||
await response.WriteAsync("<table class=\"table table-condensed\">");
|
||||
await response.WriteAsync("<tr>");
|
||||
foreach (var column in columns)
|
||||
{
|
||||
await response.WriteAsync($"<th>{HtmlEncode(column)}</th>");
|
||||
}
|
||||
await response.WriteAsync("</tr>");
|
||||
foreach (var row in data)
|
||||
{
|
||||
await response.WriteAsync("<tr>");
|
||||
foreach (var column in row)
|
||||
{
|
||||
await response.WriteAsync($"<td>{HtmlEncode(column)}</td>");
|
||||
}
|
||||
await response.WriteAsync("</tr>");
|
||||
}
|
||||
await response.WriteAsync("</table>");
|
||||
}
|
||||
|
||||
private static string HtmlEncode(string content) =>
|
||||
string.IsNullOrEmpty(content) ? string.Empty : HtmlEncoder.Default.Encode(content);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
|
||||
<UserSecretsId>aspnet5-OpenIdConnectSample-20151210110318</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="compiler\resources\cert.pfx" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.OpenIdConnect\Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="$(MicrosoftAspNetCoreServerKestrelHttpsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(MicrosoftExtensionsConfigurationUserSecretsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="$(MicrosoftExtensionsFileProvidersEmbeddedPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="$(MicrosoftExtensionsLoggingDebugPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="compiler\resources\cert.pfx" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace OpenIdConnectSample
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.ConfigureLogging(factory =>
|
||||
{
|
||||
factory.AddConsole();
|
||||
factory.AddDebug();
|
||||
factory.AddFilter("Console", level => level >= LogLevel.Information);
|
||||
factory.AddFilter("Debug", level => level >= LogLevel.Information);
|
||||
})
|
||||
.UseKestrel(options =>
|
||||
{
|
||||
options.Listen(IPAddress.Loopback, 44318, listenOptions =>
|
||||
{
|
||||
// Configure SSL
|
||||
var serverCertificate = LoadCertificate();
|
||||
listenOptions.UseHttps(serverCertificate);
|
||||
});
|
||||
})
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
|
||||
private static X509Certificate2 LoadCertificate()
|
||||
{
|
||||
var assembly = typeof(Startup).GetTypeInfo().Assembly;
|
||||
var embeddedFileProvider = new EmbeddedFileProvider(assembly, "OpenIdConnectSample");
|
||||
var certificateFileInfo = embeddedFileProvider.GetFileInfo("compiler/resources/cert.pfx");
|
||||
using (var certificateStream = certificateFileInfo.CreateReadStream())
|
||||
{
|
||||
byte[] certificatePayload;
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
certificateStream.CopyTo(memoryStream);
|
||||
certificatePayload = memoryStream.ToArray();
|
||||
}
|
||||
|
||||
return new X509Certificate2(certificatePayload, "testPassword");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:42023",
|
||||
"sslPort": 44318
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "https://localhost:44318/",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"OpenIdConnectSample": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:44318/",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
# How to set up the sample locally
|
||||
|
||||
The OpenIdConnect sample supports multilpe authentication providers. In these instruction, we will explore how to set up this sample with both Azure Active Directory and Google Identity Platform.
|
||||
|
||||
## Determine your development environment and a few key variables
|
||||
|
||||
This sample is configured to run on port __44318__ locally. In Visual Studio, the setting is carried out in `.\properties\launchSettings.json`. When the application is run from command line, the URL is coded in `Program.cs`.
|
||||
|
||||
If the application is run from command line or terminal, environment variable ASPNETCORE_ENVIRONMENT should be set to DEVELOPMENT to enable user secret.
|
||||
|
||||
## Configure the Authorization server
|
||||
|
||||
### Configure with Azure Active Directory
|
||||
|
||||
1. Set up a new Azure Active Directory (AAD) in your Azure Subscription.
|
||||
2. Open the newly created AAD in Azure web portal.
|
||||
3. Navigate to the Applications tab.
|
||||
4. Add a new Application to the AAD. Set the "Sign-on URL" to sample application's URL.
|
||||
5. Naigate to the Application, and click the Configure tab.
|
||||
6. Find and save the "Client Id".
|
||||
7. Add a new key in the "Keys" section. Save value of the key, which is the "Client Secret".
|
||||
8. Click the "View Endpoints" on the drawer, a dialog will shows six endpoint URLs. Copy the "OAuth 2.0 Authorization Endpoint" to a text editor and remove the "/oauth2/authorize" from the string. The remaining part is the __authority URL__. It looks like `https://login.microsoftonline.com/<guid>`.
|
||||
|
||||
### Configure with Google Identity Platform
|
||||
|
||||
1. Create a new project through [Google APIs](https://console.developers.google.com).
|
||||
2. In the sidebar choose "Credentials".
|
||||
3. Navigate to "OAuth consent screen" tab, fill in the project name and save.
|
||||
4. Navigate to "Credentials" tab. Click "Create credentials". Choose "OAuth client ID".
|
||||
5. Select "Web application" as the application type. Fill in the "Authorized redirect URIs" with `https://localhost:44318/signin-oidc`.
|
||||
6. Save the "Client ID" and "Client Secret" shown in the dialog.
|
||||
7. The "Authority URL" for Google Authentication is `https://accounts.google.com/`.
|
||||
|
||||
## Configure the sample application
|
||||
|
||||
1. Restore the application.
|
||||
2. Set user secrets:
|
||||
|
||||
```
|
||||
dotnet user-secrets set oidc:clientid <Client Id>
|
||||
dotnet user-secrets set oidc:clientsecret <Client Secret>
|
||||
dotnet user-secrets set oidc:authority <Authority URL>
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,297 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace OpenIdConnectSample
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IHostingEnvironment env)
|
||||
{
|
||||
Environment = env;
|
||||
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(env.ContentRootPath);
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
|
||||
builder.AddUserSecrets<Startup>();
|
||||
}
|
||||
|
||||
builder.AddEnvironmentVariables();
|
||||
Configuration = builder.Build();
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; set; }
|
||||
|
||||
public IHostingEnvironment Environment { get; set; }
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
||||
|
||||
services.AddAuthentication(sharedOptions =>
|
||||
{
|
||||
sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddCookie()
|
||||
.AddOpenIdConnect(o =>
|
||||
{
|
||||
o.ClientId = Configuration["oidc:clientid"];
|
||||
o.ClientSecret = Configuration["oidc:clientsecret"]; // for code flow
|
||||
o.Authority = Configuration["oidc:authority"];
|
||||
|
||||
o.ResponseType = OpenIdConnectResponseType.CodeIdToken;
|
||||
o.SaveTokens = true;
|
||||
o.GetClaimsFromUserInfoEndpoint = true;
|
||||
|
||||
o.ClaimActions.MapAllExcept("aud", "iss", "iat", "nbf", "exp", "aio", "c_hash", "uti", "nonce");
|
||||
|
||||
o.Events = new OpenIdConnectEvents()
|
||||
{
|
||||
OnAuthenticationFailed = c =>
|
||||
{
|
||||
c.HandleResponse();
|
||||
|
||||
c.Response.StatusCode = 500;
|
||||
c.Response.ContentType = "text/plain";
|
||||
if (Environment.IsDevelopment())
|
||||
{
|
||||
// Debug only, in production do not share exceptions with the remote host.
|
||||
return c.Response.WriteAsync(c.Exception.ToString());
|
||||
}
|
||||
return c.Response.WriteAsync("An error occurred processing your authentication.");
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IOptionsMonitor<OpenIdConnectOptions> optionsMonitor)
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseAuthentication();
|
||||
|
||||
app.Run(async context =>
|
||||
{
|
||||
var response = context.Response;
|
||||
|
||||
if (context.Request.Path.Equals("/signedout"))
|
||||
{
|
||||
await WriteHtmlAsync(response, async res =>
|
||||
{
|
||||
await res.WriteAsync($"<h1>You have been signed out.</h1>");
|
||||
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/\">Home</a>");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Request.Path.Equals("/signout"))
|
||||
{
|
||||
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
await WriteHtmlAsync(response, async res =>
|
||||
{
|
||||
await res.WriteAsync($"<h1>Signed out {HtmlEncode(context.User.Identity.Name)}</h1>");
|
||||
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/\">Home</a>");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Request.Path.Equals("/signout-remote"))
|
||||
{
|
||||
// Redirects
|
||||
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties()
|
||||
{
|
||||
RedirectUri = "/signedout"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Request.Path.Equals("/Account/AccessDenied"))
|
||||
{
|
||||
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
await WriteHtmlAsync(response, async res =>
|
||||
{
|
||||
await res.WriteAsync($"<h1>Access Denied for user {HtmlEncode(context.User.Identity.Name)} to resource '{HtmlEncode(context.Request.Query["ReturnUrl"])}'</h1>");
|
||||
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/signout\">Sign Out</a>");
|
||||
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/\">Home</a>");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// DefaultAuthenticateScheme causes User to be set
|
||||
// var user = context.User;
|
||||
|
||||
// This is what [Authorize] calls
|
||||
var userResult = await context.AuthenticateAsync();
|
||||
var user = userResult.Principal;
|
||||
var props = userResult.Properties;
|
||||
|
||||
// This is what [Authorize(ActiveAuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] calls
|
||||
// var user = await context.AuthenticateAsync(OpenIdConnectDefaults.AuthenticationScheme);
|
||||
|
||||
// Not authenticated
|
||||
if (user == null || !user.Identities.Any(identity => identity.IsAuthenticated))
|
||||
{
|
||||
// This is what [Authorize] calls
|
||||
await context.ChallengeAsync();
|
||||
|
||||
// This is what [Authorize(ActiveAuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] calls
|
||||
// await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Authenticated, but not authorized
|
||||
if (context.Request.Path.Equals("/restricted") && !user.Identities.Any(identity => identity.HasClaim("special", "true")))
|
||||
{
|
||||
await context.ForbidAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Request.Path.Equals("/refresh"))
|
||||
{
|
||||
var refreshToken = props.GetTokenValue("refresh_token");
|
||||
|
||||
if (string.IsNullOrEmpty(refreshToken))
|
||||
{
|
||||
await WriteHtmlAsync(response, async res =>
|
||||
{
|
||||
await res.WriteAsync($"No refresh_token is available.<br>");
|
||||
await res.WriteAsync("<a class=\"btn btn-link\" href=\"/signout\">Sign Out</a>");
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var options = optionsMonitor.Get(OpenIdConnectDefaults.AuthenticationScheme);
|
||||
var metadata = await options.ConfigurationManager.GetConfigurationAsync(context.RequestAborted);
|
||||
|
||||
var pairs = new Dictionary<string, string>()
|
||||
{
|
||||
{ "client_id", options.ClientId },
|
||||
{ "client_secret", options.ClientSecret },
|
||||
{ "grant_type", "refresh_token" },
|
||||
{ "refresh_token", refreshToken }
|
||||
};
|
||||
var content = new FormUrlEncodedContent(pairs);
|
||||
var tokenResponse = await options.Backchannel.PostAsync(metadata.TokenEndpoint, content, context.RequestAborted);
|
||||
tokenResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var payload = JObject.Parse(await tokenResponse.Content.ReadAsStringAsync());
|
||||
|
||||
// Persist the new acess token
|
||||
props.UpdateTokenValue("access_token", payload.Value<string>("access_token"));
|
||||
props.UpdateTokenValue("refresh_token", payload.Value<string>("refresh_token"));
|
||||
if (int.TryParse(payload.Value<string>("expires_in"), NumberStyles.Integer, CultureInfo.InvariantCulture, out var seconds))
|
||||
{
|
||||
var expiresAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds);
|
||||
props.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));
|
||||
}
|
||||
await context.SignInAsync(user, props);
|
||||
|
||||
await WriteHtmlAsync(response, async res =>
|
||||
{
|
||||
await res.WriteAsync($"<h1>Refreshed.</h1>");
|
||||
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/refresh\">Refresh tokens</a>");
|
||||
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/\">Home</a>");
|
||||
|
||||
await res.WriteAsync("<h2>Tokens:</h2>");
|
||||
await WriteTableHeader(res, new string[] { "Token Type", "Value" }, props.GetTokens().Select(token => new string[] { token.Name, token.Value }));
|
||||
|
||||
await res.WriteAsync("<h2>Payload:</h2>");
|
||||
await res.WriteAsync(HtmlEncoder.Default.Encode(payload.ToString()).Replace(",", ",<br>") + "<br>");
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Request.Path.Equals("/login-challenge"))
|
||||
{
|
||||
// Challenge the user authentication, and force a login prompt by overwriting the
|
||||
// "prompt". This could be used for example to require the user to re-enter their
|
||||
// credentials at the authentication provider, to add an extra confirmation layer.
|
||||
await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new OpenIdConnectChallengeProperties()
|
||||
{
|
||||
Prompt = "login",
|
||||
|
||||
// it is also possible to specify different scopes, e.g.
|
||||
// Scope = new string[] { "openid", "profile", "other" }
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await WriteHtmlAsync(response, async res =>
|
||||
{
|
||||
await res.WriteAsync($"<h1>Hello Authenticated User {HtmlEncode(user.Identity.Name)}</h1>");
|
||||
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/refresh\">Refresh tokens</a>");
|
||||
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/restricted\">Restricted</a>");
|
||||
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/login-challenge\">Login challenge</a>");
|
||||
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/signout\">Sign Out</a>");
|
||||
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/signout-remote\">Sign Out Remote</a>");
|
||||
|
||||
await res.WriteAsync("<h2>Claims:</h2>");
|
||||
await WriteTableHeader(res, new string[] { "Claim Type", "Value" }, context.User.Claims.Select(c => new string[] { c.Type, c.Value }));
|
||||
|
||||
await res.WriteAsync("<h2>Tokens:</h2>");
|
||||
await WriteTableHeader(res, new string[] { "Token Type", "Value" }, props.GetTokens().Select(token => new string[] { token.Name, token.Value }));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static async Task WriteHtmlAsync(HttpResponse response, Func<HttpResponse, Task> writeContent)
|
||||
{
|
||||
var bootstrap = "<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u\" crossorigin=\"anonymous\">";
|
||||
|
||||
response.ContentType = "text/html";
|
||||
await response.WriteAsync($"<html><head>{bootstrap}</head><body><div class=\"container\">");
|
||||
await writeContent(response);
|
||||
await response.WriteAsync("</div></body></html>");
|
||||
}
|
||||
|
||||
private static async Task WriteTableHeader(HttpResponse response, IEnumerable<string> columns, IEnumerable<IEnumerable<string>> data)
|
||||
{
|
||||
await response.WriteAsync("<table class=\"table table-condensed\">");
|
||||
await response.WriteAsync("<tr>");
|
||||
foreach (var column in columns)
|
||||
{
|
||||
await response.WriteAsync($"<th>{HtmlEncode(column)}</th>");
|
||||
}
|
||||
await response.WriteAsync("</tr>");
|
||||
foreach (var row in data)
|
||||
{
|
||||
await response.WriteAsync("<tr>");
|
||||
foreach (var column in row)
|
||||
{
|
||||
await response.WriteAsync($"<td>{HtmlEncode(column)}</td>");
|
||||
}
|
||||
await response.WriteAsync("</tr>");
|
||||
}
|
||||
await response.WriteAsync("</table>");
|
||||
}
|
||||
|
||||
private static string HtmlEncode(string content) =>
|
||||
string.IsNullOrEmpty(content) ? string.Empty : HtmlEncoder.Default.Encode(content);
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace SocialSample
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.ConfigureLogging(factory =>
|
||||
{
|
||||
factory.AddConsole();
|
||||
factory.AddFilter("Console", level => level >= LogLevel.Information);
|
||||
})
|
||||
.UseKestrel(options =>
|
||||
{
|
||||
options.Listen(IPAddress.Loopback, 44318, listenOptions =>
|
||||
{
|
||||
// Configure SSL
|
||||
var serverCertificate = LoadCertificate();
|
||||
listenOptions.UseHttps(serverCertificate);
|
||||
});
|
||||
})
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
|
||||
private static X509Certificate2 LoadCertificate()
|
||||
{
|
||||
var socialSampleAssembly = typeof(Startup).GetTypeInfo().Assembly;
|
||||
var embeddedFileProvider = new EmbeddedFileProvider(socialSampleAssembly, "SocialSample");
|
||||
var certificateFileInfo = embeddedFileProvider.GetFileInfo("compiler/resources/cert.pfx");
|
||||
using (var certificateStream = certificateFileInfo.CreateReadStream())
|
||||
{
|
||||
byte[] certificatePayload;
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
certificateStream.CopyTo(memoryStream);
|
||||
certificatePayload = memoryStream.ToArray();
|
||||
}
|
||||
|
||||
return new X509Certificate2(certificatePayload, "testPassword");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:54540",
|
||||
"sslPort": 44318
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "https://localhost:44318/",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"SocialSample": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:44318/",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
|
||||
<UserSecretsId>aspnet5-SocialSample-20151210111056</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="compiler\resources\cert.pfx" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="compiler\resources\cert.pfx" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Facebook\Microsoft.AspNetCore.Authentication.Facebook.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Google\Microsoft.AspNetCore.Authentication.Google.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.MicrosoftAccount\Microsoft.AspNetCore.Authentication.MicrosoftAccount.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Twitter\Microsoft.AspNetCore.Authentication.Twitter.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection" Version="$(MicrosoftAspNetCoreDataProtectionPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="$(MicrosoftAspNetCoreServerKestrelHttpsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(MicrosoftExtensionsConfigurationUserSecretsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="$(MicrosoftExtensionsFileProvidersEmbeddedPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,502 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.Facebook;
|
||||
using Microsoft.AspNetCore.Authentication.Google;
|
||||
using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.AspNetCore.Authentication.Twitter;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace SocialSample
|
||||
{
|
||||
/* Note all servers must use the same address and port because these are pre-registered with the various providers. */
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IHostingEnvironment env)
|
||||
{
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(env.ContentRootPath)
|
||||
.AddJsonFile("appsettings.json", optional: true);
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
|
||||
builder.AddUserSecrets<Startup>();
|
||||
}
|
||||
|
||||
builder.AddEnvironmentVariables();
|
||||
Configuration = builder.Build();
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; set; }
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Configuration["facebook:appid"]))
|
||||
{
|
||||
// User-Secrets: https://docs.asp.net/en/latest/security/app-secrets.html
|
||||
// See below for registration instructions for each provider.
|
||||
throw new InvalidOperationException("User secrets must be configured for each authentication provider.");
|
||||
}
|
||||
|
||||
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie(o => o.LoginPath = new PathString("/login"))
|
||||
// You must first create an app with Facebook and add its ID and Secret to your user-secrets.
|
||||
// https://developers.facebook.com/apps/
|
||||
.AddFacebook(o =>
|
||||
{
|
||||
o.AppId = Configuration["facebook:appid"];
|
||||
o.AppSecret = Configuration["facebook:appsecret"];
|
||||
o.Scope.Add("email");
|
||||
o.Fields.Add("name");
|
||||
o.Fields.Add("email");
|
||||
o.SaveTokens = true;
|
||||
o.Events = new OAuthEvents()
|
||||
{
|
||||
OnRemoteFailure = HandleOnRemoteFailure
|
||||
};
|
||||
})
|
||||
// You must first create an app with Google and add its ID and Secret to your user-secrets.
|
||||
// https://console.developers.google.com/project
|
||||
.AddOAuth("Google-AccessToken", "Google AccessToken only", o =>
|
||||
{
|
||||
o.ClientId = Configuration["google:clientid"];
|
||||
o.ClientSecret = Configuration["google:clientsecret"];
|
||||
o.CallbackPath = new PathString("/signin-google-token");
|
||||
o.AuthorizationEndpoint = GoogleDefaults.AuthorizationEndpoint;
|
||||
o.TokenEndpoint = GoogleDefaults.TokenEndpoint;
|
||||
o.Scope.Add("openid");
|
||||
o.Scope.Add("profile");
|
||||
o.Scope.Add("email");
|
||||
o.SaveTokens = true;
|
||||
o.Events = new OAuthEvents()
|
||||
{
|
||||
OnRemoteFailure = HandleOnRemoteFailure
|
||||
};
|
||||
})
|
||||
// You must first create an app with Google and add its ID and Secret to your user-secrets.
|
||||
// https://console.developers.google.com/project
|
||||
.AddGoogle(o =>
|
||||
{
|
||||
o.ClientId = Configuration["google:clientid"];
|
||||
o.ClientSecret = Configuration["google:clientsecret"];
|
||||
o.AuthorizationEndpoint += "?prompt=consent"; // Hack so we always get a refresh token, it only comes on the first authorization response
|
||||
o.AccessType = "offline";
|
||||
o.SaveTokens = true;
|
||||
o.Events = new OAuthEvents()
|
||||
{
|
||||
OnRemoteFailure = HandleOnRemoteFailure
|
||||
};
|
||||
o.ClaimActions.MapJsonSubKey("urn:google:image", "image", "url");
|
||||
o.ClaimActions.Remove(ClaimTypes.GivenName);
|
||||
})
|
||||
// You must first create an app with Twitter and add its key and Secret to your user-secrets.
|
||||
// https://apps.twitter.com/
|
||||
.AddTwitter(o =>
|
||||
{
|
||||
o.ConsumerKey = Configuration["twitter:consumerkey"];
|
||||
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/36330675/get-users-email-from-twitter-api-for-external-login-authentication-asp-net-mvc?lq=1
|
||||
o.RetrieveUserDetails = true;
|
||||
o.SaveTokens = true;
|
||||
o.ClaimActions.MapJsonKey("urn:twitter:profilepicture", "profile_image_url", ClaimTypes.Uri);
|
||||
o.Events = new TwitterEvents()
|
||||
{
|
||||
OnRemoteFailure = HandleOnRemoteFailure
|
||||
};
|
||||
})
|
||||
/* 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:
|
||||
https://localhost:44318/
|
||||
*/
|
||||
// You must first create an app with Microsoft Account and add its ID and Secret to your user-secrets.
|
||||
// https://apps.dev.microsoft.com/
|
||||
.AddOAuth("Microsoft-AccessToken", "Microsoft AccessToken only", o =>
|
||||
{
|
||||
o.ClientId = Configuration["microsoftaccount:clientid"];
|
||||
o.ClientSecret = Configuration["microsoftaccount:clientsecret"];
|
||||
o.CallbackPath = new PathString("/signin-microsoft-token");
|
||||
o.AuthorizationEndpoint = MicrosoftAccountDefaults.AuthorizationEndpoint;
|
||||
o.TokenEndpoint = MicrosoftAccountDefaults.TokenEndpoint;
|
||||
o.Scope.Add("https://graph.microsoft.com/user.read");
|
||||
o.SaveTokens = true;
|
||||
o.Events = new OAuthEvents()
|
||||
{
|
||||
OnRemoteFailure = HandleOnRemoteFailure
|
||||
};
|
||||
})
|
||||
// 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/
|
||||
.AddMicrosoftAccount(o =>
|
||||
{
|
||||
o.ClientId = Configuration["microsoftaccount:clientid"];
|
||||
o.ClientSecret = Configuration["microsoftaccount:clientsecret"];
|
||||
o.SaveTokens = true;
|
||||
o.Scope.Add("offline_access");
|
||||
o.Events = new OAuthEvents()
|
||||
{
|
||||
OnRemoteFailure = HandleOnRemoteFailure
|
||||
};
|
||||
})
|
||||
// You must first create an app with GitHub and add its ID and Secret to your user-secrets.
|
||||
// https://github.com/settings/applications/
|
||||
.AddOAuth("GitHub-AccessToken", "GitHub AccessToken only", o =>
|
||||
{
|
||||
o.ClientId = Configuration["github-token:clientid"];
|
||||
o.ClientSecret = Configuration["github-token:clientsecret"];
|
||||
o.CallbackPath = new PathString("/signin-github-token");
|
||||
o.AuthorizationEndpoint = "https://github.com/login/oauth/authorize";
|
||||
o.TokenEndpoint = "https://github.com/login/oauth/access_token";
|
||||
o.SaveTokens = true;
|
||||
o.Events = new OAuthEvents()
|
||||
{
|
||||
OnRemoteFailure = HandleOnRemoteFailure
|
||||
};
|
||||
})
|
||||
// You must first create an app with GitHub and add its ID and Secret to your user-secrets.
|
||||
// https://github.com/settings/applications/
|
||||
.AddOAuth("GitHub", "Github", o =>
|
||||
{
|
||||
o.ClientId = Configuration["github:clientid"];
|
||||
o.ClientSecret = Configuration["github:clientsecret"];
|
||||
o.CallbackPath = new PathString("/signin-github");
|
||||
o.AuthorizationEndpoint = "https://github.com/login/oauth/authorize";
|
||||
o.TokenEndpoint = "https://github.com/login/oauth/access_token";
|
||||
o.UserInformationEndpoint = "https://api.github.com/user";
|
||||
o.ClaimsIssuer = "OAuth2-Github";
|
||||
o.SaveTokens = true;
|
||||
// Retrieving user information is unique to each provider.
|
||||
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");
|
||||
o.Events = new OAuthEvents
|
||||
{
|
||||
OnRemoteFailure = HandleOnRemoteFailure,
|
||||
OnCreatingTicket = async context =>
|
||||
{
|
||||
// Get the GitHub user
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
|
||||
var response = await context.Backchannel.SendAsync(request, context.HttpContext.RequestAborted);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var user = JObject.Parse(await response.Content.ReadAsStringAsync());
|
||||
|
||||
context.RunClaimActions(user);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private async Task HandleOnRemoteFailure(RemoteFailureContext context)
|
||||
{
|
||||
context.Response.StatusCode = 500;
|
||||
context.Response.ContentType = "text/html";
|
||||
await context.Response.WriteAsync("<html><body>");
|
||||
await context.Response.WriteAsync("A remote failure has occurred: " + UrlEncoder.Default.Encode(context.Failure.Message) + "<br>");
|
||||
|
||||
if (context.Properties != null)
|
||||
{
|
||||
await context.Response.WriteAsync("Properties:<br>");
|
||||
foreach (var pair in context.Properties.Items)
|
||||
{
|
||||
await context.Response.WriteAsync($"-{ UrlEncoder.Default.Encode(pair.Key)}={ UrlEncoder.Default.Encode(pair.Value)}<br>");
|
||||
}
|
||||
}
|
||||
|
||||
await context.Response.WriteAsync("<a href=\"/\">Home</a>");
|
||||
await context.Response.WriteAsync("</body></html>");
|
||||
|
||||
// context.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(context.Failure.Message));
|
||||
|
||||
context.HandleResponse();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
|
||||
app.UseAuthentication();
|
||||
|
||||
// Choose an authentication type
|
||||
app.Map("/login", signinApp =>
|
||||
{
|
||||
signinApp.Run(async context =>
|
||||
{
|
||||
var authType = context.Request.Query["authscheme"];
|
||||
if (!string.IsNullOrEmpty(authType))
|
||||
{
|
||||
// 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 (/).
|
||||
await context.ChallengeAsync(authType, new AuthenticationProperties() { RedirectUri = "/" });
|
||||
return;
|
||||
}
|
||||
|
||||
var response = context.Response;
|
||||
response.ContentType = "text/html";
|
||||
await response.WriteAsync("<html><body>");
|
||||
await response.WriteAsync("Choose an authentication scheme: <br>");
|
||||
var schemeProvider = context.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
|
||||
foreach (var provider in await schemeProvider.GetAllSchemesAsync())
|
||||
{
|
||||
await response.WriteAsync("<a href=\"?authscheme=" + provider.Name + "\">" + (provider.DisplayName ?? "(suppressed)") + "</a><br>");
|
||||
}
|
||||
await response.WriteAsync("</body></html>");
|
||||
});
|
||||
});
|
||||
|
||||
// Refresh the access token
|
||||
app.Map("/refresh_token", signinApp =>
|
||||
{
|
||||
signinApp.Run(async context =>
|
||||
{
|
||||
var response = context.Response;
|
||||
|
||||
// Setting DefaultAuthenticateScheme causes User to be set
|
||||
// var user = context.User;
|
||||
|
||||
// This is what [Authorize] calls
|
||||
var userResult = await context.AuthenticateAsync();
|
||||
var user = userResult.Principal;
|
||||
var authProperties = userResult.Properties;
|
||||
|
||||
// This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls
|
||||
// var user = await context.AuthenticateAsync(MicrosoftAccountDefaults.AuthenticationScheme);
|
||||
|
||||
// Deny anonymous request beyond this point.
|
||||
if (!userResult.Succeeded || user == null || !user.Identities.Any(identity => identity.IsAuthenticated))
|
||||
{
|
||||
// This is what [Authorize] calls
|
||||
// The cookie middleware will handle this and redirect to /login
|
||||
await context.ChallengeAsync();
|
||||
|
||||
// This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls
|
||||
// await context.ChallengeAsync(MicrosoftAccountDefaults.AuthenticationScheme);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var currentAuthType = user.Identities.First().AuthenticationType;
|
||||
if (string.Equals(GoogleDefaults.AuthenticationScheme, currentAuthType)
|
||||
|| string.Equals(MicrosoftAccountDefaults.AuthenticationScheme, currentAuthType))
|
||||
{
|
||||
var refreshToken = authProperties.GetTokenValue("refresh_token");
|
||||
|
||||
if (string.IsNullOrEmpty(refreshToken))
|
||||
{
|
||||
response.ContentType = "text/html";
|
||||
await response.WriteAsync("<html><body>");
|
||||
await response.WriteAsync("No refresh_token is available.<br>");
|
||||
await response.WriteAsync("<a href=\"/\">Home</a>");
|
||||
await response.WriteAsync("</body></html>");
|
||||
return;
|
||||
}
|
||||
|
||||
var options = await GetOAuthOptionsAsync(context, currentAuthType);
|
||||
|
||||
var pairs = new Dictionary<string, string>()
|
||||
{
|
||||
{ "client_id", options.ClientId },
|
||||
{ "client_secret", options.ClientSecret },
|
||||
{ "grant_type", "refresh_token" },
|
||||
{ "refresh_token", refreshToken }
|
||||
};
|
||||
var content = new FormUrlEncodedContent(pairs);
|
||||
var refreshResponse = await options.Backchannel.PostAsync(options.TokenEndpoint, content, context.RequestAborted);
|
||||
refreshResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var payload = JObject.Parse(await refreshResponse.Content.ReadAsStringAsync());
|
||||
|
||||
// Persist the new acess token
|
||||
authProperties.UpdateTokenValue("access_token", payload.Value<string>("access_token"));
|
||||
refreshToken = payload.Value<string>("refresh_token");
|
||||
if (!string.IsNullOrEmpty(refreshToken))
|
||||
{
|
||||
authProperties.UpdateTokenValue("refresh_token", refreshToken);
|
||||
}
|
||||
if (int.TryParse(payload.Value<string>("expires_in"), NumberStyles.Integer, CultureInfo.InvariantCulture, out var seconds))
|
||||
{
|
||||
var expiresAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds);
|
||||
authProperties.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));
|
||||
}
|
||||
await context.SignInAsync(user, authProperties);
|
||||
|
||||
await PrintRefreshedTokensAsync(response, payload, authProperties);
|
||||
|
||||
return;
|
||||
}
|
||||
// https://developers.facebook.com/docs/facebook-login/access-tokens/expiration-and-extension
|
||||
else if (string.Equals(FacebookDefaults.AuthenticationScheme, currentAuthType))
|
||||
{
|
||||
var options = await GetOAuthOptionsAsync(context, currentAuthType);
|
||||
|
||||
var accessToken = authProperties.GetTokenValue("access_token");
|
||||
|
||||
var query = new QueryBuilder()
|
||||
{
|
||||
{ "grant_type", "fb_exchange_token" },
|
||||
{ "client_id", options.ClientId },
|
||||
{ "client_secret", options.ClientSecret },
|
||||
{ "fb_exchange_token", accessToken },
|
||||
}.ToQueryString();
|
||||
|
||||
var refreshResponse = await options.Backchannel.GetStringAsync(options.TokenEndpoint + query);
|
||||
var payload = JObject.Parse(refreshResponse);
|
||||
|
||||
authProperties.UpdateTokenValue("access_token", payload.Value<string>("access_token"));
|
||||
if (int.TryParse(payload.Value<string>("expires_in"), NumberStyles.Integer, CultureInfo.InvariantCulture, out var seconds))
|
||||
{
|
||||
var expiresAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds);
|
||||
authProperties.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));
|
||||
}
|
||||
await context.SignInAsync(user, authProperties);
|
||||
|
||||
await PrintRefreshedTokensAsync(response, payload, authProperties);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
response.ContentType = "text/html";
|
||||
await response.WriteAsync("<html><body>");
|
||||
await response.WriteAsync("Refresh has not been implemented for this provider.<br>");
|
||||
await response.WriteAsync("<a href=\"/\">Home</a>");
|
||||
await response.WriteAsync("</body></html>");
|
||||
});
|
||||
});
|
||||
|
||||
// Sign-out to remove the user cookie.
|
||||
app.Map("/logout", signoutApp =>
|
||||
{
|
||||
signoutApp.Run(async context =>
|
||||
{
|
||||
var response = context.Response;
|
||||
response.ContentType = "text/html";
|
||||
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
await response.WriteAsync("<html><body>");
|
||||
await response.WriteAsync("You have been logged out. Goodbye " + context.User.Identity.Name + "<br>");
|
||||
await response.WriteAsync("<a href=\"/\">Home</a>");
|
||||
await response.WriteAsync("</body></html>");
|
||||
});
|
||||
});
|
||||
|
||||
// Display the remote error
|
||||
app.Map("/error", errorApp =>
|
||||
{
|
||||
errorApp.Run(async context =>
|
||||
{
|
||||
var response = context.Response;
|
||||
response.ContentType = "text/html";
|
||||
await response.WriteAsync("<html><body>");
|
||||
await response.WriteAsync("An remote failure has occurred: " + context.Request.Query["FailureMessage"] + "<br>");
|
||||
await response.WriteAsync("<a href=\"/\">Home</a>");
|
||||
await response.WriteAsync("</body></html>");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
app.Run(async context =>
|
||||
{
|
||||
// Setting DefaultAuthenticateScheme causes User to be set
|
||||
var user = context.User;
|
||||
|
||||
// This is what [Authorize] calls
|
||||
// var user = await context.AuthenticateAsync();
|
||||
|
||||
// This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls
|
||||
// var user = await context.AuthenticateAsync(MicrosoftAccountDefaults.AuthenticationScheme);
|
||||
|
||||
// Deny anonymous request beyond this point.
|
||||
if (user == null || !user.Identities.Any(identity => identity.IsAuthenticated))
|
||||
{
|
||||
// This is what [Authorize] calls
|
||||
// The cookie middleware will handle this and redirect to /login
|
||||
await context.ChallengeAsync();
|
||||
|
||||
// This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls
|
||||
// await context.ChallengeAsync(MicrosoftAccountDefaults.AuthenticationScheme);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Display user information
|
||||
var response = context.Response;
|
||||
response.ContentType = "text/html";
|
||||
await response.WriteAsync("<html><body>");
|
||||
await response.WriteAsync("Hello " + (context.User.Identity.Name ?? "anonymous") + "<br>");
|
||||
foreach (var claim in context.User.Claims)
|
||||
{
|
||||
await response.WriteAsync(claim.Type + ": " + claim.Value + "<br>");
|
||||
}
|
||||
|
||||
await response.WriteAsync("Tokens:<br>");
|
||||
|
||||
await response.WriteAsync("Access Token: " + await context.GetTokenAsync("access_token") + "<br>");
|
||||
await response.WriteAsync("Refresh Token: " + await context.GetTokenAsync("refresh_token") + "<br>");
|
||||
await response.WriteAsync("Token Type: " + await context.GetTokenAsync("token_type") + "<br>");
|
||||
await response.WriteAsync("expires_at: " + await context.GetTokenAsync("expires_at") + "<br>");
|
||||
await response.WriteAsync("<a href=\"/logout\">Logout</a><br>");
|
||||
await response.WriteAsync("<a href=\"/refresh_token\">Refresh Token</a><br>");
|
||||
await response.WriteAsync("</body></html>");
|
||||
});
|
||||
}
|
||||
|
||||
private Task<OAuthOptions> GetOAuthOptionsAsync(HttpContext context, string currentAuthType)
|
||||
{
|
||||
if (string.Equals(GoogleDefaults.AuthenticationScheme, currentAuthType))
|
||||
{
|
||||
return Task.FromResult<OAuthOptions>(context.RequestServices.GetRequiredService<IOptionsMonitor<GoogleOptions>>().Get(currentAuthType));
|
||||
}
|
||||
else if (string.Equals(MicrosoftAccountDefaults.AuthenticationScheme, currentAuthType))
|
||||
{
|
||||
return Task.FromResult<OAuthOptions>(context.RequestServices.GetRequiredService<IOptionsMonitor<MicrosoftAccountOptions>>().Get(currentAuthType));
|
||||
}
|
||||
else if (string.Equals(FacebookDefaults.AuthenticationScheme, currentAuthType))
|
||||
{
|
||||
return Task.FromResult<OAuthOptions>(context.RequestServices.GetRequiredService<IOptionsMonitor<FacebookOptions>>().Get(currentAuthType));
|
||||
}
|
||||
|
||||
throw new NotImplementedException(currentAuthType);
|
||||
}
|
||||
|
||||
private async Task PrintRefreshedTokensAsync(HttpResponse response, JObject payload, AuthenticationProperties authProperties)
|
||||
{
|
||||
response.ContentType = "text/html";
|
||||
await response.WriteAsync("<html><body>");
|
||||
await response.WriteAsync("Refreshed.<br>");
|
||||
await response.WriteAsync(HtmlEncoder.Default.Encode(payload.ToString()).Replace(",", ",<br>") + "<br>");
|
||||
|
||||
await response.WriteAsync("<br>Tokens:<br>");
|
||||
|
||||
await response.WriteAsync("Access Token: " + authProperties.GetTokenValue("access_token") + "<br>");
|
||||
await response.WriteAsync("Refresh Token: " + authProperties.GetTokenValue("refresh_token") + "<br>");
|
||||
await response.WriteAsync("Token Type: " + authProperties.GetTokenValue("token_type") + "<br>");
|
||||
await response.WriteAsync("expires_at: " + authProperties.GetTokenValue("expires_at") + "<br>");
|
||||
|
||||
await response.WriteAsync("<a href=\"/\">Home</a><br>");
|
||||
await response.WriteAsync("<a href=\"/refresh_token\">Refresh Token</a><br>");
|
||||
await response.WriteAsync("</body></html>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<system.webServer>
|
||||
<handlers>
|
||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
|
||||
</handlers>
|
||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" />
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace WsFedSample
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.ConfigureLogging(factory =>
|
||||
{
|
||||
factory.AddConsole();
|
||||
factory.AddDebug();
|
||||
factory.AddFilter("Console", level => level >= LogLevel.Information);
|
||||
factory.AddFilter("Debug", level => level >= LogLevel.Information);
|
||||
})
|
||||
.UseKestrel(options =>
|
||||
{
|
||||
options.Listen(IPAddress.Loopback, 44307, listenOptions =>
|
||||
{
|
||||
// Configure SSL
|
||||
var serverCertificate = LoadCertificate();
|
||||
listenOptions.UseHttps(serverCertificate);
|
||||
});
|
||||
})
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
|
||||
private static X509Certificate2 LoadCertificate()
|
||||
{
|
||||
var assembly = typeof(Startup).GetTypeInfo().Assembly;
|
||||
var embeddedFileProvider = new EmbeddedFileProvider(assembly, "WsFedSample");
|
||||
var certificateFileInfo = embeddedFileProvider.GetFileInfo("compiler/resources/cert.pfx");
|
||||
using (var certificateStream = certificateFileInfo.CreateReadStream())
|
||||
{
|
||||
byte[] certificatePayload;
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
certificateStream.CopyTo(memoryStream);
|
||||
certificatePayload = memoryStream.ToArray();
|
||||
}
|
||||
|
||||
return new X509Certificate2(certificatePayload, "testPassword");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "https://localhost:44307/",
|
||||
"sslPort": 44318
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "https://localhost:44307/",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"WsFedSample": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:44307/",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.WsFederation;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace WsFedSample
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddAuthentication(sharedOptions =>
|
||||
{
|
||||
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddWsFederation(options =>
|
||||
{
|
||||
options.Wtrealm = "https://Tratcheroutlook.onmicrosoft.com/WsFedSample";
|
||||
options.MetadataAddress = "https://login.windows.net/cdc690f9-b6b8-4023-813a-bae7143d1f87/FederationMetadata/2007-06/FederationMetadata.xml";
|
||||
// options.CallbackPath = "/";
|
||||
// options.SkipUnrecognizedRequests = true;
|
||||
})
|
||||
.AddCookie();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseAuthentication();
|
||||
|
||||
app.Run(async context =>
|
||||
{
|
||||
if (context.Request.Path.Equals("/signedout"))
|
||||
{
|
||||
await WriteHtmlAsync(context.Response, async res =>
|
||||
{
|
||||
await res.WriteAsync($"<h1>You have been signed out.</h1>");
|
||||
await res.WriteAsync("<a class=\"btn btn-link\" href=\"/\">Sign In</a>");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Request.Path.Equals("/signout"))
|
||||
{
|
||||
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
await WriteHtmlAsync(context.Response, async res =>
|
||||
{
|
||||
await context.Response.WriteAsync($"<h1>Signed out {HtmlEncode(context.User.Identity.Name)}</h1>");
|
||||
await context.Response.WriteAsync("<a class=\"btn btn-link\" href=\"/\">Sign In</a>");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Request.Path.Equals("/signout-remote"))
|
||||
{
|
||||
// Redirects
|
||||
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
await context.SignOutAsync(WsFederationDefaults.AuthenticationScheme, new AuthenticationProperties()
|
||||
{
|
||||
RedirectUri = "/signedout"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Request.Path.Equals("/Account/AccessDenied"))
|
||||
{
|
||||
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("<a class=\"btn btn-link\" href=\"/signout\">Sign Out</a>");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// DefaultAuthenticateScheme causes User to be set
|
||||
var user = context.User;
|
||||
|
||||
// This is what [Authorize] calls
|
||||
// var user = await context.AuthenticateAsync();
|
||||
|
||||
// This is what [Authorize(ActiveAuthenticationSchemes = WsFederationDefaults.AuthenticationScheme)] calls
|
||||
// var user = await context.AuthenticateAsync(WsFederationDefaults.AuthenticationScheme);
|
||||
|
||||
// Not authenticated
|
||||
if (user == null || !user.Identities.Any(identity => identity.IsAuthenticated))
|
||||
{
|
||||
// This is what [Authorize] calls
|
||||
await context.ChallengeAsync();
|
||||
|
||||
// This is what [Authorize(ActiveAuthenticationSchemes = WsFederationDefaults.AuthenticationScheme)] calls
|
||||
// await context.ChallengeAsync(WsFederationDefaults.AuthenticationScheme);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Authenticated, but not authorized
|
||||
if (context.Request.Path.Equals("/restricted") && !user.Identities.Any(identity => identity.HasClaim("special", "true")))
|
||||
{
|
||||
await context.ForbidAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await WriteHtmlAsync(context.Response, async response =>
|
||||
{
|
||||
await response.WriteAsync($"<h1>Hello Authenticated User {HtmlEncode(user.Identity.Name)}</h1>");
|
||||
await response.WriteAsync("<a class=\"btn btn-default\" href=\"/restricted\">Restricted</a>");
|
||||
await response.WriteAsync("<a class=\"btn btn-default\" href=\"/signout\">Sign Out</a>");
|
||||
await response.WriteAsync("<a class=\"btn btn-default\" href=\"/signout-remote\">Sign Out Remote</a>");
|
||||
|
||||
await response.WriteAsync("<h2>Claims:</h2>");
|
||||
await WriteTableHeader(response, new string[] { "Claim Type", "Value" }, context.User.Claims.Select(c => new string[] { c.Type, c.Value }));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static async Task WriteHtmlAsync(HttpResponse response, Func<HttpResponse, Task> writeContent)
|
||||
{
|
||||
var bootstrap = "<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u\" crossorigin=\"anonymous\">";
|
||||
|
||||
response.ContentType = "text/html";
|
||||
await response.WriteAsync($"<html><head>{bootstrap}</head><body><div class=\"container\">");
|
||||
await writeContent(response);
|
||||
await response.WriteAsync("</div></body></html>");
|
||||
}
|
||||
|
||||
private static async Task WriteTableHeader(HttpResponse response, IEnumerable<string> columns, IEnumerable<IEnumerable<string>> data)
|
||||
{
|
||||
await response.WriteAsync("<table class=\"table table-condensed\">");
|
||||
await response.WriteAsync("<tr>");
|
||||
foreach (var column in columns)
|
||||
{
|
||||
await response.WriteAsync($"<th>{HtmlEncode(column)}</th>");
|
||||
}
|
||||
await response.WriteAsync("</tr>");
|
||||
foreach (var row in data)
|
||||
{
|
||||
await response.WriteAsync("<tr>");
|
||||
foreach (var column in row)
|
||||
{
|
||||
await response.WriteAsync($"<td>{HtmlEncode(column)}</td>");
|
||||
}
|
||||
await response.WriteAsync("</tr>");
|
||||
}
|
||||
await response.WriteAsync("</table>");
|
||||
}
|
||||
|
||||
private static string HtmlEncode(string content) =>
|
||||
string.IsNullOrEmpty(content) ? string.Empty : HtmlEncoder.Default.Encode(content);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.WsFederation\Microsoft.AspNetCore.Authentication.WsFederation.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="$(MicrosoftAspNetCoreServerKestrelHttpsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="$(MicrosoftExtensionsFileProvidersEmbeddedPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="$(MicrosoftExtensionsLoggingDebugPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="compiler\resources\cert.pfx" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Binary file not shown.
|
|
@ -0,0 +1,309 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
// Keep the type public for Security repo as it would be a breaking change to change the accessor now.
|
||||
// Make this type internal for other repos as it could be used by multiple projects and having it public causes type conflicts.
|
||||
#if SECURITY
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
/// <summary>
|
||||
/// This handles cookies that are limited by per cookie length. It breaks down long cookies for responses, and reassembles them
|
||||
/// from requests.
|
||||
/// </summary>
|
||||
public class ChunkingCookieManager : ICookieManager
|
||||
{
|
||||
#else
|
||||
namespace Microsoft.AspNetCore.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// This handles cookies that are limited by per cookie length. It breaks down long cookies for responses, and reassembles them
|
||||
/// from requests.
|
||||
/// </summary>
|
||||
internal class ChunkingCookieManager
|
||||
{
|
||||
#endif
|
||||
/// <summary>
|
||||
/// The default maximum size of characters in a cookie to send back to the client.
|
||||
/// </summary>
|
||||
public const int DefaultChunkSize = 4050;
|
||||
|
||||
private const string ChunkKeySuffix = "C";
|
||||
private const string ChunkCountPrefix = "chunks-";
|
||||
|
||||
public ChunkingCookieManager()
|
||||
{
|
||||
// Lowest common denominator. Safari has the lowest known limit (4093), and we leave little extra just in case.
|
||||
// See http://browsercookielimits.x64.me/.
|
||||
// Leave at least 40 in case CookiePolicy tries to add 'secure', 'samesite=strict' and/or 'httponly'.
|
||||
ChunkSize = DefaultChunkSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The maximum size of cookie to send back to the client. If a cookie exceeds this size it will be broken down into multiple
|
||||
/// cookies. Set this value to null to disable this behavior. The default is 4090 characters, which is supported by all
|
||||
/// common browsers.
|
||||
///
|
||||
/// Note that browsers may also have limits on the total size of all cookies per domain, and on the number of cookies per domain.
|
||||
/// </summary>
|
||||
public int? ChunkSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Throw if not all chunks of a cookie are available on a request for re-assembly.
|
||||
/// </summary>
|
||||
public bool ThrowForPartialCookies { get; set; }
|
||||
|
||||
// Parse the "chunks-XX" to determine how many chunks there should be.
|
||||
private static int ParseChunksCount(string value)
|
||||
{
|
||||
if (value != null && value.StartsWith(ChunkCountPrefix, StringComparison.Ordinal))
|
||||
{
|
||||
var chunksCountString = value.Substring(ChunkCountPrefix.Length);
|
||||
int chunksCount;
|
||||
if (int.TryParse(chunksCountString, NumberStyles.None, CultureInfo.InvariantCulture, out chunksCount))
|
||||
{
|
||||
return chunksCount;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the reassembled cookie. Non chunked cookies are returned normally.
|
||||
/// Cookies with missing chunks just have their "chunks-XX" header returned.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>The reassembled cookie, if any, or null.</returns>
|
||||
public string GetRequestCookie(HttpContext context, string key)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
var requestCookies = context.Request.Cookies;
|
||||
var value = requestCookies[key];
|
||||
var chunksCount = ParseChunksCount(value);
|
||||
if (chunksCount > 0)
|
||||
{
|
||||
var chunks = new string[chunksCount];
|
||||
for (var chunkId = 1; chunkId <= chunksCount; chunkId++)
|
||||
{
|
||||
var chunk = requestCookies[key + ChunkKeySuffix + chunkId.ToString(CultureInfo.InvariantCulture)];
|
||||
if (string.IsNullOrEmpty(chunk))
|
||||
{
|
||||
if (ThrowForPartialCookies)
|
||||
{
|
||||
var totalSize = 0;
|
||||
for (int i = 0; i < chunkId - 1; i++)
|
||||
{
|
||||
totalSize += chunks[i].Length;
|
||||
}
|
||||
throw new FormatException(
|
||||
string.Format(
|
||||
CultureInfo.CurrentCulture,
|
||||
"The chunked cookie is incomplete. Only {0} of the expected {1} chunks were found, totaling {2} characters. A client size limit may have been exceeded.",
|
||||
chunkId - 1,
|
||||
chunksCount,
|
||||
totalSize));
|
||||
}
|
||||
// Missing chunk, abort by returning the original cookie value. It may have been a false positive?
|
||||
return value;
|
||||
}
|
||||
|
||||
chunks[chunkId - 1] = chunk;
|
||||
}
|
||||
|
||||
return string.Join(string.Empty, chunks);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends a new response cookie to the Set-Cookie header. If the cookie is larger than the given size limit
|
||||
/// then it will be broken down into multiple cookies as follows:
|
||||
/// Set-Cookie: CookieName=chunks-3; path=/
|
||||
/// Set-Cookie: CookieNameC1=Segment1; path=/
|
||||
/// Set-Cookie: CookieNameC2=Segment2; path=/
|
||||
/// Set-Cookie: CookieNameC3=Segment3; path=/
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="options"></param>
|
||||
public void AppendResponseCookie(HttpContext context, string key, string value, CookieOptions options)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
var template = new SetCookieHeaderValue(key)
|
||||
{
|
||||
Domain = options.Domain,
|
||||
Expires = options.Expires,
|
||||
SameSite = (Net.Http.Headers.SameSiteMode)options.SameSite,
|
||||
HttpOnly = options.HttpOnly,
|
||||
Path = options.Path,
|
||||
Secure = options.Secure,
|
||||
};
|
||||
|
||||
var templateLength = template.ToString().Length;
|
||||
|
||||
value = value ?? string.Empty;
|
||||
|
||||
// Normal cookie
|
||||
var responseCookies = context.Response.Cookies;
|
||||
if (!ChunkSize.HasValue || ChunkSize.Value > templateLength + value.Length)
|
||||
{
|
||||
responseCookies.Append(key, value, options);
|
||||
}
|
||||
else if (ChunkSize.Value < templateLength + 10)
|
||||
{
|
||||
// 10 is the minimum data we want to put in an individual cookie, including the cookie chunk identifier "CXX".
|
||||
// No room for data, we can't chunk the options and name
|
||||
throw new InvalidOperationException("The cookie key and options are larger than ChunksSize, leaving no room for data.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Break the cookie down into multiple cookies.
|
||||
// Key = CookieName, value = "Segment1Segment2Segment2"
|
||||
// Set-Cookie: CookieName=chunks-3; path=/
|
||||
// Set-Cookie: CookieNameC1="Segment1"; path=/
|
||||
// Set-Cookie: CookieNameC2="Segment2"; path=/
|
||||
// Set-Cookie: CookieNameC3="Segment3"; path=/
|
||||
var dataSizePerCookie = ChunkSize.Value - templateLength - 3; // Budget 3 chars for the chunkid.
|
||||
var cookieChunkCount = (int)Math.Ceiling(value.Length * 1.0 / dataSizePerCookie);
|
||||
|
||||
responseCookies.Append(key, ChunkCountPrefix + cookieChunkCount.ToString(CultureInfo.InvariantCulture), options);
|
||||
|
||||
var offset = 0;
|
||||
for (var chunkId = 1; chunkId <= cookieChunkCount; chunkId++)
|
||||
{
|
||||
var remainingLength = value.Length - offset;
|
||||
var length = Math.Min(dataSizePerCookie, remainingLength);
|
||||
var segment = value.Substring(offset, length);
|
||||
offset += length;
|
||||
|
||||
responseCookies.Append(key + ChunkKeySuffix + chunkId.ToString(CultureInfo.InvariantCulture), segment, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the cookie with the given key by setting an expired state. If a matching chunked cookie exists on
|
||||
/// the request, delete each chunk.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="options"></param>
|
||||
public void DeleteCookie(HttpContext context, string key, CookieOptions options)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
var keys = new List<string>();
|
||||
keys.Add(key + "=");
|
||||
|
||||
var requestCookie = context.Request.Cookies[key];
|
||||
var chunks = ParseChunksCount(requestCookie);
|
||||
if (chunks > 0)
|
||||
{
|
||||
for (int i = 1; i <= chunks + 1; i++)
|
||||
{
|
||||
var subkey = key + ChunkKeySuffix + i.ToString(CultureInfo.InvariantCulture);
|
||||
keys.Add(subkey + "=");
|
||||
}
|
||||
}
|
||||
|
||||
var domainHasValue = !string.IsNullOrEmpty(options.Domain);
|
||||
var pathHasValue = !string.IsNullOrEmpty(options.Path);
|
||||
|
||||
Func<string, bool> rejectPredicate;
|
||||
Func<string, bool> predicate = value => keys.Any(k => value.StartsWith(k, StringComparison.OrdinalIgnoreCase));
|
||||
if (domainHasValue)
|
||||
{
|
||||
rejectPredicate = value => predicate(value) && value.IndexOf("domain=" + options.Domain, StringComparison.OrdinalIgnoreCase) != -1;
|
||||
}
|
||||
else if (pathHasValue)
|
||||
{
|
||||
rejectPredicate = value => predicate(value) && value.IndexOf("path=" + options.Path, StringComparison.OrdinalIgnoreCase) != -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rejectPredicate = value => predicate(value);
|
||||
}
|
||||
|
||||
var responseHeaders = context.Response.Headers;
|
||||
var existingValues = responseHeaders[HeaderNames.SetCookie];
|
||||
if (!StringValues.IsNullOrEmpty(existingValues))
|
||||
{
|
||||
responseHeaders[HeaderNames.SetCookie] = existingValues.Where(value => !rejectPredicate(value)).ToArray();
|
||||
}
|
||||
|
||||
AppendResponseCookie(
|
||||
context,
|
||||
key,
|
||||
string.Empty,
|
||||
new CookieOptions()
|
||||
{
|
||||
Path = options.Path,
|
||||
Domain = options.Domain,
|
||||
SameSite = options.SameSite,
|
||||
IsEssential = options.IsEssential,
|
||||
Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
|
||||
});
|
||||
|
||||
for (int i = 1; i <= chunks; i++)
|
||||
{
|
||||
AppendResponseCookie(
|
||||
context,
|
||||
key + "C" + i.ToString(CultureInfo.InvariantCulture),
|
||||
string.Empty,
|
||||
new CookieOptions()
|
||||
{
|
||||
Path = options.Path,
|
||||
Domain = options.Domain,
|
||||
SameSite = options.SameSite,
|
||||
IsEssential = options.IsEssential,
|
||||
Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<Project>
|
||||
<Import Project="..\Directory.Build.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Internal.AspNetCore.Sdk" PrivateAssets="All" Version="$(InternalAspNetCoreSdkPackageVersion)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
internal static class Constants
|
||||
{
|
||||
internal static class Headers
|
||||
{
|
||||
internal const string SetCookie = "Set-Cookie";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods to add cookie authentication capabilities to an HTTP application pipeline.
|
||||
/// </summary>
|
||||
public static class CookieAppBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// UseCookieAuthentication is obsolete. Configure Cookie authentication with AddAuthentication().AddCookie in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
[Obsolete("UseCookieAuthentication is obsolete. Configure Cookie authentication with AddAuthentication().AddCookie in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)]
|
||||
public static IApplicationBuilder UseCookieAuthentication(this IApplicationBuilder app)
|
||||
{
|
||||
throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UseCookieAuthentication is obsolete. Configure Cookie authentication with AddAuthentication().AddCookie in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.
|
||||
/// </summary>
|
||||
/// <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 handler.</param>
|
||||
/// <returns>A reference to this instance after the operation has completed.</returns>
|
||||
[Obsolete("UseCookieAuthentication is obsolete. Configure Cookie authentication with AddAuthentication().AddCookie in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)]
|
||||
public static IApplicationBuilder UseCookieAuthentication(this IApplicationBuilder app, CookieAuthenticationOptions options)
|
||||
{
|
||||
throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
/// <summary>
|
||||
/// Default values related to cookie-based authentication handler
|
||||
/// </summary>
|
||||
public static class CookieAuthenticationDefaults
|
||||
{
|
||||
/// <summary>
|
||||
/// The default value used for CookieAuthenticationOptions.AuthenticationScheme
|
||||
/// </summary>
|
||||
public const string AuthenticationScheme = "Cookies";
|
||||
|
||||
/// <summary>
|
||||
/// The prefix used to provide a default CookieAuthenticationOptions.CookieName
|
||||
/// </summary>
|
||||
public static readonly string CookiePrefix = ".AspNetCore.";
|
||||
|
||||
/// <summary>
|
||||
/// The default value used by CookieAuthenticationMiddleware for the
|
||||
/// CookieAuthenticationOptions.LoginPath
|
||||
/// </summary>
|
||||
public static readonly PathString LoginPath = new PathString("/Account/Login");
|
||||
|
||||
/// <summary>
|
||||
/// The default value used by CookieAuthenticationMiddleware for the
|
||||
/// CookieAuthenticationOptions.LogoutPath
|
||||
/// </summary>
|
||||
public static readonly PathString LogoutPath = new PathString("/Account/Logout");
|
||||
|
||||
/// <summary>
|
||||
/// The default value used by CookieAuthenticationMiddleware for the
|
||||
/// CookieAuthenticationOptions.AccessDeniedPath
|
||||
/// </summary>
|
||||
public static readonly PathString AccessDeniedPath = new PathString("/Account/AccessDenied");
|
||||
|
||||
/// <summary>
|
||||
/// The default value of the CookieAuthenticationOptions.ReturnUrlParameter
|
||||
/// </summary>
|
||||
public static readonly string ReturnUrlParameter = "ReturnUrl";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,451 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
public class CookieAuthenticationHandler : SignInAuthenticationHandler<CookieAuthenticationOptions>
|
||||
{
|
||||
private const string HeaderValueNoCache = "no-cache";
|
||||
private const string HeaderValueEpocDate = "Thu, 01 Jan 1970 00:00:00 GMT";
|
||||
private const string SessionIdClaim = "Microsoft.AspNetCore.Authentication.Cookies-SessionId";
|
||||
|
||||
private bool _shouldRefresh;
|
||||
private bool _signInCalled;
|
||||
private bool _signOutCalled;
|
||||
|
||||
private DateTimeOffset? _refreshIssuedUtc;
|
||||
private DateTimeOffset? _refreshExpiresUtc;
|
||||
private string _sessionKey;
|
||||
private Task<AuthenticateResult> _readCookieTask;
|
||||
private AuthenticationTicket _refreshTicket;
|
||||
|
||||
public CookieAuthenticationHandler(IOptionsMonitor<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 Task.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());
|
||||
|
||||
private Task<AuthenticateResult> EnsureCookieTicket()
|
||||
{
|
||||
// We only need to read the ticket once
|
||||
if (_readCookieTask == null)
|
||||
{
|
||||
_readCookieTask = ReadCookieTicket();
|
||||
}
|
||||
return _readCookieTask;
|
||||
}
|
||||
|
||||
private void CheckForRefresh(AuthenticationTicket ticket)
|
||||
{
|
||||
var currentUtc = Clock.UtcNow;
|
||||
var issuedUtc = ticket.Properties.IssuedUtc;
|
||||
var expiresUtc = ticket.Properties.ExpiresUtc;
|
||||
var allowRefresh = ticket.Properties.AllowRefresh ?? true;
|
||||
if (issuedUtc != null && expiresUtc != null && Options.SlidingExpiration && allowRefresh)
|
||||
{
|
||||
var timeElapsed = currentUtc.Subtract(issuedUtc.Value);
|
||||
var timeRemaining = expiresUtc.Value.Subtract(currentUtc);
|
||||
|
||||
if (timeRemaining < timeElapsed)
|
||||
{
|
||||
RequestRefresh(ticket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RequestRefresh(AuthenticationTicket ticket, ClaimsPrincipal replacedPrincipal = null)
|
||||
{
|
||||
var issuedUtc = ticket.Properties.IssuedUtc;
|
||||
var expiresUtc = ticket.Properties.ExpiresUtc;
|
||||
|
||||
if (issuedUtc != null && expiresUtc != null)
|
||||
{
|
||||
_shouldRefresh = true;
|
||||
var currentUtc = Clock.UtcNow;
|
||||
_refreshIssuedUtc = currentUtc;
|
||||
var timeSpan = expiresUtc.Value.Subtract(issuedUtc.Value);
|
||||
_refreshExpiresUtc = currentUtc.Add(timeSpan);
|
||||
_refreshTicket = CloneTicket(ticket, replacedPrincipal);
|
||||
}
|
||||
}
|
||||
|
||||
private AuthenticationTicket CloneTicket(AuthenticationTicket ticket, ClaimsPrincipal replacedPrincipal)
|
||||
{
|
||||
var principal = replacedPrincipal ?? ticket.Principal;
|
||||
var newPrincipal = new ClaimsPrincipal();
|
||||
foreach (var identity in principal.Identities)
|
||||
{
|
||||
newPrincipal.AddIdentity(identity.Clone());
|
||||
}
|
||||
|
||||
var newProperties = new AuthenticationProperties();
|
||||
foreach (var item in ticket.Properties.Items)
|
||||
{
|
||||
newProperties.Items[item.Key] = item.Value;
|
||||
}
|
||||
|
||||
return new AuthenticationTicket(newPrincipal, newProperties, ticket.AuthenticationScheme);
|
||||
}
|
||||
|
||||
private async Task<AuthenticateResult> ReadCookieTicket()
|
||||
{
|
||||
var cookie = Options.CookieManager.GetRequestCookie(Context, Options.Cookie.Name);
|
||||
if (string.IsNullOrEmpty(cookie))
|
||||
{
|
||||
return AuthenticateResult.NoResult();
|
||||
}
|
||||
|
||||
var ticket = Options.TicketDataFormat.Unprotect(cookie, GetTlsTokenBinding());
|
||||
if (ticket == null)
|
||||
{
|
||||
return AuthenticateResult.Fail("Unprotect ticket failed");
|
||||
}
|
||||
|
||||
if (Options.SessionStore != null)
|
||||
{
|
||||
var claim = ticket.Principal.Claims.FirstOrDefault(c => c.Type.Equals(SessionIdClaim));
|
||||
if (claim == null)
|
||||
{
|
||||
return AuthenticateResult.Fail("SessionId missing");
|
||||
}
|
||||
_sessionKey = claim.Value;
|
||||
ticket = await Options.SessionStore.RetrieveAsync(_sessionKey);
|
||||
if (ticket == null)
|
||||
{
|
||||
return AuthenticateResult.Fail("Identity missing in session store");
|
||||
}
|
||||
}
|
||||
|
||||
var currentUtc = Clock.UtcNow;
|
||||
var expiresUtc = ticket.Properties.ExpiresUtc;
|
||||
|
||||
if (expiresUtc != null && expiresUtc.Value < currentUtc)
|
||||
{
|
||||
if (Options.SessionStore != null)
|
||||
{
|
||||
await Options.SessionStore.RemoveAsync(_sessionKey);
|
||||
}
|
||||
return AuthenticateResult.Fail("Ticket expired");
|
||||
}
|
||||
|
||||
CheckForRefresh(ticket);
|
||||
|
||||
// Finally we have a valid ticket
|
||||
return AuthenticateResult.Success(ticket);
|
||||
}
|
||||
|
||||
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
var result = await EnsureCookieTicket();
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var context = new CookieValidatePrincipalContext(Context, Scheme, Options, result.Ticket);
|
||||
await Events.ValidatePrincipal(context);
|
||||
|
||||
if (context.Principal == null)
|
||||
{
|
||||
return AuthenticateResult.Fail("No principal.");
|
||||
}
|
||||
|
||||
if (context.ShouldRenew)
|
||||
{
|
||||
RequestRefresh(result.Ticket, context.Principal);
|
||||
}
|
||||
|
||||
return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name));
|
||||
}
|
||||
|
||||
private CookieOptions BuildCookieOptions()
|
||||
{
|
||||
var cookieOptions = Options.Cookie.Build(Context);
|
||||
// ignore the 'Expires' value as this will be computed elsewhere
|
||||
cookieOptions.Expires = null;
|
||||
|
||||
return cookieOptions;
|
||||
}
|
||||
|
||||
protected virtual async Task FinishResponseAsync()
|
||||
{
|
||||
// Only renew if requested, and neither sign in or sign out was called
|
||||
if (!_shouldRefresh || _signInCalled || _signOutCalled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ticket = _refreshTicket;
|
||||
if (ticket != null)
|
||||
{
|
||||
var properties = ticket.Properties;
|
||||
|
||||
if (_refreshIssuedUtc.HasValue)
|
||||
{
|
||||
properties.IssuedUtc = _refreshIssuedUtc;
|
||||
}
|
||||
|
||||
if (_refreshExpiresUtc.HasValue)
|
||||
{
|
||||
properties.ExpiresUtc = _refreshExpiresUtc;
|
||||
}
|
||||
|
||||
if (Options.SessionStore != null && _sessionKey != null)
|
||||
{
|
||||
await Options.SessionStore.RenewAsync(_sessionKey, ticket);
|
||||
var principal = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) },
|
||||
Scheme.Name));
|
||||
ticket = new AuthenticationTicket(principal, null, Scheme.Name);
|
||||
}
|
||||
|
||||
var cookieValue = Options.TicketDataFormat.Protect(ticket, GetTlsTokenBinding());
|
||||
|
||||
var cookieOptions = BuildCookieOptions();
|
||||
if (properties.IsPersistent && _refreshExpiresUtc.HasValue)
|
||||
{
|
||||
cookieOptions.Expires = _refreshExpiresUtc.Value.ToUniversalTime();
|
||||
}
|
||||
|
||||
Options.CookieManager.AppendResponseCookie(
|
||||
Context,
|
||||
Options.Cookie.Name,
|
||||
cookieValue,
|
||||
cookieOptions);
|
||||
|
||||
await ApplyHeaders(shouldRedirectToReturnUrl: false, properties: properties);
|
||||
}
|
||||
}
|
||||
|
||||
protected async override Task HandleSignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
properties = properties ?? new AuthenticationProperties();
|
||||
|
||||
_signInCalled = true;
|
||||
|
||||
// Process the request cookie to initialize members like _sessionKey.
|
||||
await EnsureCookieTicket();
|
||||
var cookieOptions = BuildCookieOptions();
|
||||
|
||||
var signInContext = new CookieSigningInContext(
|
||||
Context,
|
||||
Scheme,
|
||||
Options,
|
||||
user,
|
||||
properties,
|
||||
cookieOptions);
|
||||
|
||||
DateTimeOffset issuedUtc;
|
||||
if (signInContext.Properties.IssuedUtc.HasValue)
|
||||
{
|
||||
issuedUtc = signInContext.Properties.IssuedUtc.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
issuedUtc = Clock.UtcNow;
|
||||
signInContext.Properties.IssuedUtc = issuedUtc;
|
||||
}
|
||||
|
||||
if (!signInContext.Properties.ExpiresUtc.HasValue)
|
||||
{
|
||||
signInContext.Properties.ExpiresUtc = issuedUtc.Add(Options.ExpireTimeSpan);
|
||||
}
|
||||
|
||||
await Events.SigningIn(signInContext);
|
||||
|
||||
if (signInContext.Properties.IsPersistent)
|
||||
{
|
||||
var expiresUtc = signInContext.Properties.ExpiresUtc ?? issuedUtc.Add(Options.ExpireTimeSpan);
|
||||
signInContext.CookieOptions.Expires = expiresUtc.ToUniversalTime();
|
||||
}
|
||||
|
||||
var ticket = new AuthenticationTicket(signInContext.Principal, signInContext.Properties, signInContext.Scheme.Name);
|
||||
|
||||
if (Options.SessionStore != null)
|
||||
{
|
||||
if (_sessionKey != null)
|
||||
{
|
||||
await Options.SessionStore.RemoveAsync(_sessionKey);
|
||||
}
|
||||
_sessionKey = await Options.SessionStore.StoreAsync(ticket);
|
||||
var principal = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) },
|
||||
Options.ClaimsIssuer));
|
||||
ticket = new AuthenticationTicket(principal, null, Scheme.Name);
|
||||
}
|
||||
|
||||
var cookieValue = Options.TicketDataFormat.Protect(ticket, GetTlsTokenBinding());
|
||||
|
||||
Options.CookieManager.AppendResponseCookie(
|
||||
Context,
|
||||
Options.Cookie.Name,
|
||||
cookieValue,
|
||||
signInContext.CookieOptions);
|
||||
|
||||
var signedInContext = new CookieSignedInContext(
|
||||
Context,
|
||||
Scheme,
|
||||
signInContext.Principal,
|
||||
signInContext.Properties,
|
||||
Options);
|
||||
|
||||
await Events.SignedIn(signedInContext);
|
||||
|
||||
// Only redirect on the login path
|
||||
var shouldRedirect = Options.LoginPath.HasValue && OriginalPath == Options.LoginPath;
|
||||
await ApplyHeaders(shouldRedirect, signedInContext.Properties);
|
||||
|
||||
Logger.SignedIn(Scheme.Name);
|
||||
}
|
||||
|
||||
protected async override Task HandleSignOutAsync(AuthenticationProperties properties)
|
||||
{
|
||||
properties = properties ?? new AuthenticationProperties();
|
||||
|
||||
_signOutCalled = true;
|
||||
|
||||
// Process the request cookie to initialize members like _sessionKey.
|
||||
await EnsureCookieTicket();
|
||||
var cookieOptions = BuildCookieOptions();
|
||||
if (Options.SessionStore != null && _sessionKey != null)
|
||||
{
|
||||
await Options.SessionStore.RemoveAsync(_sessionKey);
|
||||
}
|
||||
|
||||
var context = new CookieSigningOutContext(
|
||||
Context,
|
||||
Scheme,
|
||||
Options,
|
||||
properties,
|
||||
cookieOptions);
|
||||
|
||||
await Events.SigningOut(context);
|
||||
|
||||
Options.CookieManager.DeleteCookie(
|
||||
Context,
|
||||
Options.Cookie.Name,
|
||||
context.CookieOptions);
|
||||
|
||||
// Only redirect on the logout path
|
||||
var shouldRedirect = Options.LogoutPath.HasValue && OriginalPath == Options.LogoutPath;
|
||||
await ApplyHeaders(shouldRedirect, context.Properties);
|
||||
|
||||
Logger.SignedOut(Scheme.Name);
|
||||
}
|
||||
|
||||
private async Task ApplyHeaders(bool shouldRedirectToReturnUrl, AuthenticationProperties properties)
|
||||
{
|
||||
Response.Headers[HeaderNames.CacheControl] = HeaderValueNoCache;
|
||||
Response.Headers[HeaderNames.Pragma] = HeaderValueNoCache;
|
||||
Response.Headers[HeaderNames.Expires] = HeaderValueEpocDate;
|
||||
|
||||
if (shouldRedirectToReturnUrl && Response.StatusCode == 200)
|
||||
{
|
||||
// set redirect uri in order:
|
||||
// 1. properties.RedirectUri
|
||||
// 2. query parameter ReturnUrlParameter
|
||||
//
|
||||
// Absolute uri is not allowed if it is from query string as query string is not
|
||||
// a trusted source.
|
||||
var redirectUri = properties.RedirectUri;
|
||||
if (string.IsNullOrEmpty(redirectUri))
|
||||
{
|
||||
redirectUri = Request.Query[Options.ReturnUrlParameter];
|
||||
if (string.IsNullOrEmpty(redirectUri) || !IsHostRelative(redirectUri))
|
||||
{
|
||||
redirectUri = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (redirectUri != null)
|
||||
{
|
||||
await Events.RedirectToReturnUrl(
|
||||
new RedirectContext<CookieAuthenticationOptions>(Context, Scheme, Options, properties, redirectUri));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsHostRelative(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (path.Length == 1)
|
||||
{
|
||||
return path[0] == '/';
|
||||
}
|
||||
return path[0] == '/' && path[1] != '/' && path[1] != '\\';
|
||||
}
|
||||
|
||||
protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
|
||||
{
|
||||
var returnUrl = properties.RedirectUri;
|
||||
if (string.IsNullOrEmpty(returnUrl))
|
||||
{
|
||||
returnUrl = OriginalPathBase + Request.Path + Request.QueryString;
|
||||
}
|
||||
var accessDeniedUri = Options.AccessDeniedPath + QueryString.Create(Options.ReturnUrlParameter, returnUrl);
|
||||
var redirectContext = new RedirectContext<CookieAuthenticationOptions>(Context, Scheme, Options, properties, BuildRedirectUri(accessDeniedUri));
|
||||
await Events.RedirectToAccessDenied(redirectContext);
|
||||
}
|
||||
|
||||
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
|
||||
{
|
||||
var redirectUri = properties.RedirectUri;
|
||||
if (string.IsNullOrEmpty(redirectUri))
|
||||
{
|
||||
redirectUri = OriginalPathBase + Request.Path + Request.QueryString;
|
||||
}
|
||||
|
||||
var loginUri = Options.LoginPath + QueryString.Create(Options.ReturnUrlParameter, redirectUri);
|
||||
var redirectContext = new RedirectContext<CookieAuthenticationOptions>(Context, Scheme, Options, properties, BuildRedirectUri(loginUri));
|
||||
await Events.RedirectToLogin(redirectContext);
|
||||
}
|
||||
|
||||
private string GetTlsTokenBinding()
|
||||
{
|
||||
var binding = Context.Features.Get<ITlsTokenBindingFeature>()?.GetProvidedTokenBindingId();
|
||||
return binding == null ? null : Convert.ToBase64String(binding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
// 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.Internal;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration options for <see cref="CookieAuthenticationOptions"/>.
|
||||
/// </summary>
|
||||
public class CookieAuthenticationOptions : AuthenticationSchemeOptions
|
||||
{
|
||||
private CookieBuilder _cookieBuilder = new RequestPathBaseCookieBuilder
|
||||
{
|
||||
// the default name is configured in PostConfigureCookieAuthenticationOptions
|
||||
|
||||
// To support OAuth authentication, a lax mode is required, see https://github.com/aspnet/Security/issues/1231.
|
||||
SameSite = SameSiteMode.Lax,
|
||||
HttpOnly = true,
|
||||
SecurePolicy = CookieSecurePolicy.SameAsRequest,
|
||||
IsEssential = true,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of the options initialized with the default values
|
||||
/// </summary>
|
||||
public CookieAuthenticationOptions()
|
||||
{
|
||||
ExpireTimeSpan = TimeSpan.FromDays(14);
|
||||
ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
|
||||
SlidingExpiration = true;
|
||||
Events = new CookieAuthenticationEvents();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Determines the settings used to create the cookie.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <seealso cref="CookieBuilder.SameSite"/> defaults to <see cref="SameSiteMode.Lax"/>.
|
||||
/// <seealso cref="CookieBuilder.HttpOnly"/> defaults to <c>true</c>.
|
||||
/// <seealso cref="CookieBuilder.SecurePolicy"/> defaults to <see cref="CookieSecurePolicy.SameAsRequest"/>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The default value for cookie name is ".AspNetCore.Cookies".
|
||||
/// This value should be changed if you change the name of the AuthenticationScheme, especially if your
|
||||
/// system uses the cookie authentication handler multiple times.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <seealso cref="CookieBuilder.SameSite"/> determines if the browser should allow the cookie to be attached to same-site or cross-site requests.
|
||||
/// The default is Lax, which means the cookie is only allowed to be attached to cross-site requests using safe HTTP methods and same-site requests.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <seealso cref="CookieBuilder.HttpOnly"/> determines if the browser should allow the cookie to be accessed by client-side javascript.
|
||||
/// The default is true, which means the cookie will only be passed to http requests and is not made available to script on the page.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <seealso cref="CookieBuilder.Expiration"/> is currently ignored. Use <see cref="ExpireTimeSpan"/> to control lifetime of cookie authentication.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public CookieBuilder Cookie
|
||||
{
|
||||
get => _cookieBuilder;
|
||||
set => _cookieBuilder = value ?? throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If set this will be used by the CookieAuthenticationHandler for data protection.
|
||||
/// </summary>
|
||||
public IDataProtectionProvider DataProtectionProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public bool SlidingExpiration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The LoginPath property is used by the handler for the redirection target when handling ChallengeAsync.
|
||||
/// The current url which is added 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 to the original url.
|
||||
/// </summary>
|
||||
public PathString LoginPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the LogoutPath is provided the handler then a request to that path will redirect based on the ReturnUrlParameter.
|
||||
/// </summary>
|
||||
public PathString LogoutPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The AccessDeniedPath property is used by the handler for the redirection target when handling ForbidAsync.
|
||||
/// </summary>
|
||||
public PathString AccessDeniedPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ReturnUrlParameter determines the name of the query string parameter which is appended by the handler
|
||||
/// when during a Challenge. 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 original url after the action is performed.
|
||||
/// </summary>
|
||||
public string ReturnUrlParameter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// If it is not provided a default instance is supplied which does nothing when the methods are called.
|
||||
/// </summary>
|
||||
public new CookieAuthenticationEvents Events
|
||||
{
|
||||
get => (CookieAuthenticationEvents)base.Events;
|
||||
set => base.Events = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The TicketDataFormat is used to protect and unprotect the identity and other properties which are stored in the
|
||||
/// cookie value. If not provided one will be created using <see cref="DataProtectionProvider"/>.
|
||||
/// </summary>
|
||||
public ISecureDataFormat<AuthenticationTicket> TicketDataFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The component used to get cookies from the request or set them on the response.
|
||||
///
|
||||
/// ChunkingCookieManager will be used by default.
|
||||
/// </summary>
|
||||
public ICookieManager CookieManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An optional container in which to store the identity across requests. When used, only a session identifier is sent
|
||||
/// to the client. This can be used to mitigate potential problems with very large identities.
|
||||
/// </summary>
|
||||
public ITicketStore SessionStore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Controls how much time the authentication ticket stored in the cookie will remain valid from the point it is created
|
||||
/// The expiration information is stored in the protected cookie ticket. Because of that an expired cookie will be ignored
|
||||
/// even if it is passed to the server after the browser should have purged it.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This is separate from the value of <seealso cref="CookieOptions.Expires"/>, which specifies
|
||||
/// how long the browser will keep the cookie.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public TimeSpan ExpireTimeSpan { get; set; }
|
||||
|
||||
#region Obsolete API
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.Name"/> on <see cref="Cookie"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// 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
|
||||
/// system uses the cookie authentication handler multiple times.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Name) + ".")]
|
||||
public string CookieName { get => Cookie.Name; set => Cookie.Name = value; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.Domain"/> on <see cref="Cookie"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Determines the domain used to create the cookie. Is not provided by default.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Domain) + ".")]
|
||||
public string CookieDomain { get => Cookie.Domain; set => Cookie.Domain = value; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.Path"/> on <see cref="Cookie"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Determines the path used to create the cookie. The default value is "/" for highest browser compatibility.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Path) + ".")]
|
||||
public string CookiePath { get => Cookie.Path; set => Cookie.Path = value; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.HttpOnly"/> on <see cref="Cookie"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Determines if the browser should allow the cookie to be accessed by client-side javascript. The
|
||||
/// default is true, which means the cookie will only be passed to http requests and is not made available
|
||||
/// to script on the page.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.HttpOnly) + ".")]
|
||||
public bool CookieHttpOnly { get => Cookie.HttpOnly; set => Cookie.HttpOnly = value; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.SecurePolicy"/> on <see cref="Cookie"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Determines if the cookie should only be transmitted on HTTPS request. The default is to limit the cookie
|
||||
/// to HTTPS requests if the page which is doing the SignIn is also HTTPS. If you have an HTTPS sign in page
|
||||
/// and portions of your site are HTTP you may need to change this value.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.SecurePolicy) + ".")]
|
||||
public CookieSecurePolicy CookieSecure { get => Cookie.SecurePolicy; set => Cookie.SecurePolicy = value; }
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
public static class CookieExtensions
|
||||
{
|
||||
public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder)
|
||||
=> builder.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
|
||||
public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, string authenticationScheme)
|
||||
=> builder.AddCookie(authenticationScheme, configureOptions: null);
|
||||
|
||||
public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, Action<CookieAuthenticationOptions> configureOptions)
|
||||
=> builder.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, configureOptions);
|
||||
|
||||
public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, string authenticationScheme, Action<CookieAuthenticationOptions> configureOptions)
|
||||
=> builder.AddCookie(authenticationScheme, displayName: null, configureOptions: configureOptions);
|
||||
|
||||
public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<CookieAuthenticationOptions> configureOptions)
|
||||
{
|
||||
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<CookieAuthenticationOptions>, PostConfigureCookieAuthenticationOptions>());
|
||||
return builder.AddScheme<CookieAuthenticationOptions, CookieAuthenticationHandler>(authenticationScheme, displayName, configureOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
/// <summary>
|
||||
/// This default implementation of the ICookieAuthenticationEvents may be used if the
|
||||
/// application only needs to override a few of the interface methods. This may be used as a base class
|
||||
/// or may be instantiated directly.
|
||||
/// </summary>
|
||||
public class CookieAuthenticationEvents
|
||||
{
|
||||
/// <summary>
|
||||
/// A delegate assigned to this property will be invoked when the related method is called.
|
||||
/// </summary>
|
||||
public Func<CookieValidatePrincipalContext, Task> OnValidatePrincipal { get; set; } = context => Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// A delegate assigned to this property will be invoked when the related method is called.
|
||||
/// </summary>
|
||||
public Func<CookieSigningInContext, Task> OnSigningIn { get; set; } = context => Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// A delegate assigned to this property will be invoked when the related method is called.
|
||||
/// </summary>
|
||||
public Func<CookieSignedInContext, Task> OnSignedIn { get; set; } = context => Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// A delegate assigned to this property will be invoked when the related method is called.
|
||||
/// </summary>
|
||||
public Func<CookieSigningOutContext, Task> OnSigningOut { get; set; } = context => Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// A delegate assigned to this property will be invoked when the related method is called.
|
||||
/// </summary>
|
||||
public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToLogin { get; set; } = context =>
|
||||
{
|
||||
if (IsAjaxRequest(context.Request))
|
||||
{
|
||||
context.Response.Headers["Location"] = context.RedirectUri;
|
||||
context.Response.StatusCode = 401;
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.Redirect(context.RedirectUri);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A delegate assigned to this property will be invoked when the related method is called.
|
||||
/// </summary>
|
||||
public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToAccessDenied { get; set; } = context =>
|
||||
{
|
||||
if (IsAjaxRequest(context.Request))
|
||||
{
|
||||
context.Response.Headers["Location"] = context.RedirectUri;
|
||||
context.Response.StatusCode = 403;
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.Redirect(context.RedirectUri);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A delegate assigned to this property will be invoked when the related method is called.
|
||||
/// </summary>
|
||||
public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToLogout { get; set; } = context =>
|
||||
{
|
||||
if (IsAjaxRequest(context.Request))
|
||||
{
|
||||
context.Response.Headers["Location"] = context.RedirectUri;
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.Redirect(context.RedirectUri);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A delegate assigned to this property will be invoked when the related method is called.
|
||||
/// </summary>
|
||||
public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToReturnUrl { get; set; } = context =>
|
||||
{
|
||||
if (IsAjaxRequest(context.Request))
|
||||
{
|
||||
context.Response.Headers["Location"] = context.RedirectUri;
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.Redirect(context.RedirectUri);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
private static bool IsAjaxRequest(HttpRequest request)
|
||||
{
|
||||
return string.Equals(request.Query["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal) ||
|
||||
string.Equals(request.Headers["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements the interface method by invoking the related delegate method.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Task ValidatePrincipal(CookieValidatePrincipalContext context) => OnValidatePrincipal(context);
|
||||
|
||||
/// <summary>
|
||||
/// Implements the interface method by invoking the related delegate method.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public virtual Task SigningIn(CookieSigningInContext context) => OnSigningIn(context);
|
||||
|
||||
/// <summary>
|
||||
/// Implements the interface method by invoking the related delegate method.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public virtual Task SignedIn(CookieSignedInContext context) => OnSignedIn(context);
|
||||
|
||||
/// <summary>
|
||||
/// Implements the interface method by invoking the related delegate method.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public virtual Task SigningOut(CookieSigningOutContext context) => OnSigningOut(context);
|
||||
|
||||
/// <summary>
|
||||
/// Implements the interface method by invoking the related delegate method.
|
||||
/// </summary>
|
||||
/// <param name="context">Contains information about the event</param>
|
||||
public virtual Task RedirectToLogout(RedirectContext<CookieAuthenticationOptions> context) => OnRedirectToLogout(context);
|
||||
|
||||
/// <summary>
|
||||
/// Implements the interface method by invoking the related delegate method.
|
||||
/// </summary>
|
||||
/// <param name="context">Contains information about the event</param>
|
||||
public virtual Task RedirectToLogin(RedirectContext<CookieAuthenticationOptions> context) => OnRedirectToLogin(context);
|
||||
|
||||
/// <summary>
|
||||
/// Implements the interface method by invoking the related delegate method.
|
||||
/// </summary>
|
||||
/// <param name="context">Contains information about the event</param>
|
||||
public virtual Task RedirectToReturnUrl(RedirectContext<CookieAuthenticationOptions> context) => OnRedirectToReturnUrl(context);
|
||||
|
||||
/// <summary>
|
||||
/// Implements the interface method by invoking the related delegate method.
|
||||
/// </summary>
|
||||
/// <param name="context">Contains information about the event</param>
|
||||
public virtual Task RedirectToAccessDenied(RedirectContext<CookieAuthenticationOptions> context) => OnRedirectToAccessDenied(context);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
/// <summary>
|
||||
/// Context object passed to the ICookieAuthenticationEvents method SignedIn.
|
||||
/// </summary>
|
||||
public class CookieSignedInContext : PrincipalContext<CookieAuthenticationOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the context object.
|
||||
/// </summary>
|
||||
/// <param name="context">The HTTP request context</param>
|
||||
/// <param name="scheme">The scheme data</param>
|
||||
/// <param name="principal">Initializes Principal property</param>
|
||||
/// <param name="properties">Initializes Properties property</param>
|
||||
/// <param name="options">The handler options</param>
|
||||
public CookieSignedInContext(
|
||||
HttpContext context,
|
||||
AuthenticationScheme scheme,
|
||||
ClaimsPrincipal principal,
|
||||
AuthenticationProperties properties,
|
||||
CookieAuthenticationOptions options)
|
||||
: base(context, scheme, options, properties)
|
||||
{
|
||||
Principal = principal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
/// <summary>
|
||||
/// Context object passed to the <see cref="CookieAuthenticationEvents.SigningIn(CookieSigningInContext)"/>.
|
||||
/// </summary>
|
||||
public class CookieSigningInContext : PrincipalContext<CookieAuthenticationOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the context object.
|
||||
/// </summary>
|
||||
/// <param name="context">The HTTP request context</param>
|
||||
/// <param name="scheme">The scheme data</param>
|
||||
/// <param name="options">The handler options</param>
|
||||
/// <param name="principal">Initializes Principal property</param>
|
||||
/// <param name="properties">The authentication properties.</param>
|
||||
/// <param name="cookieOptions">Initializes options for the authentication cookie.</param>
|
||||
public CookieSigningInContext(
|
||||
HttpContext context,
|
||||
AuthenticationScheme scheme,
|
||||
CookieAuthenticationOptions options,
|
||||
ClaimsPrincipal principal,
|
||||
AuthenticationProperties properties,
|
||||
CookieOptions cookieOptions)
|
||||
: base(context, scheme, options, properties)
|
||||
{
|
||||
CookieOptions = cookieOptions;
|
||||
Principal = principal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The options for creating the outgoing cookie.
|
||||
/// May be replace or altered during the SigningIn call.
|
||||
/// </summary>
|
||||
public CookieOptions CookieOptions { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
/// <summary>
|
||||
/// Context object passed to the <see cref="CookieAuthenticationEvents.SigningOut(CookieSigningOutContext)"/>
|
||||
/// </summary>
|
||||
public class CookieSigningOutContext : PropertiesContext<CookieAuthenticationOptions>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="scheme"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="properties"></param>
|
||||
/// <param name="cookieOptions"></param>
|
||||
public CookieSigningOutContext(
|
||||
HttpContext context,
|
||||
AuthenticationScheme scheme,
|
||||
CookieAuthenticationOptions options,
|
||||
AuthenticationProperties properties,
|
||||
CookieOptions cookieOptions)
|
||||
: base(context, scheme, options, properties)
|
||||
=> CookieOptions = cookieOptions;
|
||||
|
||||
/// <summary>
|
||||
/// The options for creating the outgoing cookie.
|
||||
/// May be replace or altered during the SigningOut call.
|
||||
/// </summary>
|
||||
public CookieOptions CookieOptions { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
/// <summary>
|
||||
/// Context object passed to the CookieAuthenticationEvents ValidatePrincipal method.
|
||||
/// </summary>
|
||||
public class CookieValidatePrincipalContext : PrincipalContext<CookieAuthenticationOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the context object.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="scheme"></param>
|
||||
/// <param name="ticket">Contains the initial values for identity and extra data</param>
|
||||
/// <param name="options"></param>
|
||||
public CookieValidatePrincipalContext(HttpContext context, AuthenticationScheme scheme, CookieAuthenticationOptions options, AuthenticationTicket ticket)
|
||||
: base(context, scheme, options, ticket?.Properties)
|
||||
{
|
||||
if (ticket == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(ticket));
|
||||
}
|
||||
|
||||
Principal = ticket.Principal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If true, the cookie will be renewed
|
||||
/// </summary>
|
||||
public bool ShouldRenew { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called to replace the claims principal. The supplied principal will replace the value of the
|
||||
/// Principal property, which determines the identity of the authenticated request.
|
||||
/// </summary>
|
||||
/// <param name="principal">The <see cref="ClaimsPrincipal"/> used as the replacement</param>
|
||||
public void ReplacePrincipal(ClaimsPrincipal principal) => Principal = principal;
|
||||
|
||||
/// <summary>
|
||||
/// Called to reject the incoming principal. This may be done if the application has determined the
|
||||
/// account is no longer active, and the request should be treated as if it was anonymous.
|
||||
/// </summary>
|
||||
public void RejectPrincipal() => Principal = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
/// <summary>
|
||||
/// This is used by the CookieAuthenticationMiddleware to process request and response cookies.
|
||||
/// It is abstracted from the normal cookie APIs to allow for complex operations like chunking.
|
||||
/// </summary>
|
||||
public interface ICookieManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieve a cookie of the given name from the request.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
string GetRequestCookie(HttpContext context, string key);
|
||||
|
||||
/// <summary>
|
||||
/// Append the given cookie to the response.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="options"></param>
|
||||
void AppendResponseCookie(HttpContext context, string key, string value, CookieOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Append a delete cookie to the response.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="options"></param>
|
||||
void DeleteCookie(HttpContext context, string key, CookieOptions options);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
/// <summary>
|
||||
/// This provides an abstract storage mechanic to preserve identity information on the server
|
||||
/// while only sending a simple identifier key to the client. This is most commonly used to mitigate
|
||||
/// issues with serializing large identities into cookies.
|
||||
/// </summary>
|
||||
public interface ITicketStore
|
||||
{
|
||||
/// <summary>
|
||||
/// Store the identity ticket and return the associated key.
|
||||
/// </summary>
|
||||
/// <param name="ticket">The identity information to store.</param>
|
||||
/// <returns>The key that can be used to retrieve the identity later.</returns>
|
||||
Task<string> StoreAsync(AuthenticationTicket ticket);
|
||||
|
||||
/// <summary>
|
||||
/// Tells the store that the given identity should be updated.
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="ticket"></param>
|
||||
/// <returns></returns>
|
||||
Task RenewAsync(string key, AuthenticationTicket ticket);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an identity from the store for the given key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key associated with the identity.</param>
|
||||
/// <returns>The identity associated with the given key, or if not found.</returns>
|
||||
Task<AuthenticationTicket> RetrieveAsync(string key);
|
||||
|
||||
/// <summary>
|
||||
/// Remove the identity associated with the given key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key associated with the identity.</param>
|
||||
/// <returns></returns>
|
||||
Task RemoveAsync(string key);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Extensions.Logging
|
||||
{
|
||||
internal static class LoggingExtensions
|
||||
{
|
||||
private static Action<ILogger, string, Exception> _authSchemeSignedIn;
|
||||
private static Action<ILogger, string, Exception> _authSchemeSignedOut;
|
||||
|
||||
static LoggingExtensions()
|
||||
{
|
||||
_authSchemeSignedIn = LoggerMessage.Define<string>(
|
||||
eventId: 10,
|
||||
logLevel: LogLevel.Information,
|
||||
formatString: "AuthenticationScheme: {AuthenticationScheme} signed in.");
|
||||
_authSchemeSignedOut = LoggerMessage.Define<string>(
|
||||
eventId: 11,
|
||||
logLevel: LogLevel.Information,
|
||||
formatString: "AuthenticationScheme: {AuthenticationScheme} signed out.");
|
||||
}
|
||||
|
||||
public static void SignedIn(this ILogger logger, string authenticationScheme)
|
||||
{
|
||||
_authSchemeSignedIn(logger, authenticationScheme, null);
|
||||
}
|
||||
|
||||
public static void SignedOut(this ILogger logger, string authenticationScheme)
|
||||
{
|
||||
_authSchemeSignedOut(logger, authenticationScheme, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>ASP.NET Core middleware that enables an application to use cookie based authentication.</Description>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<DefineConstants>$(DefineConstants);SECURITY</DefineConstants>
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<PackageTags>aspnetcore;authentication;security</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\shared\Microsoft.AspNetCore.ChunkingCookieManager.Sources\**\*.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
// 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.DataProtection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to setup defaults for all <see cref="CookieAuthenticationOptions"/>.
|
||||
/// </summary>
|
||||
public class PostConfigureCookieAuthenticationOptions : IPostConfigureOptions<CookieAuthenticationOptions>
|
||||
{
|
||||
private readonly IDataProtectionProvider _dp;
|
||||
|
||||
public PostConfigureCookieAuthenticationOptions(IDataProtectionProvider dataProtection)
|
||||
{
|
||||
_dp = dataProtection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked to post configure a TOptions instance.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the options instance being configured.</param>
|
||||
/// <param name="options">The options instance to configure.</param>
|
||||
public void PostConfigure(string name, CookieAuthenticationOptions options)
|
||||
{
|
||||
options.DataProtectionProvider = options.DataProtectionProvider ?? _dp;
|
||||
|
||||
if (string.IsNullOrEmpty(options.Cookie.Name))
|
||||
{
|
||||
options.Cookie.Name = CookieAuthenticationDefaults.CookiePrefix + name;
|
||||
}
|
||||
if (options.TicketDataFormat == null)
|
||||
{
|
||||
// Note: the purpose for the data protector must remain fixed for interop to work.
|
||||
var dataProtector = options.DataProtectionProvider.CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authentication.Facebook;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods to add Facebook authentication capabilities to an HTTP application pipeline.
|
||||
/// </summary>
|
||||
public static class FacebookAppBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// UseFacebookAuthentication is obsolete. Configure Facebook authentication with AddAuthentication().AddFacebook in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
[Obsolete("UseFacebookAuthentication is obsolete. Configure Facebook authentication with AddAuthentication().AddFacebook in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)]
|
||||
public static IApplicationBuilder UseFacebookAuthentication(this IApplicationBuilder app)
|
||||
{
|
||||
throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UseFacebookAuthentication is obsolete. Configure Facebook authentication with AddAuthentication().AddFacebook in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.
|
||||
/// </summary>
|
||||
/// <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 handler.</param>
|
||||
/// <returns>A reference to this instance after the operation has completed.</returns>
|
||||
[Obsolete("UseFacebookAuthentication is obsolete. Configure Facebook authentication with AddAuthentication().AddFacebook in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)]
|
||||
public static IApplicationBuilder UseFacebookAuthentication(this IApplicationBuilder app, FacebookOptions options)
|
||||
{
|
||||
throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||
{
|
||||
public static class FacebookDefaults
|
||||
{
|
||||
public const string AuthenticationScheme = "Facebook";
|
||||
|
||||
public static readonly string DisplayName = "Facebook";
|
||||
|
||||
public static readonly string AuthorizationEndpoint = "https://www.facebook.com/v2.12/dialog/oauth";
|
||||
|
||||
public static readonly string TokenEndpoint = "https://graph.facebook.com/v2.12/oauth/access_token";
|
||||
|
||||
public static readonly string UserInformationEndpoint = "https://graph.facebook.com/v2.12/me";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Facebook;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
public static class FacebookAuthenticationOptionsExtensions
|
||||
{
|
||||
public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder)
|
||||
=> builder.AddFacebook(FacebookDefaults.AuthenticationScheme, _ => { });
|
||||
|
||||
public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, Action<FacebookOptions> configureOptions)
|
||||
=> builder.AddFacebook(FacebookDefaults.AuthenticationScheme, configureOptions);
|
||||
|
||||
public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, string authenticationScheme, Action<FacebookOptions> configureOptions)
|
||||
=> builder.AddFacebook(authenticationScheme, FacebookDefaults.DisplayName, configureOptions);
|
||||
|
||||
public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<FacebookOptions> configureOptions)
|
||||
=> builder.AddOAuth<FacebookOptions, FacebookHandler>(authenticationScheme, displayName, configureOptions);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Net.Http;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||
{
|
||||
public class FacebookHandler : OAuthHandler<FacebookOptions>
|
||||
{
|
||||
public FacebookHandler(IOptionsMonitor<FacebookOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||
: base(options, logger, encoder, clock)
|
||||
{ }
|
||||
|
||||
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
|
||||
{
|
||||
var endpoint = QueryHelpers.AddQueryString(Options.UserInformationEndpoint, "access_token", tokens.AccessToken);
|
||||
if (Options.SendAppSecretProof)
|
||||
{
|
||||
endpoint = QueryHelpers.AddQueryString(endpoint, "appsecret_proof", GenerateAppSecretProof(tokens.AccessToken));
|
||||
}
|
||||
if (Options.Fields.Count > 0)
|
||||
{
|
||||
endpoint = QueryHelpers.AddQueryString(endpoint, "fields", string.Join(",", Options.Fields));
|
||||
}
|
||||
|
||||
var response = await Backchannel.GetAsync(endpoint, Context.RequestAborted);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new HttpRequestException($"An error occurred when retrieving Facebook user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Facebook Graph API is enabled.");
|
||||
}
|
||||
|
||||
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
|
||||
|
||||
var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload);
|
||||
context.RunClaimActions();
|
||||
|
||||
await Events.CreatingTicket(context);
|
||||
|
||||
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
|
||||
|
||||
}
|
||||
|
||||
private string GenerateAppSecretProof(string accessToken)
|
||||
{
|
||||
using (var algorithm = new HMACSHA256(Encoding.ASCII.GetBytes(Options.AppSecret)))
|
||||
{
|
||||
var hash = algorithm.ComputeHash(Encoding.ASCII.GetBytes(accessToken));
|
||||
var builder = new StringBuilder();
|
||||
for (int i = 0; i < hash.Length; i++)
|
||||
{
|
||||
builder.Append(hash[i].ToString("x2", CultureInfo.InvariantCulture));
|
||||
}
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
protected override string FormatScope(IEnumerable<string> scopes)
|
||||
{
|
||||
// Facebook deviates from the OAuth spec here. They require comma separated instead of space separated.
|
||||
// https://developers.facebook.com/docs/reference/dialogs/oauth
|
||||
// http://tools.ietf.org/html/rfc6749#section-3.3
|
||||
return string.Join(",", scopes);
|
||||
}
|
||||
|
||||
protected override string FormatScope()
|
||||
=> base.FormatScope();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using System.Globalization;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration options for <see cref="FacebookHandler"/>.
|
||||
/// </summary>
|
||||
public class FacebookOptions : OAuthOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="FacebookOptions"/>.
|
||||
/// </summary>
|
||||
public FacebookOptions()
|
||||
{
|
||||
CallbackPath = new PathString("/signin-facebook");
|
||||
SendAppSecretProof = true;
|
||||
AuthorizationEndpoint = FacebookDefaults.AuthorizationEndpoint;
|
||||
TokenEndpoint = FacebookDefaults.TokenEndpoint;
|
||||
UserInformationEndpoint = FacebookDefaults.UserInformationEndpoint;
|
||||
Scope.Add("public_profile");
|
||||
Scope.Add("email");
|
||||
Fields.Add("name");
|
||||
Fields.Add("email");
|
||||
Fields.Add("first_name");
|
||||
Fields.Add("last_name");
|
||||
|
||||
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
|
||||
ClaimActions.MapJsonSubKey("urn:facebook:age_range_min", "age_range", "min");
|
||||
ClaimActions.MapJsonSubKey("urn:facebook:age_range_max", "age_range", "max");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.DateOfBirth, "birthday");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.GivenName, "first_name");
|
||||
ClaimActions.MapJsonKey("urn:facebook:middle_name", "middle_name");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Surname, "last_name");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Gender, "gender");
|
||||
ClaimActions.MapJsonKey("urn:facebook:link", "link");
|
||||
ClaimActions.MapJsonSubKey("urn:facebook:location", "location", "name");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Locality, "locale");
|
||||
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.
|
||||
/// <summary>
|
||||
/// Gets or sets the Facebook-assigned appId.
|
||||
/// </summary>
|
||||
public string AppId
|
||||
{
|
||||
get { return ClientId; }
|
||||
set { ClientId = value; }
|
||||
}
|
||||
|
||||
// Facebook uses a non-standard term for this field.
|
||||
/// <summary>
|
||||
/// Gets or sets the Facebook-assigned app secret.
|
||||
/// </summary>
|
||||
public string AppSecret
|
||||
{
|
||||
get { return ClientSecret; }
|
||||
set { ClientSecret = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the appsecret_proof should be generated and sent with Facebook API calls.
|
||||
/// This is enabled by default.
|
||||
/// </summary>
|
||||
public bool SendAppSecretProof { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of fields to retrieve from the UserInformationEndpoint.
|
||||
/// https://developers.facebook.com/docs/graph-api/reference/user
|
||||
/// </summary>
|
||||
public ICollection<string> Fields { get; } = new HashSet<string>();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>ASP.NET Core middleware that enables an application to support Facebook's OAuth 2.0 authentication workflow.</Description>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<PackageTags>aspnetcore;authentication;security</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
44
src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/Properties/Resources.Designer.cs
generated
Normal file
44
src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/Properties/Resources.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// <auto-generated />
|
||||
namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||
{
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
|
||||
internal static class Resources
|
||||
{
|
||||
private static readonly ResourceManager _resourceManager
|
||||
= new ResourceManager("Microsoft.AspNetCore.Authentication.Facebook.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||
|
||||
/// <summary>
|
||||
/// The '{0}' option must be provided.
|
||||
/// </summary>
|
||||
internal static string Exception_OptionMustBeProvided
|
||||
{
|
||||
get => GetString("Exception_OptionMustBeProvided");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The '{0}' option must be provided.
|
||||
/// </summary>
|
||||
internal static string FormatException_OptionMustBeProvided(object p0)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0);
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
||||
System.Diagnostics.Debug.Assert(value != null);
|
||||
|
||||
if (formatterNames != null)
|
||||
{
|
||||
for (var i = 0; i < formatterNames.Length; i++)
|
||||
{
|
||||
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Exception_OptionMustBeProvided" xml:space="preserve">
|
||||
<value>The '{0}' option must be provided.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,390 @@
|
|||
{
|
||||
"AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Facebook, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
|
||||
"Types": [
|
||||
{
|
||||
"Name": "Microsoft.Extensions.DependencyInjection.FacebookAuthenticationOptionsExtensions",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"Abstract": true,
|
||||
"Static": true,
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "AddFacebook",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "builder",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "AddFacebook",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "builder",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
|
||||
},
|
||||
{
|
||||
"Name": "configureOptions",
|
||||
"Type": "System.Action<Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "AddFacebook",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "builder",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
|
||||
},
|
||||
{
|
||||
"Name": "authenticationScheme",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "configureOptions",
|
||||
"Type": "System.Action<Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "AddFacebook",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "builder",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
|
||||
},
|
||||
{
|
||||
"Name": "authenticationScheme",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "displayName",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "configureOptions",
|
||||
"Type": "System.Action<Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Authentication.Facebook.FacebookDefaults",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"Abstract": true,
|
||||
"Static": true,
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "DisplayName",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "AuthorizationEndpoint",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "TokenEndpoint",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "UserInformationEndpoint",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "AuthenticationScheme",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": [],
|
||||
"Constant": true,
|
||||
"Literal": "\"Facebook\""
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Authentication.Facebook.FacebookHandler",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler<Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions>",
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "CreateTicketAsync",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "identity",
|
||||
"Type": "System.Security.Claims.ClaimsIdentity"
|
||||
},
|
||||
{
|
||||
"Name": "properties",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties"
|
||||
},
|
||||
{
|
||||
"Name": "tokens",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Threading.Tasks.Task<Microsoft.AspNetCore.Authentication.AuthenticationTicket>",
|
||||
"Virtual": true,
|
||||
"Override": true,
|
||||
"Visibility": "Protected",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "FormatScope",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "scopes",
|
||||
"Type": "System.Collections.Generic.IEnumerable<System.String>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.String",
|
||||
"Virtual": true,
|
||||
"Override": true,
|
||||
"Visibility": "Protected",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "FormatScope",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Virtual": true,
|
||||
"Override": true,
|
||||
"Visibility": "Protected",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "options",
|
||||
"Type": "Microsoft.Extensions.Options.IOptionsMonitor<Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions>"
|
||||
},
|
||||
{
|
||||
"Name": "logger",
|
||||
"Type": "Microsoft.Extensions.Logging.ILoggerFactory"
|
||||
},
|
||||
{
|
||||
"Name": "encoder",
|
||||
"Type": "System.Text.Encodings.Web.UrlEncoder"
|
||||
},
|
||||
{
|
||||
"Name": "clock",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.ISystemClock"
|
||||
}
|
||||
],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions",
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Validate",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.Void",
|
||||
"Virtual": true,
|
||||
"Override": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_AppId",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_AppId",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_AppSecret",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_AppSecret",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_SendAppSecretProof",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.Boolean",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_SendAppSecretProof",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.Boolean"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Fields",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.Collections.Generic.ICollection<System.String>",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Builder.FacebookAppBuilderExtensions",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"Abstract": true,
|
||||
"Static": true,
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "UseFacebookAuthentication",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "app",
|
||||
"Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "UseFacebookAuthentication",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "app",
|
||||
"Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder"
|
||||
},
|
||||
{
|
||||
"Name": "options",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authentication.Google;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods to add Google authentication capabilities to an HTTP application pipeline.
|
||||
/// </summary>
|
||||
public static class GoogleAppBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// UseGoogleAuthentication is obsolete. Configure Google authentication with AddAuthentication().AddGoogle in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
[Obsolete("UseGoogleAuthentication is obsolete. Configure Google authentication with AddAuthentication().AddGoogle in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)]
|
||||
public static IApplicationBuilder UseGoogleAuthentication(this IApplicationBuilder app)
|
||||
{
|
||||
throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UseGoogleAuthentication is obsolete. Configure Google authentication with AddAuthentication().AddGoogle in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.
|
||||
/// </summary>
|
||||
/// <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 handler.</param>
|
||||
/// <returns>A reference to this instance after the operation has completed.</returns>
|
||||
[Obsolete("UseGoogleAuthentication is obsolete. Configure Google authentication with AddAuthentication().AddGoogle in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)]
|
||||
public static IApplicationBuilder UseGoogleAuthentication(this IApplicationBuilder app, GoogleOptions options)
|
||||
{
|
||||
throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Google
|
||||
{
|
||||
public class GoogleChallengeProperties : OAuthChallengeProperties
|
||||
{
|
||||
/// <summary>
|
||||
/// The parameter key for the "access_type" argument being used for a challenge request.
|
||||
/// </summary>
|
||||
public static readonly string AccessTypeKey = "access_type";
|
||||
|
||||
/// <summary>
|
||||
/// The parameter key for the "approval_prompt" argument being used for a challenge request.
|
||||
/// </summary>
|
||||
public static readonly string ApprovalPromptKey = "approval_prompt";
|
||||
|
||||
/// <summary>
|
||||
/// The parameter key for the "include_granted_scopes" argument being used for a challenge request.
|
||||
/// </summary>
|
||||
public static readonly string IncludeGrantedScopesKey = "include_granted_scopes";
|
||||
|
||||
/// <summary>
|
||||
/// The parameter key for the "login_hint" argument being used for a challenge request.
|
||||
/// </summary>
|
||||
public static readonly string LoginHintKey = "login_hint";
|
||||
|
||||
/// <summary>
|
||||
/// The parameter key for the "prompt" argument being used for a challenge request.
|
||||
/// </summary>
|
||||
public static readonly string PromptParameterKey = "prompt";
|
||||
|
||||
public GoogleChallengeProperties()
|
||||
{ }
|
||||
|
||||
public GoogleChallengeProperties(IDictionary<string, string> items)
|
||||
: base(items)
|
||||
{ }
|
||||
|
||||
public GoogleChallengeProperties(IDictionary<string, string> items, IDictionary<string, object> parameters)
|
||||
: base(items, parameters)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// The "access_type" parameter value being used for a challenge request.
|
||||
/// </summary>
|
||||
public string AccessType
|
||||
{
|
||||
get => GetParameter<string>(AccessTypeKey);
|
||||
set => SetParameter(AccessTypeKey, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The "approval_prompt" parameter value being used for a challenge request.
|
||||
/// </summary>
|
||||
public string ApprovalPrompt
|
||||
{
|
||||
get => GetParameter<string>(ApprovalPromptKey);
|
||||
set => SetParameter(ApprovalPromptKey, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The "include_granted_scopes" parameter value being used for a challenge request.
|
||||
/// </summary>
|
||||
public bool? IncludeGrantedScopes
|
||||
{
|
||||
get => GetParameter<bool?>(IncludeGrantedScopesKey);
|
||||
set => SetParameter(IncludeGrantedScopesKey, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The "login_hint" parameter value being used for a challenge request.
|
||||
/// </summary>
|
||||
public string LoginHint
|
||||
{
|
||||
get => GetParameter<string>(LoginHintKey);
|
||||
set => SetParameter(LoginHintKey, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The "prompt" parameter value being used for a challenge request.
|
||||
/// </summary>
|
||||
public string Prompt
|
||||
{
|
||||
get => GetParameter<string>(PromptParameterKey);
|
||||
set => SetParameter(PromptParameterKey, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Google
|
||||
{
|
||||
/// <summary>
|
||||
/// Default values for Google authentication
|
||||
/// </summary>
|
||||
public static class GoogleDefaults
|
||||
{
|
||||
public const string AuthenticationScheme = "Google";
|
||||
|
||||
public static readonly string DisplayName = "Google";
|
||||
|
||||
public static readonly string AuthorizationEndpoint = "https://accounts.google.com/o/oauth2/v2/auth";
|
||||
|
||||
public static readonly string TokenEndpoint = "https://www.googleapis.com/oauth2/v4/token";
|
||||
|
||||
public static readonly string UserInformationEndpoint = "https://www.googleapis.com/plus/v1/people/me";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Google;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
public static class GoogleExtensions
|
||||
{
|
||||
public static AuthenticationBuilder AddGoogle(this AuthenticationBuilder builder)
|
||||
=> builder.AddGoogle(GoogleDefaults.AuthenticationScheme, _ => { });
|
||||
|
||||
public static AuthenticationBuilder AddGoogle(this AuthenticationBuilder builder, Action<GoogleOptions> configureOptions)
|
||||
=> builder.AddGoogle(GoogleDefaults.AuthenticationScheme, configureOptions);
|
||||
|
||||
public static AuthenticationBuilder AddGoogle(this AuthenticationBuilder builder, string authenticationScheme, Action<GoogleOptions> configureOptions)
|
||||
=> builder.AddGoogle(authenticationScheme, GoogleDefaults.DisplayName, configureOptions);
|
||||
|
||||
public static AuthenticationBuilder AddGoogle(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<GoogleOptions> configureOptions)
|
||||
=> builder.AddOAuth<GoogleOptions, GoogleHandler>(authenticationScheme, displayName, configureOptions);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Google
|
||||
{
|
||||
public class GoogleHandler : OAuthHandler<GoogleOptions>
|
||||
{
|
||||
public GoogleHandler(IOptionsMonitor<GoogleOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||
: base(options, logger, encoder, clock)
|
||||
{ }
|
||||
|
||||
protected override async Task<AuthenticationTicket> CreateTicketAsync(
|
||||
ClaimsIdentity identity,
|
||||
AuthenticationProperties properties,
|
||||
OAuthTokenResponse tokens)
|
||||
{
|
||||
// Get the Google user
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint);
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
|
||||
|
||||
var response = await Backchannel.SendAsync(request, Context.RequestAborted);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new HttpRequestException($"An error occurred when retrieving Google user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Google+ API is enabled.");
|
||||
}
|
||||
|
||||
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
|
||||
|
||||
var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload);
|
||||
context.RunClaimActions();
|
||||
|
||||
await Events.CreatingTicket(context);
|
||||
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
|
||||
}
|
||||
|
||||
// TODO: Abstract this properties override pattern into the base class?
|
||||
protected override string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
|
||||
{
|
||||
// Google Identity Platform Manual:
|
||||
// https://developers.google.com/identity/protocols/OAuth2WebServer
|
||||
|
||||
var queryStrings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
queryStrings.Add("response_type", "code");
|
||||
queryStrings.Add("client_id", Options.ClientId);
|
||||
queryStrings.Add("redirect_uri", redirectUri);
|
||||
|
||||
AddQueryString(queryStrings, properties, GoogleChallengeProperties.ScopeKey, FormatScope, Options.Scope);
|
||||
AddQueryString(queryStrings, properties, GoogleChallengeProperties.AccessTypeKey, Options.AccessType);
|
||||
AddQueryString(queryStrings, properties, GoogleChallengeProperties.ApprovalPromptKey);
|
||||
AddQueryString(queryStrings, properties, GoogleChallengeProperties.PromptParameterKey);
|
||||
AddQueryString(queryStrings, properties, GoogleChallengeProperties.LoginHintKey);
|
||||
AddQueryString(queryStrings, properties, GoogleChallengeProperties.IncludeGrantedScopesKey, v => v?.ToString().ToLower(), (bool?)null);
|
||||
|
||||
var state = Options.StateDataFormat.Protect(properties);
|
||||
queryStrings.Add("state", state);
|
||||
|
||||
var authorizationEndpoint = QueryHelpers.AddQueryString(Options.AuthorizationEndpoint, queryStrings);
|
||||
return authorizationEndpoint;
|
||||
}
|
||||
|
||||
private void AddQueryString<T>(
|
||||
IDictionary<string, string> queryStrings,
|
||||
AuthenticationProperties properties,
|
||||
string name,
|
||||
Func<T, string> formatter,
|
||||
T defaultValue)
|
||||
{
|
||||
string value = null;
|
||||
var parameterValue = properties.GetParameter<T>(name);
|
||||
if (parameterValue != null)
|
||||
{
|
||||
value = formatter(parameterValue);
|
||||
}
|
||||
else if (!properties.Items.TryGetValue(name, out value))
|
||||
{
|
||||
value = formatter(defaultValue);
|
||||
}
|
||||
|
||||
// Remove the parameter from AuthenticationProperties so it won't be serialized into the state
|
||||
properties.Items.Remove(name);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
queryStrings[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddQueryString(
|
||||
IDictionary<string, string> queryStrings,
|
||||
AuthenticationProperties properties,
|
||||
string name,
|
||||
string defaultValue = null)
|
||||
=> AddQueryString(queryStrings, properties, name, x => x, defaultValue);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Google
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains static methods that allow to extract user's information from a <see cref="JObject"/>
|
||||
/// instance retrieved from Google after a successful authentication process.
|
||||
/// </summary>
|
||||
public static class GoogleHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the user's email.
|
||||
/// </summary>
|
||||
public static string GetEmail(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return TryGetFirstValue(user, "emails", "value");
|
||||
}
|
||||
|
||||
// Get the given subProperty from a list property.
|
||||
private static string TryGetFirstValue(JObject user, string propertyName, string subProperty)
|
||||
{
|
||||
JToken value;
|
||||
if (user.TryGetValue(propertyName, out value))
|
||||
{
|
||||
var array = JArray.Parse(value.ToString());
|
||||
if (array != null && array.Count > 0)
|
||||
{
|
||||
var subObject = JObject.Parse(array.First.ToString());
|
||||
if (subObject != null)
|
||||
{
|
||||
if (subObject.TryGetValue(subProperty, out value))
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Google
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration options for <see cref="GoogleHandler"/>.
|
||||
/// </summary>
|
||||
public class GoogleOptions : OAuthOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="GoogleOptions"/>.
|
||||
/// </summary>
|
||||
public GoogleOptions()
|
||||
{
|
||||
CallbackPath = new PathString("/signin-google");
|
||||
AuthorizationEndpoint = GoogleDefaults.AuthorizationEndpoint;
|
||||
TokenEndpoint = GoogleDefaults.TokenEndpoint;
|
||||
UserInformationEndpoint = GoogleDefaults.UserInformationEndpoint;
|
||||
Scope.Add("openid");
|
||||
Scope.Add("profile");
|
||||
Scope.Add("email");
|
||||
|
||||
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Name, "displayName");
|
||||
ClaimActions.MapJsonSubKey(ClaimTypes.GivenName, "name", "givenName");
|
||||
ClaimActions.MapJsonSubKey(ClaimTypes.Surname, "name", "familyName");
|
||||
ClaimActions.MapJsonKey("urn:google:profile", "url");
|
||||
ClaimActions.MapCustomJson(ClaimTypes.Email, GoogleHelper.GetEmail);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// access_type. Set to 'offline' to request a refresh token.
|
||||
/// </summary>
|
||||
public string AccessType { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>ASP.NET Core contains middleware to support Google's OpenId and OAuth 2.0 authentication workflows.</Description>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<PackageTags>aspnetcore;authentication;security</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
58
src/Security/src/Microsoft.AspNetCore.Authentication.Google/Properties/Resources.Designer.cs
generated
Normal file
58
src/Security/src/Microsoft.AspNetCore.Authentication.Google/Properties/Resources.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// <auto-generated />
|
||||
namespace Microsoft.AspNetCore.Authentication.Google
|
||||
{
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
|
||||
internal static class Resources
|
||||
{
|
||||
private static readonly ResourceManager _resourceManager
|
||||
= new ResourceManager("Microsoft.AspNetCore.Authentication.Google.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||
|
||||
/// <summary>
|
||||
/// The '{0}' option must be provided.
|
||||
/// </summary>
|
||||
internal static string Exception_OptionMustBeProvided
|
||||
{
|
||||
get => GetString("Exception_OptionMustBeProvided");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The '{0}' option must be provided.
|
||||
/// </summary>
|
||||
internal static string FormatException_OptionMustBeProvided(object p0)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0);
|
||||
|
||||
/// <summary>
|
||||
/// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler.
|
||||
/// </summary>
|
||||
internal static string Exception_ValidatorHandlerMismatch
|
||||
{
|
||||
get => GetString("Exception_ValidatorHandlerMismatch");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler.
|
||||
/// </summary>
|
||||
internal static string FormatException_ValidatorHandlerMismatch()
|
||||
=> GetString("Exception_ValidatorHandlerMismatch");
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
||||
System.Diagnostics.Debug.Assert(value != null);
|
||||
|
||||
if (formatterNames != null)
|
||||
{
|
||||
for (var i = 0; i < formatterNames.Length; i++)
|
||||
{
|
||||
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Exception_OptionMustBeProvided" xml:space="preserve">
|
||||
<value>The '{0}' option must be provided.</value>
|
||||
</data>
|
||||
<data name="Exception_ValidatorHandlerMismatch" xml:space="preserve">
|
||||
<value>An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,550 @@
|
|||
{
|
||||
"AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Google, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
|
||||
"Types": [
|
||||
{
|
||||
"Name": "Microsoft.Extensions.DependencyInjection.GoogleExtensions",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"Abstract": true,
|
||||
"Static": true,
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "AddGoogle",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "builder",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "AddGoogle",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "builder",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
|
||||
},
|
||||
{
|
||||
"Name": "configureOptions",
|
||||
"Type": "System.Action<Microsoft.AspNetCore.Authentication.Google.GoogleOptions>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "AddGoogle",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "builder",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
|
||||
},
|
||||
{
|
||||
"Name": "authenticationScheme",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "configureOptions",
|
||||
"Type": "System.Action<Microsoft.AspNetCore.Authentication.Google.GoogleOptions>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "AddGoogle",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "builder",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
|
||||
},
|
||||
{
|
||||
"Name": "authenticationScheme",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "displayName",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "configureOptions",
|
||||
"Type": "System.Action<Microsoft.AspNetCore.Authentication.Google.GoogleOptions>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Authentication.Google.GoogleChallengeProperties",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthChallengeProperties",
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_AccessType",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_AccessType",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_ApprovalPrompt",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_ApprovalPrompt",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_IncludeGrantedScopes",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.Nullable<System.Boolean>",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_IncludeGrantedScopes",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.Nullable<System.Boolean>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_LoginHint",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_LoginHint",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Prompt",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_Prompt",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "items",
|
||||
"Type": "System.Collections.Generic.IDictionary<System.String, System.String>"
|
||||
}
|
||||
],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "items",
|
||||
"Type": "System.Collections.Generic.IDictionary<System.String, System.String>"
|
||||
},
|
||||
{
|
||||
"Name": "parameters",
|
||||
"Type": "System.Collections.Generic.IDictionary<System.String, System.Object>"
|
||||
}
|
||||
],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "AccessTypeKey",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "ApprovalPromptKey",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "IncludeGrantedScopesKey",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "LoginHintKey",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "PromptParameterKey",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Authentication.Google.GoogleDefaults",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"Abstract": true,
|
||||
"Static": true,
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "DisplayName",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "AuthorizationEndpoint",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "TokenEndpoint",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "UserInformationEndpoint",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "AuthenticationScheme",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": [],
|
||||
"Constant": true,
|
||||
"Literal": "\"Google\""
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Authentication.Google.GoogleHandler",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler<Microsoft.AspNetCore.Authentication.Google.GoogleOptions>",
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "CreateTicketAsync",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "identity",
|
||||
"Type": "System.Security.Claims.ClaimsIdentity"
|
||||
},
|
||||
{
|
||||
"Name": "properties",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties"
|
||||
},
|
||||
{
|
||||
"Name": "tokens",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Threading.Tasks.Task<Microsoft.AspNetCore.Authentication.AuthenticationTicket>",
|
||||
"Virtual": true,
|
||||
"Override": true,
|
||||
"Visibility": "Protected",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "BuildChallengeUrl",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "properties",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties"
|
||||
},
|
||||
{
|
||||
"Name": "redirectUri",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.String",
|
||||
"Virtual": true,
|
||||
"Override": true,
|
||||
"Visibility": "Protected",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "options",
|
||||
"Type": "Microsoft.Extensions.Options.IOptionsMonitor<Microsoft.AspNetCore.Authentication.Google.GoogleOptions>"
|
||||
},
|
||||
{
|
||||
"Name": "logger",
|
||||
"Type": "Microsoft.Extensions.Logging.ILoggerFactory"
|
||||
},
|
||||
{
|
||||
"Name": "encoder",
|
||||
"Type": "System.Text.Encodings.Web.UrlEncoder"
|
||||
},
|
||||
{
|
||||
"Name": "clock",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.ISystemClock"
|
||||
}
|
||||
],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Authentication.Google.GoogleHelper",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"Abstract": true,
|
||||
"Static": true,
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "GetEmail",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "user",
|
||||
"Type": "Newtonsoft.Json.Linq.JObject"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Authentication.Google.GoogleOptions",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions",
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_AccessType",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_AccessType",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Builder.GoogleAppBuilderExtensions",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"Abstract": true,
|
||||
"Static": true,
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "UseGoogleAuthentication",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "app",
|
||||
"Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "UseGoogleAuthentication",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "app",
|
||||
"Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder"
|
||||
},
|
||||
{
|
||||
"Name": "options",
|
||||
"Type": "Microsoft.AspNetCore.Authentication.Google.GoogleOptions"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
}
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue