diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 000000000..d45bd5a1f --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,17 @@ +init: +- git config --global core.autocrlf true +branches: + only: + - master + - /^release\/.*$/ + - /^(.*\/)?ci-.*$/ +build_script: +- ps: .\run.ps1 default-build +clone_depth: 1 +environment: + global: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: 1 +test: 'off' +deploy: 'off' +os: Visual Studio 2017 diff --git a/.gitignore b/.gitignore index 0f91ad120..3d7e16e84 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,6 @@ project.lock.json .build/ .testPublish/ /.vs/ +.vscode/ +global.json +BenchmarkDotNet.Artifacts/ diff --git a/.travis.yml b/.travis.yml index a0be88689..ab3980055 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,32 +1,27 @@ language: csharp -sudo: required +sudo: false dist: trusty +env: + global: + - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + - DOTNET_CLI_TELEMETRY_OPTOUT: 1 +mono: none +os: +- linux +- osx +osx_image: xcode8.2 addons: apt: packages: - - gettext - - libcurl4-openssl-dev - - libicu-dev - - libssl-dev - libunwind8 - - zlib1g -env: - global: - - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - - DOTNET_CLI_TELEMETRY_OPTOUT: 1 -mono: - - 4.0.5 -os: - - linux - - osx -osx_image: xcode7.3 branches: only: - - master - - release - - dev - - /^(.*\/)?ci-.*$/ + - master + - /^release\/.*$/ + - /^(.*\/)?ci-.*$/ before_install: - - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi +- if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s + /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib + /usr/local/lib/; fi script: - - ./build.sh --quiet verify +- ./build.sh diff --git a/.vsts-pipelines/builds/ci-internal.yml b/.vsts-pipelines/builds/ci-internal.yml new file mode 100644 index 000000000..c2c5336fd --- /dev/null +++ b/.vsts-pipelines/builds/ci-internal.yml @@ -0,0 +1,13 @@ +trigger: +- master +- release/* + +resources: + repositories: + - repository: buildtools + type: git + name: aspnet-BuildTools + ref: refs/heads/master + +phases: +- template: .vsts-pipelines/templates/project-ci.yml@buildtools diff --git a/.vsts-pipelines/builds/ci-public.yml b/.vsts-pipelines/builds/ci-public.yml new file mode 100644 index 000000000..507c89b02 --- /dev/null +++ b/.vsts-pipelines/builds/ci-public.yml @@ -0,0 +1,15 @@ +trigger: +- master +- release/* + +# See https://github.com/aspnet/BuildTools +resources: + repositories: + - repository: buildtools + type: github + endpoint: DotNet-Bot GitHub Connection + name: aspnet/BuildTools + ref: refs/heads/master + +phases: +- template: .vsts-pipelines/templates/project-ci.yml@buildtools diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 64ff041d5..eac4268e4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ Contributing ====== -Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo. +Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/master/CONTRIBUTING.md) in the Home repo. diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 000000000..eb9d9535e --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,19 @@ + + + + + + + + + Microsoft ASP.NET Core + https://github.com/aspnet/Security + git + $(MSBuildThisFileDirectory) + $(MSBuildThisFileDirectory)build\Key.snk + true + true + + diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 000000000..7e3f8df92 --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,6 @@ + + + $(MicrosoftNETCoreAppPackageVersion) + $(NETStandardLibrary20PackageVersion) + + diff --git a/LICENSE.txt b/LICENSE.txt index 0bdc1962b..b3b180cd5 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,12 +1,201 @@ -Copyright (c) .NET Foundation. All rights reserved. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -these files except in compliance with the License. You may obtain a copy of the -License at + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -http://www.apache.org/licenses/LICENSE-2.0 + 1. Definitions. -Unless required by applicable law or agreed to in writing, software distributed -under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) .NET Foundation and Contributors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NuGet.config b/NuGet.config index 0fd623ffd..e32bddfd5 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@  - - + + diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index 348835e2d..974eb365c 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -1,13 +1,13 @@ { - "adx-nonshipping": { - "rules": [], - "packages": { - "Microsoft.AspNetCore.ChunkingCookieManager.Sources": { } - } - }, - "Default": { // Rules to run for packages not listed in any other set. - "rules": [ - "DefaultCompositeRule" - ] + "adx-nonshipping": { + "rules": [], + "packages": { + "Microsoft.AspNetCore.ChunkingCookieManager.Sources": {} } + }, + "Default": { + "rules": [ + "DefaultCompositeRule" + ] + } } \ No newline at end of file diff --git a/README.md b/README.md index ab822bd68..66c2aa45e 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ -ASP.NET Security -======== +ASP.NET Security [Archived] +=========================== -AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/fujhh8n956v5ohfd/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/Security/branch/dev) - -Travis: [![Travis](https://travis-ci.org/aspnet/Security.svg?branch=dev)](https://travis-ci.org/aspnet/Security) +**This GitHub project has been archived.** Ongoing development on this project can be found in . 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. +This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [AspNetCore](https://github.com/aspnet/AspNetCore) repo. diff --git a/Security.sln b/Security.sln index c84ec1bd9..240100e8c 100644 --- a/Security.sln +++ b/Security.sln @@ -1,73 +1,97 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 +# 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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CookieSample", "samples\CookieSample\CookieSample.xproj", "{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}" +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}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C40A5A3B-ABA3-4819-9C44-D821E6DA1BA1}" ProjectSection(SolutionItems) = preProject - global.json = global.json + test\Directory.Build.props = test\Directory.Build.props EndProjectSection EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SocialSample", "samples\SocialSample\SocialSample.xproj", "{8C73D216-332D-41D8-BFD0-45BC4BC36552}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CookieSessionSample", "samples\CookieSessionSample\CookieSessionSample.xproj", "{19711880-46DA-4A26-9E0F-9B2E41D27651}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication", "src\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.csproj", "{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "OpenIdConnectSample", "samples\OpenIdConnectSample\OpenIdConnectSample.xproj", "{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Authentication.Cookies", "src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.xproj", "{FC152CC4-054B-457E-8D91-389C5DE3C561}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Authentication", "src\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.xproj", "{2286250A-52C8-4126-9F93-B1E45F0AD078}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Authentication.Facebook", "src\Microsoft.AspNetCore.Authentication.Facebook\Microsoft.AspNetCore.Authentication.Facebook.xproj", "{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Authentication.Google", "src\Microsoft.AspNetCore.Authentication.Google\Microsoft.AspNetCore.Authentication.Google.xproj", "{76579C39-B829-490D-B8BE-1BD35FE8412E}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Authentication.OpenIdConnect", "src\Microsoft.AspNetCore.Authentication.OpenIdConnect\Microsoft.AspNetCore.Authentication.OpenIdConnect.xproj", "{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Authentication.MicrosoftAccount", "src\Microsoft.AspNetCore.Authentication.MicrosoftAccount\Microsoft.AspNetCore.Authentication.MicrosoftAccount.xproj", "{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Authentication.Twitter", "src\Microsoft.AspNetCore.Authentication.Twitter\Microsoft.AspNetCore.Authentication.Twitter.xproj", "{0330FFF6-B4B5-42DD-8C99-26A789569000}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Authentication.OAuth", "src\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.xproj", "{1657C79E-7755-4AEE-9D61-571295B69A30}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authorization", "src\Microsoft.AspNetCore.Authorization\Microsoft.AspNetCore.Authorization.csproj", "{6AB3E514-5894-4131-9399-DC7D5284ADDB}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Authentication.Test", "test\Microsoft.AspNetCore.Authentication.Test\Microsoft.AspNetCore.Authentication.Test.xproj", "{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.CookiePolicy", "src\Microsoft.AspNetCore.CookiePolicy\Microsoft.AspNetCore.CookiePolicy.csproj", "{86183DC3-02A8-4A68-8B60-71ECEC066E79}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Authorization.Test", "test\Microsoft.AspNetCore.Authorization.Test\Microsoft.AspNetCore.Authorization.Test.xproj", "{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Authorization", "src\Microsoft.AspNetCore.Authorization\Microsoft.AspNetCore.Authorization.xproj", "{6AB3E514-5894-4131-9399-DC7D5284ADDB}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.CookiePolicy", "src\Microsoft.AspNetCore.CookiePolicy\Microsoft.AspNetCore.CookiePolicy.xproj", "{86183DC3-02A8-4A68-8B60-71ECEC066E79}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JwtBearerSample", "samples\JwtBearerSample\JwtBearerSample.csproj", "{D399B84F-591B-4E98-92BA-B0F63E7B6957}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.CookiePolicy.Test", "test\Microsoft.AspNetCore.CookiePolicy.Test\Microsoft.AspNetCore.CookiePolicy.Test.xproj", "{1790E052-646F-4529-B90E-6FEA95520D69}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Authentication.JwtBearer", "src\Microsoft.AspNetCore.Authentication.JwtBearer\Microsoft.AspNetCore.Authentication.JwtBearer.xproj", "{2755BFE5-7421-4A31-A644-F817DF5CAA98}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "JwtBearerSample", "samples\JwtBearerSample\JwtBearerSample.xproj", "{D399B84F-591B-4E98-92BA-B0F63E7B6957}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIdConnect.AzureAdSample", "samples\OpenIdConnect.AzureAdSample\OpenIdConnect.AzureAdSample.csproj", "{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Owin.Security.Interop", "src\Microsoft.Owin.Security.Interop\Microsoft.Owin.Security.Interop.xproj", "{A7922DD8-09F1-43E4-938B-CC523EA08898}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Owin.Security.Interop.Test", "test\Microsoft.Owin.Security.Interop.Test\Microsoft.Owin.Security.Interop.Test.xproj", "{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "OpenIdConnect.AzureAdSample", "samples\OpenIdConnect.AzureAdSample\OpenIdConnect.AzureAdSample.xproj", "{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CookiePolicySample", "samples\CookiePolicySample\CookiePolicySample.csproj", "{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.ChunkingCookieManager.Sources", "src\Microsoft.AspNetCore.ChunkingCookieManager.Sources\Microsoft.AspNetCore.ChunkingCookieManager.Sources.xproj", "{2690FBE6-9D27-4C84-B82C-11188B0BCDA3}" +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("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test", "test\Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test\Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.xproj", "{51563775-C659-4907-9BAF-9995BAB87D01}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WsFedSample", "samples\WsFedSample\WsFedSample.csproj", "{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{55052FE3-F8C2-4E6C-97B0-C02ED1DBEA62}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Security.Performance", "benchmarks\Microsoft.AspNetCore.Security.Performance\Microsoft.AspNetCore.Security.Performance.csproj", "{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}" 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 @@ -75,282 +99,444 @@ Global {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 - {2286250A-52C8-4126-9F93-B1E45F0AD078}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2286250A-52C8-4126-9F93-B1E45F0AD078}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2286250A-52C8-4126-9F93-B1E45F0AD078}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {2286250A-52C8-4126-9F93-B1E45F0AD078}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {2286250A-52C8-4126-9F93-B1E45F0AD078}.Debug|x86.ActiveCfg = Debug|Any CPU - {2286250A-52C8-4126-9F93-B1E45F0AD078}.Debug|x86.Build.0 = Debug|Any CPU - {2286250A-52C8-4126-9F93-B1E45F0AD078}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2286250A-52C8-4126-9F93-B1E45F0AD078}.Release|Any CPU.Build.0 = Release|Any CPU - {2286250A-52C8-4126-9F93-B1E45F0AD078}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {2286250A-52C8-4126-9F93-B1E45F0AD078}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {2286250A-52C8-4126-9F93-B1E45F0AD078}.Release|x86.ActiveCfg = Release|Any CPU - {2286250A-52C8-4126-9F93-B1E45F0AD078}.Release|x86.Build.0 = Release|Any CPU + {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 - {2690FBE6-9D27-4C84-B82C-11188B0BCDA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2690FBE6-9D27-4C84-B82C-11188B0BCDA3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2690FBE6-9D27-4C84-B82C-11188B0BCDA3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {2690FBE6-9D27-4C84-B82C-11188B0BCDA3}.Debug|x86.ActiveCfg = Debug|Any CPU - {2690FBE6-9D27-4C84-B82C-11188B0BCDA3}.Debug|x86.Build.0 = Debug|Any CPU - {2690FBE6-9D27-4C84-B82C-11188B0BCDA3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2690FBE6-9D27-4C84-B82C-11188B0BCDA3}.Release|Any CPU.Build.0 = Release|Any CPU - {2690FBE6-9D27-4C84-B82C-11188B0BCDA3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {2690FBE6-9D27-4C84-B82C-11188B0BCDA3}.Release|x86.ActiveCfg = Release|Any CPU - {2690FBE6-9D27-4C84-B82C-11188B0BCDA3}.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 + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|x64.ActiveCfg = Debug|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|x64.Build.0 = Debug|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|x86.ActiveCfg = Debug|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|x86.Build.0 = Debug|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|Any CPU.Build.0 = Release|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|x64.ActiveCfg = Release|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|x64.Build.0 = Release|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|x86.ActiveCfg = Release|Any CPU + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -361,7 +547,7 @@ Global {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} - {2286250A-52C8-4126-9F93-B1E45F0AD078} = {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} @@ -378,7 +564,14 @@ Global {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} - {2690FBE6-9D27-4C84-B82C-11188B0BCDA3} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652} {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} + {556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A} = {55052FE3-F8C2-4E6C-97B0-C02ED1DBEA62} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {ABF8089E-43D0-4010-84A7-7A9DCFE49357} EndGlobalSection EndGlobal diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index b9a9bcd1e..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,13 +0,0 @@ -init: - - git config --global core.autocrlf true -branches: - only: - - master - - release - - dev - - /^(.*\/)?ci-.*$/ -build_script: - - build.cmd verify -clone_depth: 1 -test: off -deploy: off \ No newline at end of file diff --git a/benchmarks/Microsoft.AspNetCore.Security.Performance/AuthorizationMiddlewareBenchmark.cs b/benchmarks/Microsoft.AspNetCore.Security.Performance/AuthorizationMiddlewareBenchmark.cs new file mode 100644 index 000000000..90cb135de --- /dev/null +++ b/benchmarks/Microsoft.AspNetCore.Security.Performance/AuthorizationMiddlewareBenchmark.cs @@ -0,0 +1,53 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Security +{ + public class AuthorizationMiddlewareBenchmark + { + private AuthorizationMiddleware _authorizationMiddleware; + private DefaultHttpContext _httpContextNoEndpoint; + private DefaultHttpContext _httpContextHasEndpoint; + + [GlobalSetup] + public void Setup() + { + var policyProvider = new DefaultAuthorizationPolicyProvider(Options.Create(new AuthorizationOptions())); + _authorizationMiddleware = new AuthorizationMiddleware((context) => Task.CompletedTask, policyProvider); + + _httpContextNoEndpoint = new DefaultHttpContext(); + + var feature = new EndpointFeature + { + Endpoint = new Endpoint((context) => Task.CompletedTask, EndpointMetadataCollection.Empty, "Test endpoint") + }; + _httpContextHasEndpoint = new DefaultHttpContext(); + _httpContextHasEndpoint.Features.Set(feature); + } + + [Benchmark] + public Task Invoke_NoEndpoint_NoAuthorization() + { + return _authorizationMiddleware.Invoke(_httpContextNoEndpoint); + } + + [Benchmark] + public Task Invoke_HasEndpoint_NoAuthorization() + { + return _authorizationMiddleware.Invoke(_httpContextHasEndpoint); + } + + private class EndpointFeature : IEndpointFeature + { + public Endpoint Endpoint { get; set; } + } + } +} diff --git a/benchmarks/Microsoft.AspNetCore.Security.Performance/AuthorizationPolicyBenchmark.cs b/benchmarks/Microsoft.AspNetCore.Security.Performance/AuthorizationPolicyBenchmark.cs new file mode 100644 index 000000000..86afdcd5a --- /dev/null +++ b/benchmarks/Microsoft.AspNetCore.Security.Performance/AuthorizationPolicyBenchmark.cs @@ -0,0 +1,28 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Security +{ + public class AuthorizationPolicyBenchmark + { + private DefaultAuthorizationPolicyProvider _policyProvider; + + [GlobalSetup] + public void Setup() + { + _policyProvider = new DefaultAuthorizationPolicyProvider(Options.Create(new AuthorizationOptions())); + } + + [Benchmark] + public Task CombineAsync() + { + return AuthorizationPolicy.CombineAsync(_policyProvider, Array.Empty()); + } + } +} diff --git a/benchmarks/Microsoft.AspNetCore.Security.Performance/Microsoft.AspNetCore.Security.Performance.csproj b/benchmarks/Microsoft.AspNetCore.Security.Performance/Microsoft.AspNetCore.Security.Performance.csproj new file mode 100644 index 000000000..2f16dd669 --- /dev/null +++ b/benchmarks/Microsoft.AspNetCore.Security.Performance/Microsoft.AspNetCore.Security.Performance.csproj @@ -0,0 +1,24 @@ + + + + netcoreapp3.0 + Exe + true + true + false + Microsoft.AspNetCore.Security + + + + + + + + + + + + + + + diff --git a/benchmarks/Microsoft.AspNetCore.Security.Performance/Properties/AssemblyInfo.cs b/benchmarks/Microsoft.AspNetCore.Security.Performance/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..cfb0b19c2 --- /dev/null +++ b/benchmarks/Microsoft.AspNetCore.Security.Performance/Properties/AssemblyInfo.cs @@ -0,0 +1 @@ +[assembly: BenchmarkDotNet.Attributes.AspNetCoreBenchmark] \ No newline at end of file diff --git a/benchmarks/Microsoft.AspNetCore.Security.Performance/readme.md b/benchmarks/Microsoft.AspNetCore.Security.Performance/readme.md new file mode 100644 index 000000000..cbe60261b --- /dev/null +++ b/benchmarks/Microsoft.AspNetCore.Security.Performance/readme.md @@ -0,0 +1,16 @@ +Compile the solution in Release mode (so binaries are available in release) + +To run a specific benchmark add it as parameter. +``` +dotnet run -c Release --framework +``` + +To run all benchmarks use '*' as the name. +``` +dotnet run -c Release --framework * +``` + +If you run without any parameters, you'll be offered the list of all benchmarks and get to choose. +``` +dotnet run -c Release --framework +``` \ No newline at end of file diff --git a/build.cmd b/build.cmd index 7d4894cb4..c0050bda1 100644 --- a/build.cmd +++ b/build.cmd @@ -1,2 +1,2 @@ @ECHO OFF -PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" \ No newline at end of file +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE" diff --git a/build.ps1 b/build.ps1 deleted file mode 100644 index 8f2f99691..000000000 --- a/build.ps1 +++ /dev/null @@ -1,67 +0,0 @@ -$ErrorActionPreference = "Stop" - -function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) -{ - while($true) - { - try - { - Invoke-WebRequest $url -OutFile $downloadLocation - break - } - catch - { - $exceptionMessage = $_.Exception.Message - Write-Host "Failed to download '$url': $exceptionMessage" - if ($retries -gt 0) { - $retries-- - Write-Host "Waiting 10 seconds before retrying. Retries left: $retries" - Start-Sleep -Seconds 10 - - } - else - { - $exception = $_.Exception - throw $exception - } - } - } -} - -cd $PSScriptRoot - -$repoFolder = $PSScriptRoot -$env:REPO_FOLDER = $repoFolder - -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" -if ($env:KOREBUILD_ZIP) -{ - $koreBuildZip=$env:KOREBUILD_ZIP -} - -$buildFolder = ".build" -$buildFile="$buildFolder\KoreBuild.ps1" - -if (!(Test-Path $buildFolder)) { - Write-Host "Downloading KoreBuild from $koreBuildZip" - - $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() - New-Item -Path "$tempFolder" -Type directory | Out-Null - - $localZipFile="$tempFolder\korebuild.zip" - - DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 - - Add-Type -AssemblyName System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) - - New-Item -Path "$buildFolder" -Type directory | Out-Null - copy-item "$tempFolder\**\build\*" $buildFolder -Recurse - - # Cleanup - if (Test-Path $tempFolder) { - Remove-Item -Recurse -Force $tempFolder - } -} - -&"$buildFile" $args \ No newline at end of file diff --git a/build.sh b/build.sh index 4fd7ede78..98a4b2276 100755 --- a/build.sh +++ b/build.sh @@ -1,46 +1,8 @@ #!/usr/bin/env bash -repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" -if [ ! -z $KOREBUILD_ZIP ]; then - koreBuildZip=$KOREBUILD_ZIP -fi +set -euo pipefail +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -buildFolder=".build" -buildFile="$buildFolder/KoreBuild.sh" - -if test ! -d $buildFolder; then - echo "Downloading KoreBuild from $koreBuildZip" - - tempFolder="/tmp/KoreBuild-$(uuidgen)" - mkdir $tempFolder - - localZipFile="$tempFolder/korebuild.zip" - - retries=6 - until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null) - do - echo "Failed to download '$koreBuildZip'" - if [ "$retries" -le 0 ]; then - exit 1 - fi - retries=$((retries - 1)) - echo "Waiting 10 seconds before retrying. Retries left: $retries" - sleep 10s - done - - unzip -q -d $tempFolder $localZipFile - - mkdir $buildFolder - cp -r $tempFolder/**/build/** $buildFolder - - chmod +x $buildFile - - # Cleanup - if test -d $tempFolder; then - rm -rf $tempFolder - fi -fi - -$buildFile -r $repoFolder "$@" \ No newline at end of file +# Call "sync" between "chmod" and execution to prevent "text file busy" error in Docker (aufs) +chmod +x "$DIR/run.sh"; sync +"$DIR/run.sh" default-build "$@" diff --git a/tools/Key.snk b/build/Key.snk similarity index 100% rename from tools/Key.snk rename to build/Key.snk diff --git a/build/dependencies.props b/build/dependencies.props new file mode 100644 index 000000000..163a3d400 --- /dev/null +++ b/build/dependencies.props @@ -0,0 +1,56 @@ + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + + + 0.10.13 + 3.0.0-build-20181114.5 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-preview-181113-11 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-alpha1-10742 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.0.0-preview-181113-11 + 3.19.8 + 5.3.0 + 5.3.0 + 3.0.0-preview1-26907-05 + 15.6.1 + 3.0.1 + 3.0.1 + 3.0.1 + 4.10.0 + 2.0.3 + 11.0.2 + 5.3.0 + 0.10.0 + 2.3.1 + 2.4.0 + + + + + diff --git a/build/repo.props b/build/repo.props new file mode 100644 index 000000000..4402da1d0 --- /dev/null +++ b/build/repo.props @@ -0,0 +1,13 @@ + + + + + + Internal.AspNetCore.Universe.Lineup + https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json + + + + + + diff --git a/build/sources.props b/build/sources.props new file mode 100644 index 000000000..9215df975 --- /dev/null +++ b/build/sources.props @@ -0,0 +1,17 @@ + + + + + $(DotNetRestoreSources) + + $(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); + https://api.nuget.org/v3/index.json; + + + diff --git a/global.json b/global.json deleted file mode 100644 index 0ad1995dd..000000000 --- a/global.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "projects": [ - "src" - ], - "sdk": { - "version": "1.0.0-preview2-1-003180" - } -} \ No newline at end of file diff --git a/korebuild-lock.txt b/korebuild-lock.txt new file mode 100644 index 000000000..73613543d --- /dev/null +++ b/korebuild-lock.txt @@ -0,0 +1,2 @@ +version:3.0.0-build-20181114.5 +commithash:880e9a204d4ee4a18dfd83c9fb05a192a28bca60 diff --git a/korebuild.json b/korebuild.json new file mode 100644 index 000000000..8a276a7f3 --- /dev/null +++ b/korebuild.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/master/tools/korebuild.schema.json", + "channel": "master" +} diff --git a/run.cmd b/run.cmd new file mode 100644 index 000000000..d52d5c7e6 --- /dev/null +++ b/run.cmd @@ -0,0 +1,2 @@ +@ECHO OFF +PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE" diff --git a/run.ps1 b/run.ps1 new file mode 100644 index 000000000..34604c717 --- /dev/null +++ b/run.ps1 @@ -0,0 +1,209 @@ +#!/usr/bin/env powershell +#requires -version 4 + +<# +.SYNOPSIS +Executes KoreBuild commands. + +.DESCRIPTION +Downloads korebuild if required. Then executes the KoreBuild command. To see available commands, execute with `-Command help`. + +.PARAMETER Command +The KoreBuild command to run. + +.PARAMETER Path +The folder to build. Defaults to the folder containing this script. + +.PARAMETER Channel +The channel of KoreBuild to download. Overrides the value from the config file. + +.PARAMETER DotNetHome +The directory where .NET Core tools will be stored. + +.PARAMETER ToolsSource +The base url where build tools can be downloaded. Overrides the value from the config file. + +.PARAMETER Update +Updates KoreBuild to the latest version even if a lock file is present. + +.PARAMETER Reinstall +Re-installs KoreBuild + +.PARAMETER ConfigFile +The path to the configuration file that stores values. Defaults to korebuild.json. + +.PARAMETER ToolsSourceSuffix +The Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores. + +.PARAMETER CI +Sets up CI specific settings and variables. + +.PARAMETER Arguments +Arguments to be passed to the command + +.NOTES +This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. +When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. + +The $ConfigFile is expected to be an JSON file. It is optional, and the configuration values in it are optional as well. Any options set +in the file are overridden by command line parameters. + +.EXAMPLE +Example config file: +```json +{ + "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/master/tools/korebuild.schema.json", + "channel": "master", + "toolsSource": "https://aspnetcore.blob.core.windows.net/buildtools" +} +``` +#> +[CmdletBinding(PositionalBinding = $false)] +param( + [Parameter(Mandatory = $true, Position = 0)] + [string]$Command, + [string]$Path = $PSScriptRoot, + [Alias('c')] + [string]$Channel, + [Alias('d')] + [string]$DotNetHome, + [Alias('s')] + [string]$ToolsSource, + [Alias('u')] + [switch]$Update, + [switch]$Reinstall, + [string]$ToolsSourceSuffix, + [string]$ConfigFile = $null, + [switch]$CI, + [Parameter(ValueFromRemainingArguments = $true)] + [string[]]$Arguments +) + +Set-StrictMode -Version 2 +$ErrorActionPreference = 'Stop' + +# +# Functions +# + +function Get-KoreBuild { + + $lockFile = Join-Path $Path 'korebuild-lock.txt' + + if (!(Test-Path $lockFile) -or $Update) { + Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile $ToolsSourceSuffix + } + + $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 + if (!$version) { + Write-Error "Failed to parse version from $lockFile. Expected a line that begins with 'version:'" + } + $version = $version.TrimStart('version:').Trim() + $korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version) + + if ($Reinstall -and (Test-Path $korebuildPath)) { + Remove-Item -Force -Recurse $korebuildPath + } + + if (!(Test-Path $korebuildPath)) { + Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version" + New-Item -ItemType Directory -Path $korebuildPath | Out-Null + $remotePath = "$ToolsSource/korebuild/artifacts/$version/korebuild.$version.zip" + + try { + $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" + Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix + if (Get-Command -Name 'Microsoft.PowerShell.Archive\Expand-Archive' -ErrorAction Ignore) { + # Use built-in commands where possible as they are cross-plat compatible + Microsoft.PowerShell.Archive\Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath + } + else { + # Fallback to old approach for old installations of PowerShell + Add-Type -AssemblyName System.IO.Compression.FileSystem + [System.IO.Compression.ZipFile]::ExtractToDirectory($tmpfile, $korebuildPath) + } + } + catch { + Remove-Item -Recurse -Force $korebuildPath -ErrorAction Ignore + throw + } + finally { + Remove-Item $tmpfile -ErrorAction Ignore + } + } + + return $korebuildPath +} + +function Join-Paths([string]$path, [string[]]$childPaths) { + $childPaths | ForEach-Object { $path = Join-Path $path $_ } + return $path +} + +function Get-RemoteFile([string]$RemotePath, [string]$LocalPath, [string]$RemoteSuffix) { + if ($RemotePath -notlike 'http*') { + Copy-Item $RemotePath $LocalPath + return + } + + $retries = 10 + while ($retries -gt 0) { + $retries -= 1 + try { + Invoke-WebRequest -UseBasicParsing -Uri $($RemotePath + $RemoteSuffix) -OutFile $LocalPath + return + } + catch { + Write-Verbose "Request failed. $retries retries remaining" + } + } + + Write-Error "Download failed: '$RemotePath'." +} + +# +# Main +# + +# Load configuration or set defaults + +$Path = Resolve-Path $Path +if (!$ConfigFile) { $ConfigFile = Join-Path $Path 'korebuild.json' } + +if (Test-Path $ConfigFile) { + try { + $config = Get-Content -Raw -Encoding UTF8 -Path $ConfigFile | ConvertFrom-Json + if ($config) { + if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } + if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} + } + } + catch { + Write-Host -ForegroundColor Red $Error[0] + Write-Error "$ConfigFile contains invalid JSON." + exit 1 + } +} + +if (!$DotNetHome) { + $DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } ` + elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} ` + elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}` + else { Join-Path $PSScriptRoot '.dotnet'} +} + +if (!$Channel) { $Channel = 'master' } +if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' } + +# Execute + +$korebuildPath = Get-KoreBuild +Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') + +try { + Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile -CI:$CI + Invoke-KoreBuildCommand $Command @Arguments +} +finally { + Remove-Module 'KoreBuild' -ErrorAction Ignore +} diff --git a/run.sh b/run.sh new file mode 100755 index 000000000..4c1fed564 --- /dev/null +++ b/run.sh @@ -0,0 +1,256 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# +# variables +# + +RESET="\033[0m" +RED="\033[0;31m" +YELLOW="\033[0;33m" +MAGENTA="\033[0;95m" +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" +verbose=false +update=false +reinstall=false +repo_path="$DIR" +channel='' +tools_source='' +tools_source_suffix='' +ci=false + +# +# Functions +# +__usage() { + echo "Usage: $(basename "${BASH_SOURCE[0]}") command [options] [[--] ...]" + echo "" + echo "Arguments:" + echo " command The command to be run." + echo " ... Arguments passed to the command. Variable number of arguments allowed." + echo "" + echo "Options:" + echo " --verbose Show verbose output." + echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." + echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." + echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." + echo " --path The directory to build. Defaults to the directory containing the script." + echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." + echo " --tools-source-suffix|-ToolsSourceSuffix The suffix to append to tools-source. Useful for query strings." + echo " -u|--update Update to the latest KoreBuild even if the lock file is present." + echo " --reinstall Reinstall KoreBuild." + echo " --ci Apply CI specific settings and environment variables." + echo "" + echo "Description:" + echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be." + echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." + + if [[ "${1:-}" != '--no-exit' ]]; then + exit 2 + fi +} + +get_korebuild() { + local version + local lock_file="$repo_path/korebuild-lock.txt" + if [ ! -f "$lock_file" ] || [ "$update" = true ]; then + __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" "$tools_source_suffix" + fi + version="$(grep 'version:*' -m 1 "$lock_file")" + if [[ "$version" == '' ]]; then + __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" + return 1 + fi + version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" + + if [ "$reinstall" = true ] && [ -d "$korebuild_path" ]; then + rm -rf "$korebuild_path" + fi + + { + if [ ! -d "$korebuild_path" ]; then + mkdir -p "$korebuild_path" + local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" + tmpfile="$(mktemp)" + echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" + if __get_remote_file "$remote_path" "$tmpfile" "$tools_source_suffix"; then + unzip -q -d "$korebuild_path" "$tmpfile" + fi + rm "$tmpfile" || true + fi + + source "$korebuild_path/KoreBuild.sh" + } || { + if [ -d "$korebuild_path" ]; then + echo "Cleaning up after failed installation" + rm -rf "$korebuild_path" || true + fi + return 1 + } +} + +__error() { + echo -e "${RED}error: $*${RESET}" 1>&2 +} + +__warn() { + echo -e "${YELLOW}warning: $*${RESET}" +} + +__machine_has() { + hash "$1" > /dev/null 2>&1 + return $? +} + +__get_remote_file() { + local remote_path=$1 + local local_path=$2 + local remote_path_suffix=$3 + + if [[ "$remote_path" != 'http'* ]]; then + cp "$remote_path" "$local_path" + return 0 + fi + + local failed=false + if __machine_has wget; then + wget --tries 10 --quiet -O "$local_path" "${remote_path}${remote_path_suffix}" || failed=true + else + failed=true + fi + + if [ "$failed" = true ] && __machine_has curl; then + failed=false + curl --retry 10 -sSL -f --create-dirs -o "$local_path" "${remote_path}${remote_path_suffix}" || failed=true + fi + + if [ "$failed" = true ]; then + __error "Download failed: $remote_path" 1>&2 + return 1 + fi +} + +# +# main +# + +command="${1:-}" +shift + +while [[ $# -gt 0 ]]; do + case $1 in + -\?|-h|--help) + __usage --no-exit + exit 0 + ;; + -c|--channel|-Channel) + shift + channel="${1:-}" + [ -z "$channel" ] && __usage + ;; + --config-file|-ConfigFile) + shift + config_file="${1:-}" + [ -z "$config_file" ] && __usage + if [ ! -f "$config_file" ]; then + __error "Invalid value for --config-file. $config_file does not exist." + exit 1 + fi + ;; + -d|--dotnet-home|-DotNetHome) + shift + DOTNET_HOME="${1:-}" + [ -z "$DOTNET_HOME" ] && __usage + ;; + --path|-Path) + shift + repo_path="${1:-}" + [ -z "$repo_path" ] && __usage + ;; + -s|--tools-source|-ToolsSource) + shift + tools_source="${1:-}" + [ -z "$tools_source" ] && __usage + ;; + --tools-source-suffix|-ToolsSourceSuffix) + shift + tools_source_suffix="${1:-}" + [ -z "$tools_source_suffix" ] && __usage + ;; + -u|--update|-Update) + update=true + ;; + --reinstall|-[Rr]einstall) + reinstall=true + ;; + --ci|-[Cc][Ii]) + ci=true + ;; + --verbose|-Verbose) + verbose=true + ;; + --) + shift + break + ;; + *) + break + ;; + esac + shift +done + +if ! __machine_has unzip; then + __error 'Missing required command: unzip' + exit 1 +fi + +if ! __machine_has curl && ! __machine_has wget; then + __error 'Missing required command. Either wget or curl is required.' + exit 1 +fi + +[ -z "${config_file:-}" ] && config_file="$repo_path/korebuild.json" +if [ -f "$config_file" ]; then + if __machine_has jq ; then + if jq '.' "$config_file" >/dev/null ; then + config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" + config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" + else + __error "$config_file contains invalid JSON." + exit 1 + fi + elif __machine_has python ; then + if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then + config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" + config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" + else + __error "$config_file contains invalid JSON." + exit 1 + fi + elif __machine_has python3 ; then + if python3 -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then + config_channel="$(python3 -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" + config_tools_source="$(python3 -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" + else + __error "$config_file contains invalid JSON." + exit 1 + fi + else + __error 'Missing required command: jq or python. Could not parse the JSON file.' + exit 1 + fi + + [ ! -z "${config_channel:-}" ] && channel="$config_channel" + [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source" +fi + +[ -z "$channel" ] && channel='master' +[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' + +get_korebuild +set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" "$ci" +invoke_korebuild_command "$command" "$@" diff --git a/samples/CookiePolicySample/CookiePolicySample.csproj b/samples/CookiePolicySample/CookiePolicySample.csproj new file mode 100644 index 000000000..010edb018 --- /dev/null +++ b/samples/CookiePolicySample/CookiePolicySample.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp3.0 + + + + + + + + + + + + + + diff --git a/samples/CookiePolicySample/Program.cs b/samples/CookiePolicySample/Program.cs new file mode 100644 index 000000000..3fc09a3db --- /dev/null +++ b/samples/CookiePolicySample/Program.cs @@ -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() + .Build(); + + host.Run(); + } + } +} diff --git a/samples/CookiePolicySample/Properties/launchSettings.json b/samples/CookiePolicySample/Properties/launchSettings.json new file mode 100644 index 000000000..38ca6fc37 --- /dev/null +++ b/samples/CookiePolicySample/Properties/launchSettings.json @@ -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" + } + } + } +} \ No newline at end of file diff --git a/samples/CookiePolicySample/Startup.cs b/samples/CookiePolicySample/Startup.cs new file mode 100644 index 000000000..4dcc6d4dc --- /dev/null +++ b/samples/CookiePolicySample/Startup.cs @@ -0,0 +1,127 @@ +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(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 "/CreateEssentialCookie": + context.Response.Cookies.Append("EssentialCookie", "2", + new CookieOptions() { IsEssential = true }); + break; + case "/RemoveEssentialCookie": + context.Response.Cookies.Delete("EssentialCookie"); + break; + case "/GrantConsent": + context.Features.Get().GrantConsent(); + break; + case "/WithdrawConsent": + context.Features.Get().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("\r\n"); + + await response.WriteAsync($"Home
\r\n"); + await response.WriteAsync($"Login
\r\n"); + await response.WriteAsync($"Logout
\r\n"); + await response.WriteAsync($"Create Temp Cookie
\r\n"); + await response.WriteAsync($"Remove Temp Cookie
\r\n"); + await response.WriteAsync($"Create Essential Cookie
\r\n"); + await response.WriteAsync($"Remove Essential Cookie
\r\n"); + await response.WriteAsync($"Grant Consent
\r\n"); + await response.WriteAsync($"Withdraw Consent
\r\n"); + await response.WriteAsync("
\r\n"); + await response.WriteAsync($"Needs Consent
\r\n"); + await response.WriteAsync($"Needs No Consent
\r\n"); + await response.WriteAsync("
\r\n"); + + var feature = context.Features.Get(); + await response.WriteAsync($"Consent:
\r\n"); + await response.WriteAsync($" - IsNeeded: {feature.IsConsentNeeded}
\r\n"); + await response.WriteAsync($" - Has: {feature.HasConsent}
\r\n"); + await response.WriteAsync($" - Can Track: {feature.CanTrack}
\r\n"); + await response.WriteAsync("
\r\n"); + + await response.WriteAsync($"{cookies.Count} Request Cookies:
\r\n"); + foreach (var cookie in cookies) + { + await response.WriteAsync($" - {cookie.Key} = {cookie.Value}
\r\n"); + } + await response.WriteAsync("
\r\n"); + + var responseCookies = response.Headers[HeaderNames.SetCookie]; + await response.WriteAsync($"{responseCookies.Count} Response Cookies:
\r\n"); + foreach (var cookie in responseCookies) + { + await response.WriteAsync($" - {cookie}
\r\n"); + } + + await response.WriteAsync(""); + } + } +} diff --git a/samples/CookieSample/CookieSample.csproj b/samples/CookieSample/CookieSample.csproj new file mode 100644 index 000000000..bc92d68a2 --- /dev/null +++ b/samples/CookieSample/CookieSample.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp3.0 + + + + + + + + + + + + + + + + diff --git a/samples/CookieSample/CookieSample.xproj b/samples/CookieSample/CookieSample.xproj deleted file mode 100644 index f6575c3e0..000000000 --- a/samples/CookieSample/CookieSample.xproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 558c2c2a-aed8-49de-bb60-d5f8ae06c714 - .\obj - .\bin\ - - - 2.0 - 22569 - - - \ No newline at end of file diff --git a/samples/CookieSample/Program.cs b/samples/CookieSample/Program.cs index 7deed359e..3f40d3194 100644 --- a/samples/CookieSample/Program.cs +++ b/samples/CookieSample/Program.cs @@ -1,5 +1,6 @@ using System.IO; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; namespace CookieSample { @@ -8,6 +9,11 @@ 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() diff --git a/samples/CookieSample/Properties/launchSettings.json b/samples/CookieSample/Properties/launchSettings.json index afe862f4f..38ca6fc37 100644 --- a/samples/CookieSample/Properties/launchSettings.json +++ b/samples/CookieSample/Properties/launchSettings.json @@ -18,10 +18,9 @@ "CookieSample": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "http://localhost:12345", + "applicationUrl": "http://localhost:12345", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development", - "ASPNETCORE_URLS": "http://localhost:12345" + "ASPNETCORE_ENVIRONMENT": "Development" } } } diff --git a/samples/CookieSample/Startup.cs b/samples/CookieSample/Startup.cs index 002d87888..a91791070 100644 --- a/samples/CookieSample/Startup.cs +++ b/samples/CookieSample/Startup.cs @@ -1,11 +1,11 @@ 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; -using Microsoft.Extensions.Logging; namespace CookieSample { @@ -13,24 +13,24 @@ public class Startup { public void ConfigureServices(IServiceCollection services) { - services.AddAuthentication(); + // 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, ILoggerFactory loggerfactory) + public void Configure(IApplicationBuilder app) { - loggerfactory.AddConsole(LogLevel.Information); - - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - AutomaticAuthenticate = true - }); + 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.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user); + await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user); context.Response.ContentType = "text/plain"; await context.Response.WriteAsync("Hello First timer"); diff --git a/samples/CookieSample/project.json b/samples/CookieSample/project.json deleted file mode 100644 index 9815401c9..000000000 --- a/samples/CookieSample/project.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "dependencies": { - "Microsoft.AspNetCore.Authentication.Cookies": "1.2.0-*", - "Microsoft.AspNetCore.DataProtection": "1.2.0-*", - "Microsoft.AspNetCore.Server.IISIntegration": "1.2.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.2.0-*", - "Microsoft.Extensions.Logging.Console": "1.2.0-*" - }, - "buildOptions": { - "emitEntryPoint": true - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - } - }, - "publishOptions": { - "include": [ - "web.config" - ] - }, - "tools": { - "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-*" - }, - "scripts": { - "postpublish": "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" - } -} \ No newline at end of file diff --git a/samples/CookieSample/web.config b/samples/CookieSample/web.config deleted file mode 100644 index f7ac67933..000000000 --- a/samples/CookieSample/web.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/samples/CookieSessionSample/CookieSessionSample.csproj b/samples/CookieSessionSample/CookieSessionSample.csproj new file mode 100644 index 000000000..6230c98a5 --- /dev/null +++ b/samples/CookieSessionSample/CookieSessionSample.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp3.0 + + + + + + + + + + + + + + + + diff --git a/samples/CookieSessionSample/CookieSessionSample.xproj b/samples/CookieSessionSample/CookieSessionSample.xproj deleted file mode 100644 index 1c347c845..000000000 --- a/samples/CookieSessionSample/CookieSessionSample.xproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 19711880-46da-4a26-9e0f-9b2e41d27651 - .\obj - .\bin\ - - - 2.0 - 36505 - - - \ No newline at end of file diff --git a/samples/CookieSessionSample/Program.cs b/samples/CookieSessionSample/Program.cs index adf8f1f1a..1a19850e6 100644 --- a/samples/CookieSessionSample/Program.cs +++ b/samples/CookieSessionSample/Program.cs @@ -1,6 +1,6 @@ using System.IO; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; namespace CookieSessionSample { @@ -9,6 +9,11 @@ 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() diff --git a/samples/CookieSessionSample/Properties/launchSettings.json b/samples/CookieSessionSample/Properties/launchSettings.json index edb6e4dd1..25de3e478 100644 --- a/samples/CookieSessionSample/Properties/launchSettings.json +++ b/samples/CookieSessionSample/Properties/launchSettings.json @@ -18,10 +18,9 @@ "CookieSessionSample": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "http://localhost:12345", + "applicationUrl": "http://localhost:12345", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development", - "ASPNETCORE_URLS": "http://localhost:12345" + "ASPNETCORE_ENVIRONMENT": "Development" } } } diff --git a/samples/CookieSessionSample/Startup.cs b/samples/CookieSessionSample/Startup.cs index ecb61ab66..f7b8f2bb8 100644 --- a/samples/CookieSessionSample/Startup.cs +++ b/samples/CookieSessionSample/Startup.cs @@ -4,9 +4,9 @@ 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; -using Microsoft.Extensions.Logging; namespace CookieSessionSample { @@ -14,18 +14,17 @@ public class Startup { public void ConfigureServices(IServiceCollection services) { - services.AddAuthentication(); + // 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, ILoggerFactory loggerfactory) + public void Configure(IApplicationBuilder app) { - loggerfactory.AddConsole(LogLevel.Information); - - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - AutomaticAuthenticate = true, - SessionStore = new MemoryCacheTicketStore() - }); + app.UseAuthentication(); app.Run(async context => { @@ -39,7 +38,7 @@ public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) claims.Add(new Claim(ClaimTypes.Role, "SomeRandomGroup" + i, ClaimValueTypes.String, "IssuedByBob", "OriginalIssuerJoe")); } - await context.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, + await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme))); context.Response.ContentType = "text/plain"; diff --git a/samples/CookieSessionSample/project.json b/samples/CookieSessionSample/project.json deleted file mode 100644 index 728956503..000000000 --- a/samples/CookieSessionSample/project.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "dependencies": { - "Microsoft.AspNetCore.Authentication.Cookies": "1.2.0-*", - "Microsoft.AspNetCore.DataProtection": "1.2.0-*", - "Microsoft.AspNetCore.Server.IISIntegration": "1.2.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", - "Microsoft.Extensions.Caching.Memory": "1.2.0-*", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.2.0-*", - "Microsoft.Extensions.Logging.Console": "1.2.0-*" - }, - "buildOptions": { - "emitEntryPoint": true - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - } - }, - "publishOptions": { - "include": [ - "web.config" - ] - }, - "tools": { - "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-*" - }, - "scripts": { - "postpublish": "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" - } -} \ No newline at end of file diff --git a/samples/CookieSessionSample/web.config b/samples/CookieSessionSample/web.config deleted file mode 100644 index f7ac67933..000000000 --- a/samples/CookieSessionSample/web.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/samples/JwtBearerSample/JwtBearerSample.csproj b/samples/JwtBearerSample/JwtBearerSample.csproj new file mode 100644 index 000000000..58bf5e2d9 --- /dev/null +++ b/samples/JwtBearerSample/JwtBearerSample.csproj @@ -0,0 +1,21 @@ + + + + netcoreapp3.0 + aspnet5-JwtBearerSample-20151210102827 + + + + + + + + + + + + + + + + diff --git a/samples/JwtBearerSample/JwtBearerSample.xproj b/samples/JwtBearerSample/JwtBearerSample.xproj deleted file mode 100644 index 97f5837ce..000000000 --- a/samples/JwtBearerSample/JwtBearerSample.xproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - d399b84f-591b-4e98-92ba-b0f63e7b6957 - .\obj - .\bin\ - - - 2.0 - - - - - - - - - \ No newline at end of file diff --git a/samples/JwtBearerSample/Properties/launchSettings.json b/samples/JwtBearerSample/Properties/launchSettings.json index e89788c48..6922375c9 100644 --- a/samples/JwtBearerSample/Properties/launchSettings.json +++ b/samples/JwtBearerSample/Properties/launchSettings.json @@ -18,10 +18,9 @@ "JwtBearer": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "http://localhost:42023", + "applicationUrl": "http://localhost:42023", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development", - "ASPNETCORE_URLS": "http://localhost:42023" + "ASPNETCORE_ENVIRONMENT": "Development" } } } diff --git a/samples/JwtBearerSample/Startup.cs b/samples/JwtBearerSample/Startup.cs index ac599bc57..8c4a63cad 100644 --- a/samples/JwtBearerSample/Startup.cs +++ b/samples/JwtBearerSample/Startup.cs @@ -1,6 +1,8 @@ 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; @@ -24,7 +26,7 @@ public Startup(IHostingEnvironment env) if (env.IsDevelopment()) { // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 - builder.AddUserSecrets(); + builder.AddUserSecrets(); } builder.AddEnvironmentVariables(); @@ -42,71 +44,42 @@ public Startup(IHostingEnvironment env) // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { - services.AddAuthentication(); + 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) { - // Simple error page to avoid a repo dependency. - app.Use(async (context, next) => - { - try - { - await next(); - } - catch (Exception ex) - { - if (context.Response.HasStarted) - { - throw; - } - context.Response.StatusCode = 500; - await context.Response.WriteAsync(ex.ToString()); - } - }); + app.UseDeveloperExceptionPage(); app.UseDefaultFiles(); app.UseStaticFiles(); - app.UseJwtBearerAuthentication(new JwtBearerOptions - { - // You also need to update /wwwroot/app/scripts/app.js - Authority = Configuration["jwt:authority"], - Audience = Configuration["jwt:audience"], - Events = new JwtBearerEvents() - { - 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."); - } - } - }); + app.UseAuthentication(); // [Authorize] would usually handle this app.Use(async (context, next) => { - // Use this if options.AutomaticAuthenticate = false - // var user = await context.Authentication.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme); - - var user = context.User; // We can do this because of options.AutomaticAuthenticate = true; - if (user?.Identity?.IsAuthenticated ?? false) + // 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 { - // We can do this because of options.AutomaticChallenge = true; - await context.Authentication.ChallengeAsync(); + await context.ChallengeAsync(); } }); @@ -135,5 +108,4 @@ public void Configure(IApplicationBuilder app) }); } } -} - +} \ No newline at end of file diff --git a/samples/JwtBearerSample/project.json b/samples/JwtBearerSample/project.json deleted file mode 100644 index 794cc4a6a..000000000 --- a/samples/JwtBearerSample/project.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "version": "1.1.0-*", - "buildOptions": { - "emitEntryPoint": true - }, - "dependencies": { - "Microsoft.AspNetCore.Authentication.JwtBearer": "1.2.0-*", - "Microsoft.AspNetCore.Server.IISIntegration": "1.2.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", - "Microsoft.AspNetCore.StaticFiles": "1.2.0-*", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.2.0-*", - "Microsoft.Extensions.Configuration.UserSecrets": "1.2.0-*" - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - } - }, - "publishOptions": { - "include": [ - "project.json", - "wwwroot", - "web.config" - ] - }, - "userSecretsId": "aspnet5-JwtBearerSample-20151210102827", - "tools": { - "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-*" - }, - "scripts": { - "postpublish": "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" - } -} \ No newline at end of file diff --git a/samples/JwtBearerSample/web.config b/samples/JwtBearerSample/web.config deleted file mode 100644 index f7ac67933..000000000 --- a/samples/JwtBearerSample/web.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/samples/JwtBearerSample/wwwroot/index.html b/samples/JwtBearerSample/wwwroot/index.html index f71dccb69..4715ebd42 100644 --- a/samples/JwtBearerSample/wwwroot/index.html +++ b/samples/JwtBearerSample/wwwroot/index.html @@ -64,5 +64,6 @@

Todo List

+ diff --git a/samples/OpenIdConnect.AzureAdSample/AuthPropertiesTokenCache.cs b/samples/OpenIdConnect.AzureAdSample/AuthPropertiesTokenCache.cs index 54989c13a..7d9b39121 100644 --- a/samples/OpenIdConnect.AzureAdSample/AuthPropertiesTokenCache.cs +++ b/samples/OpenIdConnect.AzureAdSample/AuthPropertiesTokenCache.cs @@ -1,9 +1,8 @@ using System; using System.Security.Claims; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.IdentityModel.Clients.ActiveDirectory; namespace OpenIdConnect.AzureAdSample @@ -58,10 +57,9 @@ private void BeforeAccessNotificationWithProperties(TokenCacheNotificationArgs a private void BeforeAccessNotificationWithContext(TokenCacheNotificationArgs args) { // Retrieve the auth session with the cached tokens - var authenticateContext = new AuthenticateContext(_signInScheme); - _httpContext.Authentication.AuthenticateAsync(authenticateContext).Wait(); - _authProperties = new AuthenticationProperties(authenticateContext.Properties); - _principal = authenticateContext.Principal; + var result = _httpContext.AuthenticateAsync(_signInScheme).Result; + _authProperties = result.Ticket.Properties; + _principal = result.Ticket.Principal; BeforeAccessNotificationWithProperties(args); } @@ -87,7 +85,7 @@ private void AfterAccessNotificationWithContext(TokenCacheNotificationArgs args) var cachedTokens = Serialize(); var cachedTokensText = Convert.ToBase64String(cachedTokens); _authProperties.Items[TokenCacheKey] = cachedTokensText; - _httpContext.Authentication.SignInAsync(_signInScheme, _principal, _authProperties).Wait(); + _httpContext.SignInAsync(_signInScheme, _principal, _authProperties).Wait(); } } diff --git a/samples/OpenIdConnect.AzureAdSample/OpenIdConnect.AzureAdSample.csproj b/samples/OpenIdConnect.AzureAdSample/OpenIdConnect.AzureAdSample.csproj new file mode 100644 index 000000000..61754b60b --- /dev/null +++ b/samples/OpenIdConnect.AzureAdSample/OpenIdConnect.AzureAdSample.csproj @@ -0,0 +1,23 @@ + + + + netcoreapp3.0 + aspnet5-OpenIdConnectSample-20151210110318 + + + + + + + + + + + + + + + + + + diff --git a/samples/OpenIdConnect.AzureAdSample/OpenIdConnect.AzureAdSample.xproj b/samples/OpenIdConnect.AzureAdSample/OpenIdConnect.AzureAdSample.xproj deleted file mode 100644 index 26e9f9030..000000000 --- a/samples/OpenIdConnect.AzureAdSample/OpenIdConnect.AzureAdSample.xproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 3a7ad414-ebde-4f92-b307-4e8f19b6117e - .\obj - .\bin\ - - - 2.0 - - - - - - - - - \ No newline at end of file diff --git a/samples/OpenIdConnect.AzureAdSample/Program.cs b/samples/OpenIdConnect.AzureAdSample/Program.cs index 11d1fbeaf..0e1285a9c 100644 --- a/samples/OpenIdConnect.AzureAdSample/Program.cs +++ b/samples/OpenIdConnect.AzureAdSample/Program.cs @@ -1,5 +1,6 @@ using System.IO; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; namespace OpenIdConnect.AzureAdSample { @@ -8,7 +9,13 @@ 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() diff --git a/samples/OpenIdConnect.AzureAdSample/Properties/launchSettings.json b/samples/OpenIdConnect.AzureAdSample/Properties/launchSettings.json index 62dc4ef77..e6436fee2 100644 --- a/samples/OpenIdConnect.AzureAdSample/Properties/launchSettings.json +++ b/samples/OpenIdConnect.AzureAdSample/Properties/launchSettings.json @@ -18,10 +18,9 @@ "OpenIdConnect": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "http://localhost:42023", + "applicationUrl": "http://localhost:42023", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development", - "ASPNETCORE_URLS": "http://localhost:42023" + "ASPNETCORE_ENVIRONMENT": "Development" } } } diff --git a/samples/OpenIdConnect.AzureAdSample/Readme.md b/samples/OpenIdConnect.AzureAdSample/Readme.md index 37dda75a7..767e336ac 100644 --- a/samples/OpenIdConnect.AzureAdSample/Readme.md +++ b/samples/OpenIdConnect.AzureAdSample/Readme.md @@ -10,7 +10,7 @@ 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 DEVELOPMENMT. ([Working with Multiple Environments](https://docs.asp.net/en/latest/fundamentals/environments.html)) +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 diff --git a/samples/OpenIdConnect.AzureAdSample/Startup.cs b/samples/OpenIdConnect.AzureAdSample/Startup.cs index 84558affb..c3fa3c719 100644 --- a/samples/OpenIdConnect.AzureAdSample/Startup.cs +++ b/samples/OpenIdConnect.AzureAdSample/Startup.cs @@ -3,16 +3,15 @@ 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.Authentication; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Clients.ActiveDirectory; using Microsoft.IdentityModel.Protocols.OpenIdConnect; @@ -28,7 +27,7 @@ public Startup(IHostingEnvironment env) if (env.IsDevelopment()) { // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 - builder.AddUserSecrets(); + builder.AddUserSecrets(); } builder.AddEnvironmentVariables(); @@ -37,68 +36,50 @@ public Startup(IHostingEnvironment env) 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.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme); - } - - public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) - { - loggerfactory.AddConsole(Microsoft.Extensions.Logging.LogLevel.Information); - - // Simple error page - app.Use(async (context, next) => { - try - { - await next(); - } - catch (Exception ex) - { - if (!context.Response.HasStarted) - { - context.Response.Clear(); - context.Response.StatusCode = 500; - await context.Response.WriteAsync(ex.ToString()); - } - else - { - throw; - } - } - }); - - app.UseCookieAuthentication(new CookieAuthenticationOptions()); - - var clientId = Configuration["oidc:clientid"]; - var clientSecret = Configuration["oidc:clientsecret"]; - var authority = Configuration["oidc:authority"]; - var resource = "https://graph.windows.net"; - app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions + sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; + sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; + }) + .AddCookie() + .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, "AAD", o => { - ClientId = clientId, - ClientSecret = clientSecret, // for code flow - Authority = authority, - ResponseType = OpenIdConnectResponseType.CodeIdToken, - PostLogoutRedirectUri = "/signed-out", + o.ClientId = ClientId; + o.ClientSecret = ClientSecret; // for code flow + o.Authority = Authority; + o.ResponseType = OpenIdConnectResponseType.CodeIdToken; + o.SignedOutRedirectUri = "/signed-out"; // GetClaimsFromUserInfoEndpoint = true, - Events = new OpenIdConnectEvents() + 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 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.ProtocolMessage.Code, new Uri(currentUri), credential, Resource); - context.HandleCodeRedemption(); + context.HandleCodeRedemption(result.AccessToken, result.IdToken); } - } + }; }); + } + + public void Configure(IApplicationBuilder app) + { + app.UseDeveloperExceptionPage(); + + app.UseAuthentication(); app.Run(async context => { @@ -111,13 +92,11 @@ public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) return; } - await context.Authentication.ChallengeAsync( - OpenIdConnectDefaults.AuthenticationScheme, - new AuthenticationProperties { RedirectUri = "/" }); + await context.ChallengeAsync(new AuthenticationProperties { RedirectUri = "/" }); } else if (context.Request.Path.Equals("/signout")) { - await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await WriteHtmlAsync(context.Response, async response => { @@ -127,8 +106,8 @@ await WriteHtmlAsync(context.Response, } else if (context.Request.Path.Equals("/signout-remote")) { - await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - await context.Authentication.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme); + await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme); } else if (context.Request.Path.Equals("/signed-out")) { @@ -141,7 +120,7 @@ await WriteHtmlAsync(context.Response, } else if (context.Request.Path.Equals("/remote-signedout")) { - await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await WriteHtmlAsync(context.Response, async response => { @@ -153,7 +132,7 @@ await WriteHtmlAsync(context.Response, { if (!context.User.Identities.Any(identity => identity.IsAuthenticated)) { - await context.Authentication.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/" }); + await context.ChallengeAsync(new AuthenticationProperties { RedirectUri = "/" }); return; } @@ -170,10 +149,10 @@ await WriteHtmlAsync(context.Response, async response => try { // Use ADAL to get the right token - var authContext = new AuthenticationContext(authority, AuthPropertiesTokenCache.ForApiCalls(context, CookieAuthenticationDefaults.AuthenticationScheme)); - var credential = new ClientCredential(clientId, clientSecret); + 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)); + var result = await authContext.AcquireTokenSilentAsync(Resource, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId)); await response.WriteAsync($"

access_token

{HtmlEncode(result.AccessToken)}
"); } diff --git a/samples/OpenIdConnect.AzureAdSample/project.json b/samples/OpenIdConnect.AzureAdSample/project.json deleted file mode 100644 index 9d3c75d28..000000000 --- a/samples/OpenIdConnect.AzureAdSample/project.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "dependencies": { - "Microsoft.AspNetCore.Authentication.Cookies": "1.2.0-*", - "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.2.0-*", - "Microsoft.AspNetCore.Server.IISIntegration": "1.2.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.2.0-*", - "Microsoft.Extensions.Configuration.UserSecrets": "1.2.0-*", - "Microsoft.Extensions.Logging.Console": "1.2.0-*", - "Microsoft.IdentityModel.Clients.ActiveDirectory": "3.13.4" - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - } - }, - "buildOptions": { - "emitEntryPoint": true - }, - "publishOptions": { - "include": [ - "project.json", - "web.config" - ] - }, - "userSecretsId": "aspnet5-OpenIdConnectSample-20151210110318", - "tools": { - "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-*", - "Microsoft.Extensions.SecretManager.Tools": "1.0.0-*" - }, - "scripts": { - "postpublish": "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" - } -} \ No newline at end of file diff --git a/samples/OpenIdConnect.AzureAdSample/web.config b/samples/OpenIdConnect.AzureAdSample/web.config deleted file mode 100644 index f7ac67933..000000000 --- a/samples/OpenIdConnect.AzureAdSample/web.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/samples/OpenIdConnectSample/OpenIdConnectSample.csproj b/samples/OpenIdConnectSample/OpenIdConnectSample.csproj new file mode 100644 index 000000000..137ee47ba --- /dev/null +++ b/samples/OpenIdConnectSample/OpenIdConnectSample.csproj @@ -0,0 +1,33 @@ + + + + netcoreapp3.0 + aspnet5-OpenIdConnectSample-20151210110318 + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/OpenIdConnectSample/OpenIdConnectSample.xproj b/samples/OpenIdConnectSample/OpenIdConnectSample.xproj deleted file mode 100644 index 9029ad0f1..000000000 --- a/samples/OpenIdConnectSample/OpenIdConnectSample.xproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - bef0f5c3-ef4e-4649-9c49-d5e279a3ca2b - .\obj - .\bin\ - - - 2.0 - 42023 - - - \ No newline at end of file diff --git a/samples/OpenIdConnectSample/Program.cs b/samples/OpenIdConnectSample/Program.cs index 49cbf139d..87e775508 100644 --- a/samples/OpenIdConnectSample/Program.cs +++ b/samples/OpenIdConnectSample/Program.cs @@ -1,8 +1,11 @@ -using System.IO; +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 { @@ -11,13 +14,22 @@ 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 => { - // Configure SSL - var serverCertificate = LoadCertificate(); - options.UseHttps(serverCertificate); + options.Listen(IPAddress.Loopback, 44318, listenOptions => + { + // Configure SSL + var serverCertificate = LoadCertificate(); + listenOptions.UseHttps(serverCertificate); + }); }) - .UseUrls("https://localhost:44318") .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup() diff --git a/samples/OpenIdConnectSample/Properties/launchSettings.json b/samples/OpenIdConnectSample/Properties/launchSettings.json index 48610115f..058fa4c5d 100644 --- a/samples/OpenIdConnectSample/Properties/launchSettings.json +++ b/samples/OpenIdConnectSample/Properties/launchSettings.json @@ -19,9 +19,8 @@ "OpenIdConnectSample": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "https://localhost:44318/", + "applicationUrl": "https://localhost:44318/", "environmentVariables": { - "ASPNETCORE_URLS": "https://localhost:44318/", "ASPNETCORE_ENVIRONMENT": "Development" } } diff --git a/samples/OpenIdConnectSample/Startup.cs b/samples/OpenIdConnectSample/Startup.cs index 90ed3db25..a2b5a9a5c 100644 --- a/samples/OpenIdConnectSample/Startup.cs +++ b/samples/OpenIdConnectSample/Startup.cs @@ -1,18 +1,22 @@ 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.AspNetCore.Http.Authentication; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Protocols.OpenIdConnect; +using Newtonsoft.Json.Linq; namespace OpenIdConnectSample { @@ -28,7 +32,7 @@ public Startup(IHostingEnvironment env) if (env.IsDevelopment()) { // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 - builder.AddUserSecrets(); + builder.AddUserSecrets(); } builder.AddEnvironmentVariables(); @@ -41,47 +45,29 @@ public Startup(IHostingEnvironment env) public void ConfigureServices(IServiceCollection services) { - services.AddAuthentication(sharedOptions => - sharedOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme); - } - - public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) - { - loggerfactory.AddConsole(LogLevel.Information); - loggerfactory.AddDebug(LogLevel.Information); + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); - // Simple error page - app.Use(async (context, next) => + services.AddAuthentication(sharedOptions => { - try - { - await next(); - } - catch (Exception ex) - { - if (!context.Response.HasStarted) - { - context.Response.Clear(); - context.Response.StatusCode = 500; - await context.Response.WriteAsync(ex.ToString()); - } - else - { - throw; - } - } - }); + 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"]; - app.UseCookieAuthentication(new CookieAuthenticationOptions()); + o.ResponseType = OpenIdConnectResponseType.CodeIdToken; + o.SaveTokens = true; + o.GetClaimsFromUserInfoEndpoint = true; + o.AccessDeniedPath = "/access-denied-from-remote"; - app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions - { - ClientId = Configuration["oidc:clientid"], - ClientSecret = Configuration["oidc:clientsecret"], // for code flow - Authority = Configuration["oidc:authority"], - ResponseType = OpenIdConnectResponseType.CodeIdToken, - GetClaimsFromUserInfoEndpoint = true, - Events = new OpenIdConnectEvents() + o.ClaimActions.MapAllExcept("aud", "iss", "iat", "nbf", "exp", "aio", "c_hash", "uti", "nonce"); + + o.Events = new OpenIdConnectEvents() { OnAuthenticationFailed = c => { @@ -96,28 +82,36 @@ public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) } return c.Response.WriteAsync("An error occurred processing your authentication."); } - } + }; }); + } + + public void Configure(IApplicationBuilder app, IOptionsMonitor optionsMonitor) + { + app.UseDeveloperExceptionPage(); + app.UseAuthentication(); app.Run(async context => { + var response = context.Response; + if (context.Request.Path.Equals("/signedout")) { - await WriteHtmlAsync(context.Response, async res => + await WriteHtmlAsync(response, async res => { await res.WriteAsync($"

You have been signed out.

"); - await res.WriteAsync("Sign In"); + await res.WriteAsync("Home"); }); return; } if (context.Request.Path.Equals("/signout")) { - await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - await WriteHtmlAsync(context.Response, async res => + await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + await WriteHtmlAsync(response, async res => { - await context.Response.WriteAsync($"

Signed out {HtmlEncode(context.User.Identity.Name)}

"); - await context.Response.WriteAsync("Sign In"); + await res.WriteAsync($"

Signed out {HtmlEncode(context.User.Identity.Name)}

"); + await res.WriteAsync("Home"); }); return; } @@ -125,43 +119,55 @@ await WriteHtmlAsync(context.Response, async res => if (context.Request.Path.Equals("/signout-remote")) { // Redirects - await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - await context.Authentication.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties() + await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties() { RedirectUri = "/signedout" }); return; } + if (context.Request.Path.Equals("/access-denied-from-remote")) + { + await WriteHtmlAsync(response, async res => + { + await res.WriteAsync($"

Access Denied error received from the remote authorization server

"); + await res.WriteAsync("Home"); + }); + return; + } + if (context.Request.Path.Equals("/Account/AccessDenied")) { - await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - await WriteHtmlAsync(context.Response, async res => + await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + await WriteHtmlAsync(response, async res => { - await context.Response.WriteAsync($"

Access Denied for user {HtmlEncode(context.User.Identity.Name)} to resource '{HtmlEncode(context.Request.Query["ReturnUrl"])}'

"); - await context.Response.WriteAsync("Sign Out"); + await res.WriteAsync($"

Access Denied for user {HtmlEncode(context.User.Identity.Name)} to resource '{HtmlEncode(context.Request.Query["ReturnUrl"])}'

"); + await res.WriteAsync("Sign Out"); + await res.WriteAsync("Home"); }); return; } - // CookieAuthenticationOptions.AutomaticAuthenticate = true (default) causes User to be set - var user = context.User; + // DefaultAuthenticateScheme causes User to be set + // var user = context.User; // This is what [Authorize] calls - // var user = await context.Authentication.AuthenticateAsync(AuthenticationManager.AutomaticScheme); + 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.Authentication.AuthenticateAsync(OpenIdConnectDefaults.AuthenticationScheme); + // var user = await context.AuthenticateAsync(OpenIdConnectDefaults.AuthenticationScheme); // Not authenticated if (user == null || !user.Identities.Any(identity => identity.IsAuthenticated)) { // This is what [Authorize] calls - // The cookie middleware will intercept this 401 and redirect to /login - await context.Authentication.ChallengeAsync(); + await context.ChallengeAsync(); // This is what [Authorize(ActiveAuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] calls - // await context.Authentication.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme); + // await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme); return; } @@ -169,20 +175,97 @@ await WriteHtmlAsync(context.Response, async res => // Authenticated, but not authorized if (context.Request.Path.Equals("/restricted") && !user.Identities.Any(identity => identity.HasClaim("special", "true"))) { - await context.Authentication.ChallengeAsync(); + 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.
"); + await res.WriteAsync("Sign Out"); + }); + + return; + } + + var options = optionsMonitor.Get(OpenIdConnectDefaults.AuthenticationScheme); + var metadata = await options.ConfigurationManager.GetConfigurationAsync(context.RequestAborted); + + var pairs = new Dictionary() + { + { "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("access_token")); + props.UpdateTokenValue("refresh_token", payload.Value("refresh_token")); + if (int.TryParse(payload.Value("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($"

Refreshed.

"); + await res.WriteAsync("Refresh tokens"); + await res.WriteAsync("Home"); + + await res.WriteAsync("

Tokens:

"); + await WriteTableHeader(res, new string[] { "Token Type", "Value" }, props.GetTokens().Select(token => new string[] { token.Name, token.Value })); + + await res.WriteAsync("

Payload:

"); + await res.WriteAsync(HtmlEncoder.Default.Encode(payload.ToString()).Replace(",", ",
") + "
"); + }); + 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" } + }); - await WriteHtmlAsync(context.Response, async response => + return; + } + + await WriteHtmlAsync(response, async res => { - await response.WriteAsync($"

Hello Authenticated User {HtmlEncode(user.Identity.Name)}

"); - await response.WriteAsync("Restricted"); - await response.WriteAsync("Sign Out"); - await response.WriteAsync("Sign Out Remote"); + await res.WriteAsync($"

Hello Authenticated User {HtmlEncode(user.Identity.Name)}

"); + await res.WriteAsync("Refresh tokens"); + await res.WriteAsync("Restricted"); + await res.WriteAsync("Login challenge"); + await res.WriteAsync("Sign Out"); + await res.WriteAsync("Sign Out Remote"); + + await res.WriteAsync("

Claims:

"); + await WriteTableHeader(res, new string[] { "Claim Type", "Value" }, context.User.Claims.Select(c => new string[] { c.Type, c.Value })); - await response.WriteAsync("

Claims:

"); - await WriteTableHeader(response, new string[] { "Claim Type", "Value" }, context.User.Claims.Select(c => new string[] { c.Type, c.Value })); + await res.WriteAsync("

Tokens:

"); + await WriteTableHeader(res, new string[] { "Token Type", "Value" }, props.GetTokens().Select(token => new string[] { token.Name, token.Value })); }); }); } diff --git a/samples/OpenIdConnectSample/project.json b/samples/OpenIdConnectSample/project.json deleted file mode 100644 index 446afd02a..000000000 --- a/samples/OpenIdConnectSample/project.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "dependencies": { - "Microsoft.AspNetCore.Authentication.Cookies": "1.2.0-*", - "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.2.0-*", - "Microsoft.AspNetCore.Server.IISIntegration": "1.2.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", - "Microsoft.AspNetCore.Server.Kestrel.Https": "1.2.0-*", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.2.0-*", - "Microsoft.Extensions.Configuration.UserSecrets": "1.2.0-*", - "Microsoft.Extensions.FileProviders.Embedded": "1.2.0-*", - "Microsoft.Extensions.Logging.Console": "1.2.0-*", - "Microsoft.Extensions.Logging.Debug": "1.2.0-*" - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - } - }, - "buildOptions": { - "emitEntryPoint": true - }, - "publishOptions": { - "include": [ - "project.json", - "web.config" - ] - }, - "userSecretsId": "aspnet5-OpenIdConnectSample-20151210110318", - "tools": { - "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-*", - "Microsoft.Extensions.SecretManager.Tools": "1.0.0-*" - }, - "scripts": { - "postpublish": "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" - } -} \ No newline at end of file diff --git a/samples/OpenIdConnectSample/web.config b/samples/OpenIdConnectSample/web.config deleted file mode 100644 index f7ac67933..000000000 --- a/samples/OpenIdConnectSample/web.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/samples/SocialSample/Program.cs b/samples/SocialSample/Program.cs index f3cad66ad..a712b6c03 100644 --- a/samples/SocialSample/Program.cs +++ b/samples/SocialSample/Program.cs @@ -1,9 +1,11 @@ -using System.IO; +using System; +using System.IO; +using System.Net; using System.Reflection; using System.Security.Cryptography.X509Certificates; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Logging; namespace SocialSample { @@ -12,11 +14,19 @@ 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 => { - //Configure SSL - var serverCertificate = LoadCertificate(); - options.UseHttps(serverCertificate); + options.Listen(IPAddress.Loopback, 44318, listenOptions => + { + // Configure SSL + var serverCertificate = LoadCertificate(); + listenOptions.UseHttps(serverCertificate); + }); }) .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() diff --git a/samples/SocialSample/Properties/launchSettings.json b/samples/SocialSample/Properties/launchSettings.json index 251bfbffd..30bf2e5f6 100644 --- a/samples/SocialSample/Properties/launchSettings.json +++ b/samples/SocialSample/Properties/launchSettings.json @@ -19,10 +19,9 @@ "SocialSample": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "https://localhost:44318/", + "applicationUrl": "https://localhost:44318/", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development", - "ASPNETCORE_URLS": "https://localhost:44318/" + "ASPNETCORE_ENVIRONMENT": "Development" } } } diff --git a/samples/SocialSample/SocialSample.csproj b/samples/SocialSample/SocialSample.csproj new file mode 100644 index 000000000..e1e2262b0 --- /dev/null +++ b/samples/SocialSample/SocialSample.csproj @@ -0,0 +1,36 @@ + + + + netcoreapp3.0 + aspnet5-SocialSample-20151210111056 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/SocialSample/SocialSample.xproj b/samples/SocialSample/SocialSample.xproj deleted file mode 100644 index b439f74d1..000000000 --- a/samples/SocialSample/SocialSample.xproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 8c73d216-332d-41d8-bfd0-45bc4bc36552 - .\obj - .\bin\ - - - 2.0 - 54540 - - - \ No newline at end of file diff --git a/samples/SocialSample/Startup.cs b/samples/SocialSample/Startup.cs index 5bd848067..b5032072b 100644 --- a/samples/SocialSample/Startup.cs +++ b/samples/SocialSample/Startup.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; @@ -7,6 +9,7 @@ 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; @@ -14,10 +17,10 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; +using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; namespace SocialSample @@ -34,7 +37,7 @@ public Startup(IHostingEnvironment env) if (env.IsDevelopment()) { // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 - builder.AddUserSecrets(); + builder.AddUserSecrets(); } builder.AddEnvironmentVariables(); @@ -45,38 +48,6 @@ public Startup(IHostingEnvironment env) public void ConfigureServices(IServiceCollection services) { - services.AddAuthentication(options => options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme); - } - - public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) - { - loggerfactory.AddConsole(LogLevel.Information); - - // Simple error page to avoid a repo dependency. - app.Use(async (context, next) => - { - try - { - await next(); - } - catch (Exception ex) - { - if (context.Response.HasStarted) - { - throw; - } - context.Response.StatusCode = 500; - await context.Response.WriteAsync(ex.ToString()); - } - }); - - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - AutomaticAuthenticate = true, - AutomaticChallenge = true, - LoginPath = new PathString("/login") - }); - if (string.IsNullOrEmpty(Configuration["facebook:appid"])) { // User-Secrets: https://docs.asp.net/en/latest/security/app-secrets.html @@ -84,137 +55,148 @@ public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) throw new InvalidOperationException("User secrets must be configured for each authentication provider."); } - // You must first create an app with Facebook and add its ID and Secret to your user-secrets. - // https://developers.facebook.com/apps/ - app.UseFacebookAuthentication(new FacebookOptions + 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/ + // https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#login + .AddFacebook(o => { - AppId = Configuration["facebook:appid"], - AppSecret = Configuration["facebook:appsecret"], - Scope = { "email" }, - Fields = { "name", "email" }, - SaveTokens = true, - }); - - // You must first create an app with Google and add its ID and Secret to your user-secrets. - // https://console.developers.google.com/project - app.UseOAuthAuthentication(new OAuthOptions + 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 + // https://developers.google.com/identity/protocols/OAuth2WebServer + // https://developers.google.com/+/web/people/ + .AddOAuth("Google-AccessToken", "Google AccessToken only", o => { - AuthenticationScheme = "Google-AccessToken", - DisplayName = "Google-AccessToken", - ClientId = Configuration["google:clientid"], - ClientSecret = Configuration["google:clientsecret"], - CallbackPath = new PathString("/signin-google-token"), - AuthorizationEndpoint = GoogleDefaults.AuthorizationEndpoint, - TokenEndpoint = GoogleDefaults.TokenEndpoint, - Scope = { "openid", "profile", "email" }, - SaveTokens = true - }); - - // You must first create an app with GitHub and add its ID and Secret to your user-secrets. - // https://console.developers.google.com/project - app.UseGoogleAuthentication(new GoogleOptions + 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 + // https://developers.google.com/identity/protocols/OAuth2WebServer + // https://developers.google.com/+/web/people/ + .AddGoogle(o => { - ClientId = Configuration["google:clientid"], - ClientSecret = Configuration["google:clientsecret"], - SaveTokens = true, - Events = new OAuthEvents() + 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 = ctx => - { - ctx.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(ctx.Failure.Message)); - ctx.HandleResponse(); - return Task.FromResult(0); - } - } - }); - - // You must first create an app with Twitter and add its key and Secret to your user-secrets. - // https://apps.twitter.com/ - app.UseTwitterAuthentication(new TwitterOptions + 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/ + // https://developer.twitter.com/en/docs/basics/authentication/api-reference/access_token + .AddTwitter(o => { - ConsumerKey = Configuration["twitter:consumerkey"], - ConsumerSecret = Configuration["twitter:consumersecret"], + 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 - RetrieveUserDetails = true, - SaveTokens = true, - Events = new TwitterEvents() + o.RetrieveUserDetails = true; + o.SaveTokens = true; + o.ClaimActions.MapJsonKey("urn:twitter:profilepicture", "profile_image_url", ClaimTypes.Uri); + o.Events = new TwitterEvents() { - OnCreatingTicket = ctx => - { - var profilePic = ctx.User.Value("profile_image_url"); - ctx.Principal.Identities.First().AddClaim(new Claim("urn:twitter:profilepicture", profilePic, ClaimTypes.Uri, ctx.Options.ClaimsIssuer)); - return Task.FromResult(0); - }, - OnRemoteFailure = ctx => - { - ctx.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(ctx.Failure.Message)); - ctx.HandleResponse(); - return Task.FromResult(0); - } - } - }); - - /* 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/ - app.UseOAuthAuthentication(new OAuthOptions + 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 => { - AuthenticationScheme = "Microsoft-AccessToken", - DisplayName = "MicrosoftAccount-AccessToken", - ClientId = Configuration["microsoftaccount:clientid"], - ClientSecret = Configuration["microsoftaccount:clientsecret"], - CallbackPath = new PathString("/signin-microsoft-token"), - AuthorizationEndpoint = MicrosoftAccountDefaults.AuthorizationEndpoint, - TokenEndpoint = MicrosoftAccountDefaults.TokenEndpoint, - Scope = { "https://graph.microsoft.com/user.read" }, - SaveTokens = true - }); - - // 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/ - app.UseMicrosoftAccountAuthentication(new MicrosoftAccountOptions + 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 => { - DisplayName = "MicrosoftAccount", - ClientId = Configuration["microsoftaccount:clientid"], - ClientSecret = Configuration["microsoftaccount:clientsecret"], - SaveTokens = true - }); - - // You must first create an app with GitHub and add its ID and Secret to your user-secrets. - // https://github.com/settings/applications/ - app.UseOAuthAuthentication(new OAuthOptions + 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 => { - AuthenticationScheme = "GitHub-AccessToken", - DisplayName = "Github-AccessToken", - ClientId = Configuration["github-token:clientid"], - ClientSecret = Configuration["github-token:clientsecret"], - CallbackPath = new PathString("/signin-github-token"), - AuthorizationEndpoint = "https://github.com/login/oauth/authorize", - TokenEndpoint = "https://github.com/login/oauth/access_token", - SaveTokens = true - }); - - // You must first create an app with GitHub and add its ID and Secret to your user-secrets. - // https://github.com/settings/applications/ - app.UseOAuthAuthentication(new OAuthOptions + 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 => { - AuthenticationScheme = "GitHub", - DisplayName = "Github", - ClientId = Configuration["github:clientid"], - ClientSecret = Configuration["github:clientsecret"], - CallbackPath = new PathString("/signin-github"), - AuthorizationEndpoint = "https://github.com/login/oauth/authorize", - TokenEndpoint = "https://github.com/login/oauth/access_token", - UserInformationEndpoint = "https://api.github.com/user", - ClaimsIssuer = "OAuth2-Github", - SaveTokens = true, + 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. - Events = new OAuthEvents + 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 @@ -227,71 +209,185 @@ public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) var user = JObject.Parse(await response.Content.ReadAsStringAsync()); - var identifier = user.Value("id"); - if (!string.IsNullOrEmpty(identifier)) - { - context.Identity.AddClaim(new Claim( - ClaimTypes.NameIdentifier, identifier, - ClaimValueTypes.String, context.Options.ClaimsIssuer)); - } + context.RunClaimActions(user); + } + }; + }); + } - var userName = user.Value("login"); - if (!string.IsNullOrEmpty(userName)) - { - context.Identity.AddClaim(new Claim( - ClaimsIdentity.DefaultNameClaimType, userName, - ClaimValueTypes.String, context.Options.ClaimsIssuer)); - } + private async Task HandleOnRemoteFailure(RemoteFailureContext context) + { + context.Response.StatusCode = 500; + context.Response.ContentType = "text/html"; + await context.Response.WriteAsync(""); + await context.Response.WriteAsync("A remote failure has occurred: " + UrlEncoder.Default.Encode(context.Failure.Message) + "
"); - var name = user.Value("name"); - if (!string.IsNullOrEmpty(name)) - { - context.Identity.AddClaim(new Claim( - "urn:github:name", name, - ClaimValueTypes.String, context.Options.ClaimsIssuer)); - } + if (context.Properties != null) + { + await context.Response.WriteAsync("Properties:
"); + foreach (var pair in context.Properties.Items) + { + await context.Response.WriteAsync($"-{ UrlEncoder.Default.Encode(pair.Key)}={ UrlEncoder.Default.Encode(pair.Value)}
"); + } + } - var email = user.Value("email"); - if (!string.IsNullOrEmpty(email)) - { - context.Identity.AddClaim(new Claim( - ClaimTypes.Email, email, - ClaimValueTypes.Email, context.Options.ClaimsIssuer)); - } + await context.Response.WriteAsync("Home"); + await context.Response.WriteAsync(""); - var link = user.Value("url"); - if (!string.IsNullOrEmpty(link)) - { - context.Identity.AddClaim(new Claim( - "urn:github:url", link, - ClaimValueTypes.String, context.Options.ClaimsIssuer)); - } - } - } - }); + // 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", signoutApp => + app.Map("/login", signinApp => { - signoutApp.Run(async context => + 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.Authentication.ChallengeAsync(authType, new AuthenticationProperties() { RedirectUri = "/" }); + await context.ChallengeAsync(authType, new AuthenticationProperties() { RedirectUri = "/" }); return; } - context.Response.ContentType = "text/html"; - await context.Response.WriteAsync(""); - await context.Response.WriteAsync("Choose an authentication scheme:
"); - foreach (var type in context.Authentication.GetAuthenticationSchemes()) + var response = context.Response; + response.ContentType = "text/html"; + await response.WriteAsync(""); + await response.WriteAsync("Choose an authentication scheme:
"); + var schemeProvider = context.RequestServices.GetRequiredService(); + foreach (var provider in await schemeProvider.GetAllSchemesAsync()) { - await context.Response.WriteAsync("" + (type.DisplayName ?? "(suppressed)") + "
"); + await response.WriteAsync("" + (provider.DisplayName ?? "(suppressed)") + "
"); } - await context.Response.WriteAsync(""); + await response.WriteAsync(""); + }); + }); + + // 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(""); + await response.WriteAsync("No refresh_token is available.
"); + await response.WriteAsync("Home"); + await response.WriteAsync(""); + return; + } + + var options = await GetOAuthOptionsAsync(context, currentAuthType); + + var pairs = new Dictionary() + { + { "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("access_token")); + refreshToken = payload.Value("refresh_token"); + if (!string.IsNullOrEmpty(refreshToken)) + { + authProperties.UpdateTokenValue("refresh_token", refreshToken); + } + if (int.TryParse(payload.Value("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("access_token")); + if (int.TryParse(payload.Value("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(""); + await response.WriteAsync("Refresh has not been implemented for this provider.
"); + await response.WriteAsync("Home"); + await response.WriteAsync(""); }); }); @@ -300,12 +396,13 @@ public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) { signoutApp.Run(async context => { - context.Response.ContentType = "text/html"; - await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - await context.Response.WriteAsync(""); - await context.Response.WriteAsync("You have been logged out. Goodbye " + context.User.Identity.Name + "
"); - await context.Response.WriteAsync("Home"); - await context.Response.WriteAsync(""); + var response = context.Response; + response.ContentType = "text/html"; + await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + await response.WriteAsync(""); + await response.WriteAsync("You have been logged out. Goodbye " + context.User.Identity.Name + "
"); + await response.WriteAsync("Home"); + await response.WriteAsync(""); }); }); @@ -314,58 +411,98 @@ public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) { errorApp.Run(async context => { - context.Response.ContentType = "text/html"; - await context.Response.WriteAsync(""); - await context.Response.WriteAsync("An remote failure has occurred: " + context.Request.Query["FailureMessage"] + "
"); - await context.Response.WriteAsync("Home"); - await context.Response.WriteAsync(""); + var response = context.Response; + response.ContentType = "text/html"; + await response.WriteAsync(""); + await response.WriteAsync("An remote failure has occurred: " + context.Request.Query["FailureMessage"] + "
"); + await response.WriteAsync("Home"); + await response.WriteAsync(""); }); }); app.Run(async context => { - // CookieAuthenticationOptions.AutomaticAuthenticate = true (default) causes User to be set + // Setting DefaultAuthenticateScheme causes User to be set var user = context.User; // This is what [Authorize] calls - // var user = await context.Authentication.AuthenticateAsync(AuthenticationManager.AutomaticScheme); + // var user = await context.AuthenticateAsync(); // This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls - // var user = await context.Authentication.AuthenticateAsync(MicrosoftAccountDefaults.AuthenticationScheme); + // 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 intercept this 401 and redirect to /login - await context.Authentication.ChallengeAsync(); + // The cookie middleware will handle this and redirect to /login + await context.ChallengeAsync(); // This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls - // await context.Authentication.ChallengeAsync(MicrosoftAccountDefaults.AuthenticationScheme); + // await context.ChallengeAsync(MicrosoftAccountDefaults.AuthenticationScheme); return; } // Display user information - context.Response.ContentType = "text/html"; - await context.Response.WriteAsync(""); - await context.Response.WriteAsync("Hello " + (context.User.Identity.Name ?? "anonymous") + "
"); + var response = context.Response; + response.ContentType = "text/html"; + await response.WriteAsync(""); + await response.WriteAsync("Hello " + (context.User.Identity.Name ?? "anonymous") + "
"); foreach (var claim in context.User.Claims) { - await context.Response.WriteAsync(claim.Type + ": " + claim.Value + "
"); + await response.WriteAsync(claim.Type + ": " + claim.Value + "
"); } - await context.Response.WriteAsync("Tokens:
"); - - await context.Response.WriteAsync("Access Token: " + await context.Authentication.GetTokenAsync("access_token") + "
"); - await context.Response.WriteAsync("Refresh Token: " + await context.Authentication.GetTokenAsync("refresh_token") + "
"); - await context.Response.WriteAsync("Token Type: " + await context.Authentication.GetTokenAsync("token_type") + "
"); - await context.Response.WriteAsync("expires_at: " + await context.Authentication.GetTokenAsync("expires_at") + "
"); - await context.Response.WriteAsync("Logout
"); - await context.Response.WriteAsync(""); + await response.WriteAsync("Tokens:
"); + + await response.WriteAsync("Access Token: " + await context.GetTokenAsync("access_token") + "
"); + await response.WriteAsync("Refresh Token: " + await context.GetTokenAsync("refresh_token") + "
"); + await response.WriteAsync("Token Type: " + await context.GetTokenAsync("token_type") + "
"); + await response.WriteAsync("expires_at: " + await context.GetTokenAsync("expires_at") + "
"); + await response.WriteAsync("Logout
"); + await response.WriteAsync("Refresh Token
"); + await response.WriteAsync(""); }); } + + private Task GetOAuthOptionsAsync(HttpContext context, string currentAuthType) + { + if (string.Equals(GoogleDefaults.AuthenticationScheme, currentAuthType)) + { + return Task.FromResult(context.RequestServices.GetRequiredService>().Get(currentAuthType)); + } + else if (string.Equals(MicrosoftAccountDefaults.AuthenticationScheme, currentAuthType)) + { + return Task.FromResult(context.RequestServices.GetRequiredService>().Get(currentAuthType)); + } + else if (string.Equals(FacebookDefaults.AuthenticationScheme, currentAuthType)) + { + return Task.FromResult(context.RequestServices.GetRequiredService>().Get(currentAuthType)); + } + + throw new NotImplementedException(currentAuthType); + } + + private async Task PrintRefreshedTokensAsync(HttpResponse response, JObject payload, AuthenticationProperties authProperties) + { + response.ContentType = "text/html"; + await response.WriteAsync(""); + await response.WriteAsync("Refreshed.
"); + await response.WriteAsync(HtmlEncoder.Default.Encode(payload.ToString()).Replace(",", ",
") + "
"); + + await response.WriteAsync("
Tokens:
"); + + await response.WriteAsync("Access Token: " + authProperties.GetTokenValue("access_token") + "
"); + await response.WriteAsync("Refresh Token: " + authProperties.GetTokenValue("refresh_token") + "
"); + await response.WriteAsync("Token Type: " + authProperties.GetTokenValue("token_type") + "
"); + await response.WriteAsync("expires_at: " + authProperties.GetTokenValue("expires_at") + "
"); + + await response.WriteAsync("Home
"); + await response.WriteAsync("Refresh Token
"); + await response.WriteAsync(""); + } } } diff --git a/samples/SocialSample/project.json b/samples/SocialSample/project.json deleted file mode 100644 index c1cf78b49..000000000 --- a/samples/SocialSample/project.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "dependencies": { - "Microsoft.AspNetCore.Authentication.Cookies": "1.2.0-*", - "Microsoft.AspNetCore.Authentication.Facebook": "1.2.0-*", - "Microsoft.AspNetCore.Authentication.Google": "1.2.0-*", - "Microsoft.AspNetCore.Authentication.MicrosoftAccount": "1.2.0-*", - "Microsoft.AspNetCore.Authentication.Twitter": "1.2.0-*", - "Microsoft.AspNetCore.DataProtection": "1.2.0-*", - "Microsoft.AspNetCore.Server.IISIntegration": "1.2.0-*", - "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", - "Microsoft.AspNetCore.Server.Kestrel.Https": "1.2.0-*", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.2.0-*", - "Microsoft.Extensions.Configuration.UserSecrets": "1.2.0-*", - "Microsoft.Extensions.FileProviders.Embedded": "1.2.0-*", - "Microsoft.Extensions.Logging.Console": "1.2.0-*" - }, - "buildOptions": { - "emitEntryPoint": true - }, - "frameworks": { - "net451": {}, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - } - }, - "userSecretsId": "aspnet5-SocialSample-20151210111056", - "publishOptions": { - "include": [ - "project.json", - "web.config" - ] - }, - "tools": { - "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-*" - }, - "scripts": { - "postpublish": "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" - } -} \ No newline at end of file diff --git a/samples/WsFedSample/Program.cs b/samples/WsFedSample/Program.cs new file mode 100644 index 000000000..40e1945c6 --- /dev/null +++ b/samples/WsFedSample/Program.cs @@ -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() + .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"); + } + } + } +} diff --git a/samples/WsFedSample/Properties/launchSettings.json b/samples/WsFedSample/Properties/launchSettings.json new file mode 100644 index 000000000..bdf80e248 --- /dev/null +++ b/samples/WsFedSample/Properties/launchSettings.json @@ -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" + } + } + } +} \ No newline at end of file diff --git a/samples/WsFedSample/Startup.cs b/samples/WsFedSample/Startup.cs new file mode 100644 index 000000000..0fc32769e --- /dev/null +++ b/samples/WsFedSample/Startup.cs @@ -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($"

You have been signed out.

"); + await res.WriteAsync("Sign In"); + }); + return; + } + + if (context.Request.Path.Equals("/signout")) + { + await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + await WriteHtmlAsync(context.Response, async res => + { + await context.Response.WriteAsync($"

Signed out {HtmlEncode(context.User.Identity.Name)}

"); + await context.Response.WriteAsync("Sign In"); + }); + 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($"

Access Denied for user {HtmlEncode(context.User.Identity.Name)} to resource '{HtmlEncode(context.Request.Query["ReturnUrl"])}'

"); + await context.Response.WriteAsync("Sign Out"); + }); + 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($"

Hello Authenticated User {HtmlEncode(user.Identity.Name)}

"); + await response.WriteAsync("Restricted"); + await response.WriteAsync("Sign Out"); + await response.WriteAsync("Sign Out Remote"); + + await response.WriteAsync("

Claims:

"); + 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 writeContent) + { + var bootstrap = ""; + + response.ContentType = "text/html"; + await response.WriteAsync($"{bootstrap}
"); + await writeContent(response); + await response.WriteAsync("
"); + } + + private static async Task WriteTableHeader(HttpResponse response, IEnumerable columns, IEnumerable> data) + { + await response.WriteAsync(""); + await response.WriteAsync(""); + foreach (var column in columns) + { + await response.WriteAsync($""); + } + await response.WriteAsync(""); + foreach (var row in data) + { + await response.WriteAsync(""); + foreach (var column in row) + { + await response.WriteAsync($""); + } + await response.WriteAsync(""); + } + await response.WriteAsync("
{HtmlEncode(column)}
{HtmlEncode(column)}
"); + } + + private static string HtmlEncode(string content) => + string.IsNullOrEmpty(content) ? string.Empty : HtmlEncoder.Default.Encode(content); + } +} diff --git a/samples/WsFedSample/WsFedSample.csproj b/samples/WsFedSample/WsFedSample.csproj new file mode 100644 index 000000000..e1191ac81 --- /dev/null +++ b/samples/WsFedSample/WsFedSample.csproj @@ -0,0 +1,27 @@ + + + + netcoreapp3.0 + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/WsFedSample/compiler/resources/cert.pfx b/samples/WsFedSample/compiler/resources/cert.pfx new file mode 100644 index 000000000..7118908c2 Binary files /dev/null and b/samples/WsFedSample/compiler/resources/cert.pfx differ diff --git a/src/Microsoft.AspNetCore.ChunkingCookieManager.Sources/ChunkingCookieManager.cs b/shared/Microsoft.AspNetCore.ChunkingCookieManager.Sources/ChunkingCookieManager.cs similarity index 96% rename from src/Microsoft.AspNetCore.ChunkingCookieManager.Sources/ChunkingCookieManager.cs rename to shared/Microsoft.AspNetCore.ChunkingCookieManager.Sources/ChunkingCookieManager.cs index 16426507c..42cc4e2f0 100644 --- a/src/Microsoft.AspNetCore.ChunkingCookieManager.Sources/ChunkingCookieManager.cs +++ b/shared/Microsoft.AspNetCore.ChunkingCookieManager.Sources/ChunkingCookieManager.cs @@ -33,7 +33,7 @@ internal class ChunkingCookieManager /// /// The default maximum size of characters in a cookie to send back to the client. /// - public const int DefaultChunkSize = 4070; + public const int DefaultChunkSize = 4050; private const string ChunkKeySuffix = "C"; private const string ChunkCountPrefix = "chunks-"; @@ -42,9 +42,8 @@ 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 20 in case CookiePolicy tries to add 'secure' and/or 'httponly'. + // Leave at least 40 in case CookiePolicy tries to add 'secure', 'samesite=strict' and/or 'httponly'. ChunkSize = DefaultChunkSize; - ThrowForPartialCookies = true; } /// @@ -166,6 +165,7 @@ public void AppendResponseCookie(HttpContext context, string key, string value, { Domain = options.Domain, Expires = options.Expires, + SameSite = (Net.Http.Headers.SameSiteMode)options.SameSite, HttpOnly = options.HttpOnly, Path = options.Path, Secure = options.Secure, @@ -284,6 +284,8 @@ public void DeleteCookie(HttpContext context, string key, CookieOptions options) { Path = options.Path, Domain = options.Domain, + SameSite = options.SameSite, + IsEssential = options.IsEssential, Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), }); @@ -297,6 +299,8 @@ public void DeleteCookie(HttpContext context, string key, CookieOptions options) { Path = options.Path, Domain = options.Domain, + SameSite = options.SameSite, + IsEssential = options.IsEssential, Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), }); } diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 000000000..1e0980f66 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAppBuilderExtensions.cs index 765d1f51c..bdfd43c79 100644 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAppBuilderExtensions.cs @@ -1,9 +1,8 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Builder { @@ -13,38 +12,26 @@ namespace Microsoft.AspNetCore.Builder public static class CookieAppBuilderExtensions { /// - /// Adds the middleware to the specified , which enables cookie authentication capabilities. + /// UseCookieAuthentication is obsolete. Configure Cookie authentication with AddAuthentication().AddCookie in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. + /// The to add the handler to. /// A reference to this instance after the operation has completed. + [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) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - - return app.UseMiddleware(); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } /// - /// Adds the middleware to the specified , which enables cookie authentication capabilities. + /// UseCookieAuthentication is obsolete. Configure Cookie authentication with AddAuthentication().AddCookie in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. - /// A that specifies options for the middleware. + /// The to add the handler to. + /// A that specifies options for the handler. /// A reference to this instance after the operation has completed. + [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) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - return app.UseMiddleware(Options.Create(options)); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationDefaults.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationDefaults.cs index ad0e17a09..700b60797 100644 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationDefaults.cs +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationDefaults.cs @@ -6,7 +6,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies { /// - /// Default values related to cookie-based authentication middleware + /// Default values related to cookie-based authentication handler /// public static class CookieAuthenticationDefaults { diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationHandler.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationHandler.cs index 1f2b395b1..ff6bb3cbc 100644 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationHandler.cs @@ -1,31 +1,61 @@ // 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.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Http.Features.Authentication; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Authentication.Cookies { - internal class CookieAuthenticationHandler : AuthenticationHandler + public class CookieAuthenticationHandler : SignInAuthenticationHandler { private const string HeaderValueNoCache = "no-cache"; - private const string HeaderValueMinusOne = "-1"; + 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 _readCookieTask; + private AuthenticationTicket _refreshTicket; + + public CookieAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) + : base(options, logger, encoder, clock) + { } + + /// + /// 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. + /// + 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; + } + + /// + /// Creates a new instance of the events instance. + /// + /// A new instance of the events instance. + protected override Task CreateEventsAsync() => Task.FromResult(new CookieAuthenticationEvents()); private Task EnsureCookieTicket() { @@ -39,7 +69,7 @@ private Task EnsureCookieTicket() private void CheckForRefresh(AuthenticationTicket ticket) { - var currentUtc = Options.SystemClock.UtcNow; + var currentUtc = Clock.UtcNow; var issuedUtc = ticket.Properties.IssuedUtc; var expiresUtc = ticket.Properties.ExpiresUtc; var allowRefresh = ticket.Properties.AllowRefresh ?? true; @@ -55,7 +85,7 @@ private void CheckForRefresh(AuthenticationTicket ticket) } } - private void RequestRefresh(AuthenticationTicket ticket) + private void RequestRefresh(AuthenticationTicket ticket, ClaimsPrincipal replacedPrincipal = null) { var issuedUtc = ticket.Properties.IssuedUtc; var expiresUtc = ticket.Properties.ExpiresUtc; @@ -63,19 +93,38 @@ private void RequestRefresh(AuthenticationTicket ticket) if (issuedUtc != null && expiresUtc != null) { _shouldRefresh = true; - var currentUtc = Options.SystemClock.UtcNow; + 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 ReadCookieTicket() { - var cookie = Options.CookieManager.GetRequestCookie(Context, Options.CookieName); + var cookie = Options.CookieManager.GetRequestCookie(Context, Options.Cookie.Name); if (string.IsNullOrEmpty(cookie)) { - return AuthenticateResult.Skip(); + return AuthenticateResult.NoResult(); } var ticket = Options.TicketDataFormat.Unprotect(cookie, GetTlsTokenBinding()); @@ -99,8 +148,7 @@ private async Task ReadCookieTicket() } } - var currentUtc = Options.SystemClock.UtcNow; - var issuedUtc = ticket.Properties.IssuedUtc; + var currentUtc = Clock.UtcNow; var expiresUtc = ticket.Properties.ExpiresUtc; if (expiresUtc != null && expiresUtc.Value < currentUtc) @@ -126,8 +174,8 @@ protected override async Task HandleAuthenticateAsync() return result; } - var context = new CookieValidatePrincipalContext(Context, result.Ticket, Options); - await Options.Events.ValidatePrincipal(context); + var context = new CookieValidatePrincipalContext(Context, Scheme, Options, result.Ticket); + await Events.ValidatePrincipal(context); if (context.Principal == null) { @@ -136,42 +184,30 @@ protected override async Task HandleAuthenticateAsync() if (context.ShouldRenew) { - RequestRefresh(result.Ticket); + RequestRefresh(result.Ticket, context.Principal); } - return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme)); + return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name)); } private CookieOptions BuildCookieOptions() { - var cookieOptions = new CookieOptions - { - Domain = Options.CookieDomain, - HttpOnly = Options.CookieHttpOnly, - Path = Options.CookiePath ?? (OriginalPathBase.HasValue ? OriginalPathBase.ToString() : "/"), - }; - - if (Options.CookieSecure == CookieSecurePolicy.SameAsRequest) - { - cookieOptions.Secure = Request.IsHttps; - } - else - { - cookieOptions.Secure = Options.CookieSecure == CookieSecurePolicy.Always; - } + var cookieOptions = Options.Cookie.Build(Context); + // ignore the 'Expires' value as this will be computed elsewhere + cookieOptions.Expires = null; return cookieOptions; } - protected override async Task FinishResponseAsync() + protected virtual async Task FinishResponseAsync() { // Only renew if requested, and neither sign in or sign out was called - if (!_shouldRefresh || SignInAccepted || SignOutAccepted) + if (!_shouldRefresh || _signInCalled || _signOutCalled) { return; } - var ticket = (await HandleAuthenticateOnceSafeAsync())?.Ticket; + var ticket = _refreshTicket; if (ticket != null) { var properties = ticket.Properties; @@ -192,8 +228,8 @@ protected override async Task FinishResponseAsync() var principal = new ClaimsPrincipal( new ClaimsIdentity( new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) }, - Options.AuthenticationScheme)); - ticket = new AuthenticationTicket(principal, null, Options.AuthenticationScheme); + Scheme.Name)); + ticket = new AuthenticationTicket(principal, null, Scheme.Name); } var cookieValue = Options.TicketDataFormat.Protect(ticket, GetTlsTokenBinding()); @@ -206,7 +242,7 @@ protected override async Task FinishResponseAsync() Options.CookieManager.AppendResponseCookie( Context, - Options.CookieName, + Options.Cookie.Name, cookieValue, cookieOptions); @@ -214,18 +250,27 @@ protected override async Task FinishResponseAsync() } } - protected override async Task HandleSignInAsync(SignInContext signin) + 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. - var result = await EnsureCookieTicket(); + await EnsureCookieTicket(); var cookieOptions = BuildCookieOptions(); var signInContext = new CookieSigningInContext( Context, + Scheme, Options, - Options.AuthenticationScheme, - signin.Principal, - new AuthenticationProperties(signin.Properties), + user, + properties, cookieOptions); DateTimeOffset issuedUtc; @@ -235,7 +280,7 @@ protected override async Task HandleSignInAsync(SignInContext signin) } else { - issuedUtc = Options.SystemClock.UtcNow; + issuedUtc = Clock.UtcNow; signInContext.Properties.IssuedUtc = issuedUtc; } @@ -244,7 +289,7 @@ protected override async Task HandleSignInAsync(SignInContext signin) signInContext.Properties.ExpiresUtc = issuedUtc.Add(Options.ExpireTimeSpan); } - await Options.Events.SigningIn(signInContext); + await Events.SigningIn(signInContext); if (signInContext.Properties.IsPersistent) { @@ -252,7 +297,8 @@ protected override async Task HandleSignInAsync(SignInContext signin) signInContext.CookieOptions.Expires = expiresUtc.ToUniversalTime(); } - var ticket = new AuthenticationTicket(signInContext.Principal, signInContext.Properties, signInContext.AuthenticationScheme); + var ticket = new AuthenticationTicket(signInContext.Principal, signInContext.Properties, signInContext.Scheme.Name); + if (Options.SessionStore != null) { if (_sessionKey != null) @@ -264,35 +310,41 @@ protected override async Task HandleSignInAsync(SignInContext signin) new ClaimsIdentity( new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) }, Options.ClaimsIssuer)); - ticket = new AuthenticationTicket(principal, null, Options.AuthenticationScheme); + ticket = new AuthenticationTicket(principal, null, Scheme.Name); } var cookieValue = Options.TicketDataFormat.Protect(ticket, GetTlsTokenBinding()); Options.CookieManager.AppendResponseCookie( Context, - Options.CookieName, + Options.Cookie.Name, cookieValue, signInContext.CookieOptions); var signedInContext = new CookieSignedInContext( Context, - Options, - Options.AuthenticationScheme, + Scheme, signInContext.Principal, - signInContext.Properties); + signInContext.Properties, + Options); - await Options.Events.SignedIn(signedInContext); + 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 override async Task HandleSignOutAsync(SignOutContext signOutContext) + protected async override Task HandleSignOutAsync(AuthenticationProperties properties) { + properties = properties ?? new AuthenticationProperties(); + + _signOutCalled = true; + // Process the request cookie to initialize members like _sessionKey. - var ticket = await EnsureCookieTicket(); + await EnsureCookieTicket(); var cookieOptions = BuildCookieOptions(); if (Options.SessionStore != null && _sessionKey != null) { @@ -301,27 +353,30 @@ protected override async Task HandleSignOutAsync(SignOutContext signOutContext) var context = new CookieSigningOutContext( Context, + Scheme, Options, - new AuthenticationProperties(signOutContext.Properties), + properties, cookieOptions); - await Options.Events.SigningOut(context); + await Events.SigningOut(context); Options.CookieManager.DeleteCookie( Context, - Options.CookieName, + 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] = HeaderValueMinusOne; + Response.Headers[HeaderNames.Expires] = HeaderValueEpocDate; if (shouldRedirectToReturnUrl && Response.StatusCode == 200) { @@ -343,8 +398,8 @@ private async Task ApplyHeaders(bool shouldRedirectToReturnUrl, AuthenticationPr if (redirectUri != null) { - await Options.Events.RedirectToReturnUrl( - new CookieRedirectContext(Context, Options, redirectUri, properties)); + await Events.RedirectToReturnUrl( + new RedirectContext(Context, Scheme, Options, properties, redirectUri)); } } } @@ -362,39 +417,29 @@ private static bool IsHostRelative(string path) return path[0] == '/' && path[1] != '/' && path[1] != '\\'; } - protected override async Task HandleForbiddenAsync(ChallengeContext context) + protected override async Task HandleForbiddenAsync(AuthenticationProperties properties) { - var properties = new AuthenticationProperties(context.Properties); var returnUrl = properties.RedirectUri; if (string.IsNullOrEmpty(returnUrl)) { - returnUrl = OriginalPathBase + Request.Path + Request.QueryString; + returnUrl = OriginalPathBase + OriginalPath + Request.QueryString; } var accessDeniedUri = Options.AccessDeniedPath + QueryString.Create(Options.ReturnUrlParameter, returnUrl); - var redirectContext = new CookieRedirectContext(Context, Options, BuildRedirectUri(accessDeniedUri), properties); - await Options.Events.RedirectToAccessDenied(redirectContext); - return true; + var redirectContext = new RedirectContext(Context, Scheme, Options, properties, BuildRedirectUri(accessDeniedUri)); + await Events.RedirectToAccessDenied(redirectContext); } - protected override async Task HandleUnauthorizedAsync(ChallengeContext context) + protected override async Task HandleChallengeAsync(AuthenticationProperties properties) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - var properties = new AuthenticationProperties(context.Properties); var redirectUri = properties.RedirectUri; if (string.IsNullOrEmpty(redirectUri)) { - redirectUri = OriginalPathBase + Request.Path + Request.QueryString; + redirectUri = OriginalPathBase + OriginalPath + Request.QueryString; } var loginUri = Options.LoginPath + QueryString.Create(Options.ReturnUrlParameter, redirectUri); - var redirectContext = new CookieRedirectContext(Context, Options, BuildRedirectUri(loginUri), properties); - await Options.Events.RedirectToLogin(redirectContext); - return true; - + var redirectContext = new RedirectContext(Context, Scheme, Options, properties, BuildRedirectUri(loginUri)); + await Events.RedirectToLogin(redirectContext); } private string GetTlsTokenBinding() diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationMiddleware.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationMiddleware.cs deleted file mode 100644 index 14d152a81..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationMiddleware.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Text.Encodings.Web; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.DataProtection; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace Microsoft.AspNetCore.Authentication.Cookies -{ - public class CookieAuthenticationMiddleware : AuthenticationMiddleware - { - public CookieAuthenticationMiddleware( - RequestDelegate next, - IDataProtectionProvider dataProtectionProvider, - ILoggerFactory loggerFactory, - UrlEncoder urlEncoder, - IOptions options) - : base(next, options, loggerFactory, urlEncoder) - { - if (dataProtectionProvider == null) - { - throw new ArgumentNullException(nameof(dataProtectionProvider)); - } - - if (Options.Events == null) - { - Options.Events = new CookieAuthenticationEvents(); - } - if (String.IsNullOrEmpty(Options.CookieName)) - { - Options.CookieName = CookieAuthenticationDefaults.CookiePrefix + Options.AuthenticationScheme; - } - if (Options.TicketDataFormat == null) - { - var provider = Options.DataProtectionProvider ?? dataProtectionProvider; - var dataProtector = provider.CreateProtector(typeof(CookieAuthenticationMiddleware).FullName, Options.AuthenticationScheme, "v2"); - Options.TicketDataFormat = new TicketDataFormat(dataProtector); - } - if (Options.CookieManager == null) - { - Options.CookieManager = new ChunkingCookieManager(); - } - if (!Options.LoginPath.HasValue) - { - Options.LoginPath = CookieAuthenticationDefaults.LoginPath; - } - if (!Options.LogoutPath.HasValue) - { - Options.LogoutPath = CookieAuthenticationDefaults.LogoutPath; - } - if (!Options.AccessDeniedPath.HasValue) - { - Options.AccessDeniedPath = CookieAuthenticationDefaults.AccessDeniedPath; - } - } - - protected override AuthenticationHandler CreateHandler() - { - return new CookieAuthenticationHandler(); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationOptions.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationOptions.cs index b42561250..78156caec 100644 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationOptions.cs +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationOptions.cs @@ -2,139 +2,123 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.ComponentModel; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authentication.Internal; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Options; -namespace Microsoft.AspNetCore.Builder +namespace Microsoft.AspNetCore.Authentication.Cookies { /// - /// Configuration options for . + /// Configuration options for . /// - public class CookieAuthenticationOptions : AuthenticationOptions, IOptions + public class CookieAuthenticationOptions : AuthenticationSchemeOptions { - private string _cookieName; + 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, + }; /// /// Create an instance of the options initialized with the default values /// public CookieAuthenticationOptions() { - AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme; - AutomaticAuthenticate = true; - ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter; ExpireTimeSpan = TimeSpan.FromDays(14); + ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter; SlidingExpiration = true; - CookieHttpOnly = true; - CookieSecure = CookieSecurePolicy.SameAsRequest; - SystemClock = new SystemClock(); Events = new CookieAuthenticationEvents(); } /// - /// 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 middleware multiple times. + /// + /// Determines the settings used to create the cookie. + /// + /// + /// defaults to . + /// defaults to true. + /// defaults to . + /// /// - public string CookieName + /// + /// + /// 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. + /// + /// + /// 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. + /// + /// + /// 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. + /// + /// + /// is currently ignored. Use to control lifetime of cookie authentication. + /// + /// + public CookieBuilder Cookie { - get { return _cookieName; } - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - _cookieName = value; - } + get => _cookieBuilder; + set => _cookieBuilder = value ?? throw new ArgumentNullException(nameof(value)); } /// - /// Determines the domain used to create the cookie. Is not provided by default. - /// - public string CookieDomain { get; set; } - - /// - /// Determines the path used to create the cookie. The default value is "/" for highest browser compatibility. - /// - public string CookiePath { get; set; } - - /// - /// 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. - /// - public bool CookieHttpOnly { get; set; } - - /// - /// 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. - /// - public CookieSecurePolicy CookieSecure { get; set; } - - /// - /// If set this will be used by the CookieAuthenticationMiddleware for data protection. + /// If set this will be used by the CookieAuthenticationHandler for data protection. /// public IDataProtectionProvider DataProtectionProvider { get; set; } /// - /// Controls how much time the cookie will remain valid from the point it is created. The expiration - /// information is 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 - /// - public TimeSpan ExpireTimeSpan { get; set; } - - /// - /// The SlidingExpiration is set to true to instruct the middleware to re-issue a new cookie with a new + /// The SlidingExpiration is set to true to instruct the handler to re-issue a new cookie with a new /// expiration time any time it processes a request which is more than halfway through the expiration window. /// public bool SlidingExpiration { get; set; } /// - /// The LoginPath property informs the middleware that it should change an outgoing 401 Unauthorized status - /// code into a 302 redirection onto the given login path. The current url which generated the 401 is added - /// 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 url which caused the original unauthorized status code. + /// 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. /// public PathString LoginPath { get; set; } /// - /// If the LogoutPath is provided the middleware then a request to that path will redirect based on the ReturnUrlParameter. + /// If the LogoutPath is provided the handler then a request to that path will redirect based on the ReturnUrlParameter. /// public PathString LogoutPath { get; set; } /// - /// The AccessDeniedPath property informs the middleware that it should change an outgoing 403 Forbidden status - /// code into a 302 redirection onto the given path. + /// The AccessDeniedPath property is used by the handler for the redirection target when handling ForbidAsync. /// public PathString AccessDeniedPath { get; set; } /// - /// The ReturnUrlParameter determines the name of the query string parameter which is appended by the middleware - /// when a 401 Unauthorized status code is changed to a 302 redirect onto the login path. This is also the query - /// string parameter looked for when a request arrives on the login path or logout path, in order to return to the - /// original url after the action is performed. + /// 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. /// public string ReturnUrlParameter { get; set; } /// - /// The Provider may be assigned to an instance of an object created by the application at startup time. The middleware - /// calls methods on the provider which give the application control at certain points where processing is occurring. + /// 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. /// - public ICookieAuthenticationEvents Events { get; set; } + public new CookieAuthenticationEvents Events + { + get => (CookieAuthenticationEvents)base.Events; + set => base.Events = value; + } /// /// The TicketDataFormat is used to protect and unprotect the identity and other properties which are stored in the - /// cookie value. If it is not provided a default data handler is created using the data protection service contained - /// in the IApplicationBuilder.Properties. The default data protection service is based on machine key when running on ASP.NET, - /// and on DPAPI when running in a different process. + /// cookie value. If not provided one will be created using . /// public ISecureDataFormat TicketDataFormat { get; set; } @@ -151,12 +135,17 @@ public string CookieName /// public ITicketStore SessionStore { get; set; } - CookieAuthenticationOptions IOptions.Value - { - get - { - return this; - } - } + /// + /// + /// 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. + /// + /// + /// This is separate from the value of , which specifies + /// how long the browser will keep the cookie. + /// + /// + public TimeSpan ExpireTimeSpan { get; set; } } } diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/CookieExtensions.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/CookieExtensions.cs new file mode 100644 index 000000000..4c41f54a9 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/CookieExtensions.cs @@ -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 configureOptions) + => builder.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, configureOptions); + + public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, string authenticationScheme, Action configureOptions) + => builder.AddCookie(authenticationScheme, displayName: null, configureOptions: configureOptions); + + public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions) + { + builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton, PostConfigureCookieAuthenticationOptions>()); + return builder.AddScheme(authenticationScheme, displayName, configureOptions); + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/BaseCookieContext.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/BaseCookieContext.cs deleted file mode 100644 index e5423fed2..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/BaseCookieContext.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Authentication.Cookies -{ - public class BaseCookieContext : BaseContext - { - public BaseCookieContext( - HttpContext context, - CookieAuthenticationOptions options) - : base(context) - { - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - Options = options; - } - - public CookieAuthenticationOptions Options { get; } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieAuthenticationEvents.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieAuthenticationEvents.cs index 4364a2e54..2b8b0416b 100644 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieAuthenticationEvents.cs +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieAuthenticationEvents.cs @@ -4,7 +4,6 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Authentication.Cookies { @@ -13,32 +12,32 @@ namespace Microsoft.AspNetCore.Authentication.Cookies /// application only needs to override a few of the interface methods. This may be used as a base class /// or may be instantiated directly. /// - public class CookieAuthenticationEvents : ICookieAuthenticationEvents + public class CookieAuthenticationEvents { /// /// A delegate assigned to this property will be invoked when the related method is called. /// - public Func OnValidatePrincipal { get; set; } = context => TaskCache.CompletedTask; + public Func OnValidatePrincipal { get; set; } = context => Task.CompletedTask; /// /// A delegate assigned to this property will be invoked when the related method is called. /// - public Func OnSigningIn { get; set; } = context => TaskCache.CompletedTask; + public Func OnSigningIn { get; set; } = context => Task.CompletedTask; /// /// A delegate assigned to this property will be invoked when the related method is called. /// - public Func OnSignedIn { get; set; } = context => TaskCache.CompletedTask; + public Func OnSignedIn { get; set; } = context => Task.CompletedTask; /// /// A delegate assigned to this property will be invoked when the related method is called. /// - public Func OnSigningOut { get; set; } = context => TaskCache.CompletedTask; + public Func OnSigningOut { get; set; } = context => Task.CompletedTask; /// /// A delegate assigned to this property will be invoked when the related method is called. /// - public Func OnRedirectToLogin { get; set; } = context => + public Func, Task> OnRedirectToLogin { get; set; } = context => { if (IsAjaxRequest(context.Request)) { @@ -49,13 +48,13 @@ public class CookieAuthenticationEvents : ICookieAuthenticationEvents { context.Response.Redirect(context.RedirectUri); } - return TaskCache.CompletedTask; + return Task.CompletedTask; }; /// /// A delegate assigned to this property will be invoked when the related method is called. /// - public Func OnRedirectToAccessDenied { get; set; } = context => + public Func, Task> OnRedirectToAccessDenied { get; set; } = context => { if (IsAjaxRequest(context.Request)) { @@ -66,13 +65,13 @@ public class CookieAuthenticationEvents : ICookieAuthenticationEvents { context.Response.Redirect(context.RedirectUri); } - return TaskCache.CompletedTask; + return Task.CompletedTask; }; /// /// A delegate assigned to this property will be invoked when the related method is called. /// - public Func OnRedirectToLogout { get; set; } = context => + public Func, Task> OnRedirectToLogout { get; set; } = context => { if (IsAjaxRequest(context.Request)) { @@ -82,13 +81,13 @@ public class CookieAuthenticationEvents : ICookieAuthenticationEvents { context.Response.Redirect(context.RedirectUri); } - return TaskCache.CompletedTask; + return Task.CompletedTask; }; /// /// A delegate assigned to this property will be invoked when the related method is called. /// - public Func OnRedirectToReturnUrl { get; set; } = context => + public Func, Task> OnRedirectToReturnUrl { get; set; } = context => { if (IsAjaxRequest(context.Request)) { @@ -98,7 +97,7 @@ public class CookieAuthenticationEvents : ICookieAuthenticationEvents { context.Response.Redirect(context.RedirectUri); } - return TaskCache.CompletedTask; + return Task.CompletedTask; }; private static bool IsAjaxRequest(HttpRequest request) @@ -136,24 +135,24 @@ private static bool IsAjaxRequest(HttpRequest request) /// Implements the interface method by invoking the related delegate method. /// /// Contains information about the event - public virtual Task RedirectToLogout(CookieRedirectContext context) => OnRedirectToLogout(context); + public virtual Task RedirectToLogout(RedirectContext context) => OnRedirectToLogout(context); /// /// Implements the interface method by invoking the related delegate method. /// /// Contains information about the event - public virtual Task RedirectToLogin(CookieRedirectContext context) => OnRedirectToLogin(context); + public virtual Task RedirectToLogin(RedirectContext context) => OnRedirectToLogin(context); /// /// Implements the interface method by invoking the related delegate method. /// /// Contains information about the event - public virtual Task RedirectToReturnUrl(CookieRedirectContext context) => OnRedirectToReturnUrl(context); + public virtual Task RedirectToReturnUrl(RedirectContext context) => OnRedirectToReturnUrl(context); /// /// Implements the interface method by invoking the related delegate method. /// /// Contains information about the event - public virtual Task RedirectToAccessDenied(CookieRedirectContext context) => OnRedirectToAccessDenied(context); + public virtual Task RedirectToAccessDenied(RedirectContext context) => OnRedirectToAccessDenied(context); } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSignedInContext.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSignedInContext.cs index cfb7c5f1d..98c31dd19 100644 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSignedInContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSignedInContext.cs @@ -2,51 +2,32 @@ // 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.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; namespace Microsoft.AspNetCore.Authentication.Cookies { /// /// Context object passed to the ICookieAuthenticationEvents method SignedIn. /// - public class CookieSignedInContext : BaseCookieContext + public class CookieSignedInContext : PrincipalContext { /// /// Creates a new instance of the context object. /// /// The HTTP request context - /// The middleware options - /// Initializes AuthenticationScheme property + /// The scheme data /// Initializes Principal property /// Initializes Properties property + /// The handler options public CookieSignedInContext( HttpContext context, - CookieAuthenticationOptions options, - string authenticationScheme, + AuthenticationScheme scheme, ClaimsPrincipal principal, - AuthenticationProperties properties) - : base(context, options) + AuthenticationProperties properties, + CookieAuthenticationOptions options) + : base(context, scheme, options, properties) { - AuthenticationScheme = authenticationScheme; Principal = principal; - Properties = properties; } - - /// - /// The name of the AuthenticationScheme creating a cookie - /// - public string AuthenticationScheme { get; } - - /// - /// Contains the claims that were converted into the outgoing cookie. - /// - public ClaimsPrincipal Principal { get; } - - /// - /// Contains the extra data that was contained in the outgoing cookie. - /// - public AuthenticationProperties Properties { get; } } } diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSigningInContext.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSigningInContext.cs index d8b2307f3..41d7b4f6a 100644 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSigningInContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSigningInContext.cs @@ -2,58 +2,37 @@ // 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.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; namespace Microsoft.AspNetCore.Authentication.Cookies { /// - /// Context object passed to the ICookieAuthenticationEvents method SigningIn. + /// Context object passed to the . /// - public class CookieSigningInContext : BaseCookieContext + public class CookieSigningInContext : PrincipalContext { /// /// Creates a new instance of the context object. /// /// The HTTP request context - /// The middleware options - /// Initializes AuthenticationScheme property + /// The scheme data + /// The handler options /// Initializes Principal property - /// Initializes Extra property + /// The authentication properties. /// Initializes options for the authentication cookie. public CookieSigningInContext( HttpContext context, + AuthenticationScheme scheme, CookieAuthenticationOptions options, - string authenticationScheme, ClaimsPrincipal principal, AuthenticationProperties properties, CookieOptions cookieOptions) - : base(context, options) + : base(context, scheme, options, properties) { - AuthenticationScheme = authenticationScheme; - Principal = principal; - Properties = properties; CookieOptions = cookieOptions; + Principal = principal; } - /// - /// The name of the AuthenticationScheme creating a cookie - /// - public string AuthenticationScheme { get; } - - /// - /// Contains the claims about to be converted into the outgoing cookie. - /// May be replaced or altered during the SigningIn call. - /// - public ClaimsPrincipal Principal { get; set; } - - /// - /// Contains the extra data about to be contained in the outgoing cookie. - /// May be replaced or altered during the SigningIn call. - /// - public AuthenticationProperties Properties { get; set; } - /// /// The options for creating the outgoing cookie. /// May be replace or altered during the SigningIn call. diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSigningOutContext.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSigningOutContext.cs index 51c04a56b..34f6e49ab 100644 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSigningOutContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSigningOutContext.cs @@ -1,41 +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.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; namespace Microsoft.AspNetCore.Authentication.Cookies { /// - /// Context object passed to the ICookieAuthenticationEvents method SigningOut + /// Context object passed to the /// - public class CookieSigningOutContext : BaseCookieContext + public class CookieSigningOutContext : PropertiesContext { /// /// /// /// + /// /// /// /// public CookieSigningOutContext( - HttpContext context, + HttpContext context, + AuthenticationScheme scheme, CookieAuthenticationOptions options, AuthenticationProperties properties, CookieOptions cookieOptions) - : base(context, options) - { - CookieOptions = cookieOptions; - Properties = properties; - } + : base(context, scheme, options, properties) + => CookieOptions = cookieOptions; /// /// The options for creating the outgoing cookie. /// May be replace or altered during the SigningOut call. /// public CookieOptions CookieOptions { get; set; } - - public AuthenticationProperties Properties { get; set; } } } diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieValidatePrincipalContext.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieValidatePrincipalContext.cs index 57a28191c..d2161e42a 100644 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieValidatePrincipalContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieValidatePrincipalContext.cs @@ -3,56 +3,33 @@ using System; using System.Security.Claims; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; namespace Microsoft.AspNetCore.Authentication.Cookies { /// - /// Context object passed to the ICookieAuthenticationProvider method ValidatePrincipal. + /// Context object passed to the CookieAuthenticationEvents ValidatePrincipal method. /// - public class CookieValidatePrincipalContext : BaseCookieContext + public class CookieValidatePrincipalContext : PrincipalContext { /// /// Creates a new instance of the context object. /// /// + /// /// Contains the initial values for identity and extra data /// - public CookieValidatePrincipalContext(HttpContext context, AuthenticationTicket ticket, CookieAuthenticationOptions options) - : base(context, options) + public CookieValidatePrincipalContext(HttpContext context, AuthenticationScheme scheme, CookieAuthenticationOptions options, AuthenticationTicket ticket) + : base(context, scheme, options, ticket?.Properties) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - if (ticket == null) { throw new ArgumentNullException(nameof(ticket)); } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - Principal = ticket.Principal; - Properties = ticket.Properties; } - /// - /// Contains the claims principal arriving with the request. May be altered to change the - /// details of the authenticated user. - /// - public ClaimsPrincipal Principal { get; private set; } - - /// - /// Contains the extra meta-data arriving with the request ticket. May be altered. - /// - public AuthenticationProperties Properties { get; private set; } - /// /// If true, the cookie will be renewed /// @@ -63,18 +40,12 @@ public CookieValidatePrincipalContext(HttpContext context, AuthenticationTicket /// Principal property, which determines the identity of the authenticated request. /// /// The used as the replacement - public void ReplacePrincipal(ClaimsPrincipal principal) - { - Principal = principal; - } + public void ReplacePrincipal(ClaimsPrincipal principal) => Principal = principal; /// /// 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. /// - public void RejectPrincipal() - { - Principal = null; - } + public void RejectPrincipal() => Principal = null; } } diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/ICookieAuthenticationEvents.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/ICookieAuthenticationEvents.cs deleted file mode 100644 index 1406d872d..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/ICookieAuthenticationEvents.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Authentication.Cookies -{ - /// - /// Specifies callback methods which the invokes to enable developer control over the authentication process. /> - /// - public interface ICookieAuthenticationEvents - { - /// - /// Called each time a request principal has been validated by the middleware. By implementing this method the - /// application may alter or reject the principal which has arrived with the request. - /// - /// Contains information about the login session as well as the user . - /// A representing the completed operation. - Task ValidatePrincipal(CookieValidatePrincipalContext context); - - /// - /// Called when an endpoint has provided sign in information before it is converted into a cookie. By - /// implementing this method the claims and extra information that go into the ticket may be altered. - /// - /// Contains information about the login session as well as the user . - Task SigningIn(CookieSigningInContext context); - - /// - /// Called when an endpoint has provided sign in information after it is converted into a cookie. - /// - /// Contains information about the login session as well as the user . - Task SignedIn(CookieSignedInContext context); - - /// - /// Called when a SignOut causes a redirect in the cookie middleware. - /// - /// Contains information about the event - Task RedirectToLogout(CookieRedirectContext context); - - /// - /// Called when a SignIn causes a redirect in the cookie middleware. - /// - /// Contains information about the event - Task RedirectToLogin(CookieRedirectContext context); - - /// - /// Called when redirecting back to the return url in the cookie middleware. - /// - /// Contains information about the event - Task RedirectToReturnUrl(CookieRedirectContext context); - - /// - /// Called when an access denied causes a redirect in the cookie middleware. - /// - /// Contains information about the event - Task RedirectToAccessDenied(CookieRedirectContext context); - - /// - /// Called during the sign-out flow to augment the cookie cleanup process. - /// - /// Contains information about the login session as well as information about the authentication cookie. - Task SigningOut(CookieSigningOutContext context); - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/LoggingExtensions.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/LoggingExtensions.cs new file mode 100644 index 000000000..d12735443 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/LoggingExtensions.cs @@ -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 _authSchemeSignedIn; + private static Action _authSchemeSignedOut; + + static LoggingExtensions() + { + _authSchemeSignedIn = LoggerMessage.Define( + eventId: 10, + logLevel: LogLevel.Information, + formatString: "AuthenticationScheme: {AuthenticationScheme} signed in."); + _authSchemeSignedOut = LoggerMessage.Define( + 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); + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/Microsoft.AspNetCore.Authentication.Cookies.csproj b/src/Microsoft.AspNetCore.Authentication.Cookies/Microsoft.AspNetCore.Authentication.Cookies.csproj new file mode 100644 index 000000000..093f60a3d --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/Microsoft.AspNetCore.Authentication.Cookies.csproj @@ -0,0 +1,20 @@ + + + + ASP.NET Core middleware that enables an application to use cookie based authentication. + netcoreapp3.0 + $(DefineConstants);SECURITY + $(NoWarn);CS1591 + true + aspnetcore;authentication;security + + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/Microsoft.AspNetCore.Authentication.Cookies.xproj b/src/Microsoft.AspNetCore.Authentication.Cookies/Microsoft.AspNetCore.Authentication.Cookies.xproj deleted file mode 100644 index 238c0cec6..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/Microsoft.AspNetCore.Authentication.Cookies.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - fc152cc4-054b-457e-8d91-389c5de3c561 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/PostConfigureCookieAuthenticationOptions.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/PostConfigureCookieAuthenticationOptions.cs new file mode 100644 index 000000000..48895072e --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/PostConfigureCookieAuthenticationOptions.cs @@ -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 +{ + /// + /// Used to setup defaults for all . + /// + public class PostConfigureCookieAuthenticationOptions : IPostConfigureOptions + { + private readonly IDataProtectionProvider _dp; + + public PostConfigureCookieAuthenticationOptions(IDataProtectionProvider dataProtection) + { + _dp = dataProtection; + } + + /// + /// Invoked to post configure a TOptions instance. + /// + /// The name of the options instance being configured. + /// The options instance to configure. + 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; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Authentication.Cookies/Properties/Resources.Designer.cs deleted file mode 100644 index e2719f39d..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/Properties/Resources.Designer.cs +++ /dev/null @@ -1,62 +0,0 @@ -// -namespace Microsoft.AspNetCore.Authentication.Cookies -{ - using System.Globalization; - using System.Reflection; - using System.Resources; - - internal static class Resources - { - private static readonly ResourceManager _resourceManager - = new ResourceManager("Microsoft.AspNetCore.Authentication.Cookies.Resources", typeof(Resources).GetTypeInfo().Assembly); - - /// - /// The cookie key and options are larger than ChunksSize, leaving no room for data. - /// - internal static string Exception_CookieLimitTooSmall - { - get { return GetString("Exception_CookieLimitTooSmall"); } - } - - /// - /// The cookie key and options are larger than ChunksSize, leaving no room for data. - /// - internal static string FormatException_CookieLimitTooSmall() - { - return GetString("Exception_CookieLimitTooSmall"); - } - - /// - /// 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. - /// - internal static string Exception_ImcompleteChunkedCookie - { - get { return GetString("Exception_ImcompleteChunkedCookie"); } - } - - /// - /// 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. - /// - internal static string FormatException_ImcompleteChunkedCookie(object p0, object p1, object p2) - { - return string.Format(CultureInfo.CurrentCulture, GetString("Exception_ImcompleteChunkedCookie"), p0, p1, p2); - } - - 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; - } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/baseline.netcore.json b/src/Microsoft.AspNetCore.Authentication.Cookies/baseline.netcore.json index 56e48d3fe..b218669b7 100644 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/baseline.netcore.json @@ -1,8 +1,8 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Cookies, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Cookies, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { - "Name": "Microsoft.AspNetCore.Builder.CookieAppBuilderExtensions", + "Name": "Microsoft.Extensions.DependencyInjection.CookieExtensions", "Visibility": "Public", "Kind": "Class", "Abstract": true, @@ -12,14 +12,14 @@ "Members": [ { "Kind": "Method", - "Name": "UseCookieAuthentication", + "Name": "AddCookie", "Parameters": [ { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" } ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, "Extension": true, "Visibility": "Public", @@ -27,323 +27,394 @@ }, { "Kind": "Method", - "Name": "UseCookieAuthentication", + "Name": "AddCookie", "Parameters": [ { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" }, { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" + "Name": "authenticationScheme", + "Type": "System.String" } ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, "Extension": true, "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.AuthenticationOptions", - "ImplementedInterfaces": [ - "Microsoft.Extensions.Options.IOptions" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_CookieName", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CookieName", + "Name": "AddCookie", "Parameters": [ { - "Name": "value", - "Type": "System.String" + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "configureOptions", + "Type": "System.Action" } ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_CookieDomain", - "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CookieDomain", + "Name": "AddCookie", "Parameters": [ { - "Name": "value", + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" } ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_CookiePath", - "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CookiePath", + "Name": "AddCookie", "Parameters": [ { - "Name": "value", + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", "Type": "System.String" + }, + { + "Name": "displayName", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" } ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_CookieHttpOnly", - "Parameters": [], - "ReturnType": "System.Boolean", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.CookieAppBuilderExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "set_CookieHttpOnly", + "Name": "UseCookieAuthentication", "Parameters": [ { - "Name": "value", - "Type": "System.Boolean" + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" } ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_CookieSecure", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.CookieSecurePolicy", + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CookieSecure", + "Name": "UseCookieAuthentication", "Parameters": [ { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.CookieSecurePolicy" + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions" } ], - "ReturnType": "System.Void", + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ { - "Kind": "Method", - "Name": "get_DataProtectionProvider", + "Kind": "Field", + "Name": "CookiePrefix", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider", + "ReturnType": "System.String", + "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "set_DataProtectionProvider", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" - } - ], - "ReturnType": "System.Void", + "Kind": "Field", + "Name": "LoginPath", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Http.PathString", + "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "get_ExpireTimeSpan", + "Kind": "Field", + "Name": "LogoutPath", "Parameters": [], - "ReturnType": "System.TimeSpan", + "ReturnType": "Microsoft.AspNetCore.Http.PathString", + "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "set_ExpireTimeSpan", - "Parameters": [ - { - "Name": "value", - "Type": "System.TimeSpan" - } - ], - "ReturnType": "System.Void", + "Kind": "Field", + "Name": "AccessDeniedPath", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Http.PathString", + "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "get_SlidingExpiration", + "Kind": "Field", + "Name": "ReturnUrlParameter", "Parameters": [], - "ReturnType": "System.Boolean", + "ReturnType": "System.String", + "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "set_SlidingExpiration", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", + "Kind": "Field", + "Name": "AuthenticationScheme", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, "Visibility": "Public", - "GenericParameter": [] - }, + "GenericParameter": [], + "Constant": true, + "Literal": "\"Cookies\"" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.SignInAuthenticationHandler", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "get_LoginPath", + "Name": "get_Events", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Visibility": "Public", + "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_LoginPath", + "Name": "set_Events", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Http.PathString" + "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents" } ], "ReturnType": "System.Void", - "Visibility": "Public", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_LogoutPath", + "Name": "InitializeHandlerAsync", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_LogoutPath", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.PathString" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", + "Name": "CreateEventsAsync", + "Parameters": [], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_AccessDeniedPath", + "Name": "HandleAuthenticateAsync", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_AccessDeniedPath", + "Name": "FinishResponseAsync", + "Parameters": [], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleSignInAsync", "Parameters": [ { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.PathString" + "Name": "user", + "Type": "System.Security.Claims.ClaimsPrincipal" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Void", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_ReturnUrlParameter", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", + "Name": "HandleSignOutAsync", + "Parameters": [ + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_ReturnUrlParameter", + "Name": "HandleForbiddenAsync", "Parameters": [ { - "Name": "value", - "Type": "System.String" + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Void", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Events", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", - "Visibility": "Public", + "Name": "HandleChallengeAsync", + "Parameters": [ + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "set_Events", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents" + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" + }, + { + "Name": "logger", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "encoder", + "Type": "System.Text.Encodings.Web.UrlEncoder" + }, + { + "Name": "clock", + "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" } ], - "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "get_TicketDataFormat", + "Name": "get_Cookie", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", + "ReturnType": "Microsoft.AspNetCore.Http.CookieBuilder", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_TicketDataFormat", + "Name": "set_Cookie", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISecureDataFormat" + "Type": "Microsoft.AspNetCore.Http.CookieBuilder" } ], "ReturnType": "System.Void", @@ -352,19 +423,19 @@ }, { "Kind": "Method", - "Name": "get_SystemClock", + "Name": "get_DataProtectionProvider", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISystemClock", + "ReturnType": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_SystemClock", + "Name": "set_DataProtectionProvider", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" + "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" } ], "ReturnType": "System.Void", @@ -373,19 +444,19 @@ }, { "Kind": "Method", - "Name": "get_CookieManager", + "Name": "get_SlidingExpiration", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", + "ReturnType": "System.Boolean", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CookieManager", + "Name": "set_SlidingExpiration", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager" + "Type": "System.Boolean" } ], "ReturnType": "System.Void", @@ -394,58 +465,40 @@ }, { "Kind": "Method", - "Name": "get_SessionStore", + "Name": "get_LoginPath", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.ITicketStore", + "ReturnType": "Microsoft.AspNetCore.Http.PathString", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_SessionStore", + "Name": "set_LoginPath", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.ITicketStore" + "Type": "Microsoft.AspNetCore.Http.PathString" } ], "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.ChunkingCookieManager", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager" - ], - "Members": [ { "Kind": "Method", - "Name": "get_ChunkSize", + "Name": "get_LogoutPath", "Parameters": [], - "ReturnType": "System.Nullable", + "ReturnType": "Microsoft.AspNetCore.Http.PathString", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_ChunkSize", + "Name": "set_LogoutPath", "Parameters": [ { "Name": "value", - "Type": "System.Nullable" + "Type": "Microsoft.AspNetCore.Http.PathString" } ], "ReturnType": "System.Void", @@ -454,19 +507,19 @@ }, { "Kind": "Method", - "Name": "get_ThrowForPartialCookies", + "Name": "get_AccessDeniedPath", "Parameters": [], - "ReturnType": "System.Boolean", + "ReturnType": "Microsoft.AspNetCore.Http.PathString", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_ThrowForPartialCookies", + "Name": "set_AccessDeniedPath", "Parameters": [ { "Name": "value", - "Type": "System.Boolean" + "Type": "Microsoft.AspNetCore.Http.PathString" } ], "ReturnType": "System.Void", @@ -475,367 +528,239 @@ }, { "Kind": "Method", - "Name": "GetRequestCookie", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "key", - "Type": "System.String" - } - ], + "Name": "get_ReturnUrlParameter", + "Parameters": [], "ReturnType": "System.String", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "AppendResponseCookie", + "Name": "set_ReturnUrlParameter", "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "key", - "Type": "System.String" - }, { "Name": "value", "Type": "System.String" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" } ], "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "DeleteCookie", + "Name": "get_Events", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Events", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "key", - "Type": "System.String" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" + "Name": "value", + "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents" } ], "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "CookiePrefix", + "Kind": "Method", + "Name": "get_TicketDataFormat", "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "ReadOnly": true, + "ReturnType": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "LoginPath", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Static": true, - "ReadOnly": true, + "Kind": "Method", + "Name": "set_TicketDataFormat", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Authentication.ISecureDataFormat" + } + ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "LogoutPath", + "Kind": "Method", + "Name": "get_CookieManager", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Static": true, - "ReadOnly": true, + "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "AccessDeniedPath", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Static": true, - "ReadOnly": true, + "Kind": "Method", + "Name": "set_CookieManager", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager" + } + ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "ReturnUrlParameter", + "Kind": "Method", + "Name": "get_SessionStore", "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "ReadOnly": true, + "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.ITicketStore", "Visibility": "Public", "GenericParameter": [] }, - { - "Kind": "Field", - "Name": "AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"Cookies\"" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", - "ImplementedInterfaces": [], - "Members": [ { "Kind": "Method", - "Name": "CreateHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", + "Name": "set_SessionStore", "Parameters": [ { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" - }, - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "urlEncoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" + "Name": "value", + "Type": "Microsoft.AspNetCore.Authentication.Cookies.ITicketStore" } ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Method", - "Name": "GetRequestCookie", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "key", - "Type": "System.String" - } - ], - "ReturnType": "System.String", + "Name": "get_ExpireTimeSpan", + "Parameters": [], + "ReturnType": "System.TimeSpan", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "AppendResponseCookie", + "Name": "set_ExpireTimeSpan", "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "key", - "Type": "System.String" - }, { "Name": "value", - "Type": "System.String" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" + "Type": "System.TimeSpan" } ], "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "DeleteCookie", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "key", - "Type": "System.String" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" - } - ], - "ReturnType": "System.Void", + "Name": "get_CookieName", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.ITicketStore", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Method", - "Name": "StoreAsync", + "Name": "set_CookieName", "Parameters": [ { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" + "Name": "value", + "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RenewAsync", + "Name": "get_CookieDomain", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_CookieDomain", "Parameters": [ { - "Name": "key", + "Name": "value", "Type": "System.String" - }, - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RetrieveAsync", + "Name": "get_CookiePath", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_CookiePath", "Parameters": [ { - "Name": "key", + "Name": "value", "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RemoveAsync", + "Name": "get_CookieHttpOnly", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_CookieHttpOnly", "Parameters": [ { - "Name": "key", - "Type": "System.String" + "Name": "value", + "Type": "System.Boolean" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.BaseCookieContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseContext", - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Method", - "Name": "get_Options", + "Name": "get_CookieSecure", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions", + "ReturnType": "Microsoft.AspNetCore.Http.CookieSecurePolicy", "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "set_CookieSecure", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" + "Name": "value", + "Type": "Microsoft.AspNetCore.Http.CookieSecurePolicy" } ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], "Visibility": "Public", "GenericParameter": [] } @@ -846,9 +771,7 @@ "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents", "Visibility": "Public", "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents" - ], + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", @@ -938,7 +861,7 @@ "Kind": "Method", "Name": "get_OnRedirectToLogin", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "System.Func, System.Threading.Tasks.Task>", "Visibility": "Public", "GenericParameter": [] }, @@ -948,7 +871,7 @@ "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "System.Func, System.Threading.Tasks.Task>" } ], "ReturnType": "System.Void", @@ -959,7 +882,7 @@ "Kind": "Method", "Name": "get_OnRedirectToAccessDenied", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "System.Func, System.Threading.Tasks.Task>", "Visibility": "Public", "GenericParameter": [] }, @@ -969,7 +892,7 @@ "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "System.Func, System.Threading.Tasks.Task>" } ], "ReturnType": "System.Void", @@ -980,7 +903,7 @@ "Kind": "Method", "Name": "get_OnRedirectToLogout", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "System.Func, System.Threading.Tasks.Task>", "Visibility": "Public", "GenericParameter": [] }, @@ -990,7 +913,7 @@ "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "System.Func, System.Threading.Tasks.Task>" } ], "ReturnType": "System.Void", @@ -1001,7 +924,7 @@ "Kind": "Method", "Name": "get_OnRedirectToReturnUrl", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "System.Func, System.Threading.Tasks.Task>", "Visibility": "Public", "GenericParameter": [] }, @@ -1011,7 +934,7 @@ "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "System.Func, System.Threading.Tasks.Task>" } ], "ReturnType": "System.Void", @@ -1029,7 +952,6 @@ ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -1044,7 +966,6 @@ ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -1059,7 +980,6 @@ ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -1074,7 +994,6 @@ ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -1084,12 +1003,11 @@ "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" + "Type": "Microsoft.AspNetCore.Authentication.RedirectContext" } ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -1099,12 +1017,11 @@ "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" + "Type": "Microsoft.AspNetCore.Authentication.RedirectContext" } ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -1114,12 +1031,11 @@ "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" + "Type": "Microsoft.AspNetCore.Authentication.RedirectContext" } ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -1129,12 +1045,11 @@ "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" + "Type": "Microsoft.AspNetCore.Authentication.RedirectContext" } ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -1148,100 +1063,13 @@ ], "GenericParameters": [] }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Cookies.BaseCookieContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_RedirectUri", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_RedirectUri", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" - }, - { - "Name": "redirectUri", - "Type": "System.String" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, { "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieSignedInContext", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Cookies.BaseCookieContext", + "BaseType": "Microsoft.AspNetCore.Authentication.PrincipalContext", "ImplementedInterfaces": [], "Members": [ - { - "Kind": "Method", - "Name": "get_AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Principal", - "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, { "Kind": "Constructor", "Name": ".ctor", @@ -1251,12 +1079,8 @@ "Type": "Microsoft.AspNetCore.Http.HttpContext" }, { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" - }, - { - "Name": "authenticationScheme", - "Type": "System.String" + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" }, { "Name": "principal", @@ -1264,7 +1088,11 @@ }, { "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions" } ], "Visibility": "Public", @@ -1277,59 +1105,9 @@ "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningInContext", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Cookies.BaseCookieContext", + "BaseType": "Microsoft.AspNetCore.Authentication.PrincipalContext", "ImplementedInterfaces": [], "Members": [ - { - "Kind": "Method", - "Name": "get_AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Principal", - "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Principal", - "Parameters": [ - { - "Name": "value", - "Type": "System.Security.Claims.ClaimsPrincipal" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Properties", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, { "Kind": "Method", "Name": "get_CookieOptions", @@ -1360,12 +1138,12 @@ "Type": "Microsoft.AspNetCore.Http.HttpContext" }, { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" }, { - "Name": "authenticationScheme", - "Type": "System.String" + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions" }, { "Name": "principal", @@ -1373,7 +1151,7 @@ }, { "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" }, { "Name": "cookieOptions", @@ -1390,7 +1168,7 @@ "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningOutContext", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Cookies.BaseCookieContext", + "BaseType": "Microsoft.AspNetCore.Authentication.PropertiesContext", "ImplementedInterfaces": [], "Members": [ { @@ -1414,27 +1192,6 @@ "Visibility": "Public", "GenericParameter": [] }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Properties", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, { "Kind": "Constructor", "Name": ".ctor", @@ -1443,13 +1200,17 @@ "Name": "context", "Type": "Microsoft.AspNetCore.Http.HttpContext" }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" + "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions" }, { "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" }, { "Name": "cookieOptions", @@ -1465,26 +1226,10 @@ { "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieValidatePrincipalContext", "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Cookies.BaseCookieContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Principal", - "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.PrincipalContext", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", "Name": "get_ShouldRenew", @@ -1536,12 +1281,16 @@ "Type": "Microsoft.AspNetCore.Http.HttpContext" }, { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" }, { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" + "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions" + }, + { + "Name": "ticket", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" } ], "Visibility": "Public", @@ -1551,7 +1300,7 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", + "Name": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", "Visibility": "Public", "Kind": "Interface", "Abstract": true, @@ -1559,47 +1308,97 @@ "Members": [ { "Kind": "Method", - "Name": "ValidatePrincipal", + "Name": "GetRequestCookie", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieValidatePrincipalContext" + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "key", + "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.String", "GenericParameter": [] }, { "Kind": "Method", - "Name": "SigningIn", + "Name": "AppendResponseCookie", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningInContext" + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "key", + "Type": "System.String" + }, + { + "Name": "value", + "Type": "System.String" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Http.CookieOptions" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", "GenericParameter": [] }, { "Kind": "Method", - "Name": "SignedIn", + "Name": "DeleteCookie", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieSignedInContext" + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "key", + "Type": "System.String" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Http.CookieOptions" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.Cookies.ITicketStore", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "StoreAsync", + "Parameters": [ + { + "Name": "ticket", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" + } + ], + "ReturnType": "System.Threading.Tasks.Task", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RedirectToLogout", + "Name": "RenewAsync", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" + "Name": "key", + "Type": "System.String" + }, + { + "Name": "ticket", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" } ], "ReturnType": "System.Threading.Tasks.Task", @@ -1607,55 +1406,216 @@ }, { "Kind": "Method", - "Name": "RedirectToLogin", + "Name": "RetrieveAsync", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" + "Name": "key", + "Type": "System.String" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "RemoveAsync", + "Parameters": [ + { + "Name": "key", + "Type": "System.String" } ], "ReturnType": "System.Threading.Tasks.Task", "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.Cookies.PostConfigureCookieAuthenticationOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Options.IPostConfigureOptions" + ], + "Members": [ + { + "Kind": "Method", + "Name": "PostConfigure", + "Parameters": [ + { + "Name": "name", + "Type": "System.String" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Options.IPostConfigureOptions", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "dataProtection", + "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.Cookies.ChunkingCookieManager", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_ChunkSize", + "Parameters": [], + "ReturnType": "System.Nullable", + "Visibility": "Public", + "GenericParameter": [] }, { "Kind": "Method", - "Name": "RedirectToReturnUrl", + "Name": "set_ChunkSize", + "Parameters": [ + { + "Name": "value", + "Type": "System.Nullable" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ThrowForPartialCookies", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ThrowForPartialCookies", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "GetRequestCookie", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "key", + "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.String", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RedirectToAccessDenied", + "Name": "AppendResponseCookie", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "key", + "Type": "System.String" + }, + { + "Name": "value", + "Type": "System.String" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Http.CookieOptions" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "SigningOut", + "Name": "DeleteCookie", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningOutContext" + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "key", + "Type": "System.String" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Http.CookieOptions" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "DefaultChunkSize", + "Parameters": [], + "ReturnType": "System.Int32", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "4050" } ], "GenericParameters": [] } - ], - "SourceFilters": [] + ] } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/breakingchanges.netcore.json b/src/Microsoft.AspNetCore.Authentication.Cookies/breakingchanges.netcore.json new file mode 100644 index 000000000..7a1ab7962 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.Cookies/breakingchanges.netcore.json @@ -0,0 +1,52 @@ + [ + { + "TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", + "MemberId": "public Microsoft.AspNetCore.Http.CookieSecurePolicy get_CookieSecure()", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", + "MemberId": "public System.Boolean get_CookieHttpOnly()", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", + "MemberId": "public System.String get_CookieDomain()", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", + "MemberId": "public System.String get_CookieName()", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", + "MemberId": "public System.String get_CookiePath()", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", + "MemberId": "public System.Void set_CookieDomain(System.String value)", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", + "MemberId": "public System.Void set_CookieHttpOnly(System.Boolean value)", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", + "MemberId": "public System.Void set_CookieName(System.String value)", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", + "MemberId": "public System.Void set_CookiePath(System.String value)", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", + "MemberId": "public System.Void set_CookieSecure(Microsoft.AspNetCore.Http.CookieSecurePolicy value)", + "Kind": "Removal" + } + ] \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/project.json b/src/Microsoft.AspNetCore.Authentication.Cookies/project.json deleted file mode 100644 index 454540392..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/project.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core middleware that enables an application to use cookie based authentication.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/security" - }, - "tags": [ - "aspnetcore", - "authentication", - "security" - ] - }, - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true, - "define": [ - "SECURITY" - ] - }, - "dependencies": { - "Microsoft.AspNetCore.Authentication": { - "target": "project" - }, - "Microsoft.AspNetCore.ChunkingCookieManager.Sources": { - "type": "build", - "target": "project" - }, - "Microsoft.Extensions.Options": "1.2.0-*", - "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.2.0-*", - "type": "build" - }, - "Microsoft.Extensions.WebEncoders": "1.2.0-*", - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookAppBuilderExtensions.cs index 0435db794..a94dc7bc4 100644 --- a/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookAppBuilderExtensions.cs @@ -1,9 +1,8 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.AspNetCore.Authentication.Facebook; -using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Builder { @@ -13,38 +12,26 @@ namespace Microsoft.AspNetCore.Builder public static class FacebookAppBuilderExtensions { /// - /// Adds the middleware to the specified , which enables Facebook authentication capabilities. + /// UseFacebookAuthentication is obsolete. Configure Facebook authentication with AddAuthentication().AddFacebook in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. + /// The to add the handler to. /// A reference to this instance after the operation has completed. + [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) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - - return app.UseMiddleware(); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } /// - /// Adds the middleware to the specified , which enables Facebook authentication capabilities. + /// UseFacebookAuthentication is obsolete. Configure Facebook authentication with AddAuthentication().AddFacebook in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. - /// A that specifies options for the middleware. + /// The to add the handler to. + /// A that specifies options for the handler. /// A reference to this instance after the operation has completed. + [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) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - return app.UseMiddleware(Options.Create(options)); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookDefaults.cs b/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookDefaults.cs index 012f95dcc..ff9bb40bf 100644 --- a/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookDefaults.cs +++ b/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookDefaults.cs @@ -7,10 +7,13 @@ public static class FacebookDefaults { public const string AuthenticationScheme = "Facebook"; - public static readonly string AuthorizationEndpoint = "https://www.facebook.com/v2.6/dialog/oauth"; + public static readonly string DisplayName = "Facebook"; - public static readonly string TokenEndpoint = "https://graph.facebook.com/v2.6/oauth/access_token"; + // https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#login + public static readonly string AuthorizationEndpoint = "https://www.facebook.com/v3.1/dialog/oauth"; - public static readonly string UserInformationEndpoint = "https://graph.facebook.com/v2.6/me"; + public static readonly string TokenEndpoint = "https://graph.facebook.com/v3.1/oauth/access_token"; + + public static readonly string UserInformationEndpoint = "https://graph.facebook.com/v3.1/me"; } } diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookExtensions.cs b/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookExtensions.cs new file mode 100644 index 000000000..2273724a4 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookExtensions.cs @@ -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 configureOptions) + => builder.AddFacebook(FacebookDefaults.AuthenticationScheme, configureOptions); + + public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, string authenticationScheme, Action configureOptions) + => builder.AddFacebook(authenticationScheme, FacebookDefaults.DisplayName, configureOptions); + + public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions) + => builder.AddOAuth(authenticationScheme, displayName, configureOptions); + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookHandler.cs b/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookHandler.cs index be1c8f8f8..eb4251143 100644 --- a/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookHandler.cs +++ b/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookHandler.cs @@ -1,27 +1,27 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; +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.Builder; -using Microsoft.AspNetCore.Http.Authentication; using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; namespace Microsoft.AspNetCore.Authentication.Facebook { - internal class FacebookHandler : OAuthHandler + public class FacebookHandler : OAuthHandler { - public FacebookHandler(HttpClient httpClient) - : base(httpClient) - { - } + public FacebookHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) + : base(options, logger, encoder, clock) + { } protected override async Task CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens) { @@ -38,101 +38,18 @@ protected override async Task CreateTicketAsync(ClaimsIden var response = await Backchannel.GetAsync(endpoint, Context.RequestAborted); if (!response.IsSuccessStatusCode) { - throw new HttpRequestException($"Failed to retrieve Facebook user information ({response.StatusCode}) Please check if the authentication information is correct and the corresponding Facebook Graph API is enabled."); + 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 ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Options.AuthenticationScheme); - var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload); - - var identifier = FacebookHelper.GetId(payload); - if (!string.IsNullOrEmpty(identifier)) - { - identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, identifier, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var ageRangeMin = FacebookHelper.GetAgeRangeMin(payload); - if (!string.IsNullOrEmpty(ageRangeMin)) - { - identity.AddClaim(new Claim("urn:facebook:age_range_min", ageRangeMin, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var ageRangeMax = FacebookHelper.GetAgeRangeMax(payload); - if (!string.IsNullOrEmpty(ageRangeMax)) - { - identity.AddClaim(new Claim("urn:facebook:age_range_max", ageRangeMax, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var birthday = FacebookHelper.GetBirthday(payload); - if (!string.IsNullOrEmpty(birthday)) - { - identity.AddClaim(new Claim(ClaimTypes.DateOfBirth, birthday, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var email = FacebookHelper.GetEmail(payload); - if (!string.IsNullOrEmpty(email)) - { - identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var firstName = FacebookHelper.GetFirstName(payload); - if (!string.IsNullOrEmpty(firstName)) - { - identity.AddClaim(new Claim(ClaimTypes.GivenName, firstName, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var gender = FacebookHelper.GetGender(payload); - if (!string.IsNullOrEmpty(gender)) - { - identity.AddClaim(new Claim(ClaimTypes.Gender, gender, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var lastName = FacebookHelper.GetLastName(payload); - if (!string.IsNullOrEmpty(lastName)) - { - identity.AddClaim(new Claim(ClaimTypes.Surname, lastName, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var link = FacebookHelper.GetLink(payload); - if (!string.IsNullOrEmpty(link)) - { - identity.AddClaim(new Claim("urn:facebook:link", link, ClaimValueTypes.String, Options.ClaimsIssuer)); - } + var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload); + context.RunClaimActions(); - var location = FacebookHelper.GetLocation(payload); - if (!string.IsNullOrEmpty(location)) - { - identity.AddClaim(new Claim("urn:facebook:location", location, ClaimValueTypes.String, Options.ClaimsIssuer)); - } + await Events.CreatingTicket(context); - var locale = FacebookHelper.GetLocale(payload); - if (!string.IsNullOrEmpty(locale)) - { - identity.AddClaim(new Claim(ClaimTypes.Locality, locale, ClaimValueTypes.String, Options.ClaimsIssuer)); - } + return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name); - var middleName = FacebookHelper.GetMiddleName(payload); - if (!string.IsNullOrEmpty(middleName)) - { - identity.AddClaim(new Claim("urn:facebook:middle_name", middleName, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var name = FacebookHelper.GetName(payload); - if (!string.IsNullOrEmpty(name)) - { - identity.AddClaim(new Claim(ClaimTypes.Name, name, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var timeZone = FacebookHelper.GetTimeZone(payload); - if (!string.IsNullOrEmpty(timeZone)) - { - identity.AddClaim(new Claim("urn:facebook:timezone", timeZone, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - await Options.Events.CreatingTicket(context); - - return context.Ticket; } private string GenerateAppSecretProof(string accessToken) @@ -149,12 +66,15 @@ private string GenerateAppSecretProof(string accessToken) } } - protected override string FormatScope() + protected override string FormatScope(IEnumerable 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(",", Options.Scope); + return string.Join(",", scopes); } + + protected override string FormatScope() + => base.FormatScope(); } } diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookHelper.cs b/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookHelper.cs deleted file mode 100644 index 48e359099..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookHelper.cs +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Newtonsoft.Json.Linq; - -namespace Microsoft.AspNetCore.Authentication.Facebook -{ - /// - /// Contains static methods that allow to extract user's information from a - /// instance retrieved from Facebook after a successful authentication process. - /// - public static class FacebookHelper - { - /// - /// Gets the Facebook user ID. - /// - public static string GetId(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("id"); - } - - /// - /// Gets the user's min age. - /// - public static string GetAgeRangeMin(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return TryGetValue(user, "age_range", "min"); - } - - /// - /// Gets the user's max age. - /// - public static string GetAgeRangeMax(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return TryGetValue(user, "age_range", "max"); - } - - /// - /// Gets the user's birthday. - /// - public static string GetBirthday(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return user.Value("birthday"); - } - - /// - /// Gets the Facebook email. - /// - public static string GetEmail(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("email"); - } - - /// - /// Gets the user's first name. - /// - public static string GetFirstName(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("first_name"); - } - - /// - /// Gets the user's gender. - /// - public static string GetGender(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return user.Value("gender"); - } - - /// - /// Gets the user's family name. - /// - public static string GetLastName(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("last_name"); - } - - /// - /// Gets the user's link. - /// - public static string GetLink(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return user.Value("link"); - } - - /// - /// Gets the user's location. - /// - public static string GetLocation(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return TryGetValue(user, "location", "name"); - } - - /// - /// Gets the user's locale. - /// - public static string GetLocale(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return user.Value("locale"); - } - - /// - /// Gets the user's middle name. - /// - public static string GetMiddleName(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("middle_name"); - } - - /// - /// Gets the user's name. - /// - public static string GetName(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("name"); - } - - /// - /// Gets the user's timezone. - /// - public static string GetTimeZone(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return user.Value("timezone"); - } - - // Get the given subProperty from a property. - private static string TryGetValue(JObject user, string propertyName, string subProperty) - { - JToken value; - if (user.TryGetValue(propertyName, out value)) - { - var subObject = JObject.Parse(value.ToString()); - if (subObject != null && subObject.TryGetValue(subProperty, out value)) - { - return value.ToString(); - } - } - return null; - } - - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookMiddleware.cs b/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookMiddleware.cs deleted file mode 100644 index ac57e8dde..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookMiddleware.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Globalization; -using System.Text.Encodings.Web; -using Microsoft.AspNetCore.Authentication.OAuth; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.DataProtection; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace Microsoft.AspNetCore.Authentication.Facebook -{ - /// - /// An ASP.NET Core middleware for authenticating users using Facebook. - /// - public class FacebookMiddleware : OAuthMiddleware - { - /// - /// Initializes a new . - /// - /// The next middleware in the HTTP pipeline to invoke. - /// - /// - /// - /// - /// Configuration options for the middleware. - public FacebookMiddleware( - RequestDelegate next, - IDataProtectionProvider dataProtectionProvider, - ILoggerFactory loggerFactory, - UrlEncoder encoder, - IOptions sharedOptions, - IOptions options) - : base(next, dataProtectionProvider, loggerFactory, encoder, sharedOptions, options) - { - if (next == null) - { - throw new ArgumentNullException(nameof(next)); - } - - if (dataProtectionProvider == null) - { - throw new ArgumentNullException(nameof(dataProtectionProvider)); - } - - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - if (encoder == null) - { - throw new ArgumentNullException(nameof(encoder)); - } - - if (sharedOptions == null) - { - throw new ArgumentNullException(nameof(sharedOptions)); - } - - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - if (string.IsNullOrEmpty(Options.AppId)) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.AppId))); - } - - if (string.IsNullOrEmpty(Options.AppSecret)) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.AppSecret))); - } - } - - /// - /// Provides the object for processing authentication-related requests. - /// - /// An configured with the supplied to the constructor. - protected override AuthenticationHandler CreateHandler() - { - return new FacebookHandler(Backchannel); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookOptions.cs b/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookOptions.cs index 8e86b37c1..c2078a017 100644 --- a/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookOptions.cs +++ b/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookOptions.cs @@ -1,14 +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. +using System; using System.Collections.Generic; -using Microsoft.AspNetCore.Authentication.Facebook; +using System.Security.Claims; +using Microsoft.AspNetCore.Authentication; +using System.Globalization; +using Microsoft.AspNetCore.Authentication.OAuth; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Builder +namespace Microsoft.AspNetCore.Authentication.Facebook { /// - /// Configuration options for . + /// Configuration options for . /// public class FacebookOptions : OAuthOptions { @@ -17,19 +21,49 @@ public class FacebookOptions : OAuthOptions /// public FacebookOptions() { - AuthenticationScheme = FacebookDefaults.AuthenticationScheme; - DisplayName = AuthenticationScheme; 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"); + } + + /// + /// Check that the options are valid. Should throw an exception if things are not ok. + /// + 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. diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/Microsoft.AspNetCore.Authentication.Facebook.csproj b/src/Microsoft.AspNetCore.Authentication.Facebook/Microsoft.AspNetCore.Authentication.Facebook.csproj new file mode 100644 index 000000000..f57fe26e0 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.Facebook/Microsoft.AspNetCore.Authentication.Facebook.csproj @@ -0,0 +1,15 @@ + + + + ASP.NET Core middleware that enables an application to support Facebook's OAuth 2.0 authentication workflow. + netcoreapp3.0 + $(NoWarn);CS1591 + true + aspnetcore;authentication;security + + + + + + + diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/Microsoft.AspNetCore.Authentication.Facebook.xproj b/src/Microsoft.AspNetCore.Authentication.Facebook/Microsoft.AspNetCore.Authentication.Facebook.xproj deleted file mode 100644 index caa72075e..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Facebook/Microsoft.AspNetCore.Authentication.Facebook.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - eeaaee68-607b-4e33-af3e-45c66b4dba5a - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Authentication.Facebook/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Facebook/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Authentication.Facebook/Properties/Resources.Designer.cs index a3a2f2874..655da24a3 100644 --- a/src/Microsoft.AspNetCore.Authentication.Facebook/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Authentication.Facebook/Properties/Resources.Designer.cs @@ -15,16 +15,14 @@ private static readonly ResourceManager _resourceManager /// internal static string Exception_OptionMustBeProvided { - get { return GetString("Exception_OptionMustBeProvided"); } + get => GetString("Exception_OptionMustBeProvided"); } /// /// The '{0}' option must be provided. /// internal static string FormatException_OptionMustBeProvided(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); private static string GetString(string name, params string[] formatterNames) { diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/baseline.net45.json b/src/Microsoft.AspNetCore.Authentication.Facebook/baseline.net45.json deleted file mode 100644 index 1e070fc7f..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Facebook/baseline.net45.json +++ /dev/null @@ -1,453 +0,0 @@ -{ - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Facebook, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", - "Types": [ - { - "Name": "Microsoft.AspNetCore.Authentication.Facebook.FacebookDefaults", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "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.FacebookHelper", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "GetId", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetAgeRangeMin", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetAgeRangeMax", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetBirthday", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetEmail", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetFirstName", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetGender", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetLastName", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetLink", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetLocation", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetLocale", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetMiddleName", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetName", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetTimeZone", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Facebook.FacebookMiddleware", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthMiddleware", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "CreateHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" - }, - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" - }, - { - "Name": "sharedOptions", - "Type": "Microsoft.Extensions.Options.IOptions" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" - } - ], - "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.Builder.FacebookOptions" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.FacebookOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.OAuthOptions", - "ImplementedInterfaces": [], - "Members": [ - { - "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", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - } - ], - "SourceFilters": [] -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/baseline.netcore.json b/src/Microsoft.AspNetCore.Authentication.Facebook/baseline.netcore.json index 1e070fc7f..5d95efca6 100644 --- a/src/Microsoft.AspNetCore.Authentication.Facebook/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Authentication.Facebook/baseline.netcore.json @@ -1,61 +1,8 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Facebook, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Facebook, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { - "Name": "Microsoft.AspNetCore.Authentication.Facebook.FacebookDefaults", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "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.FacebookHelper", + "Name": "Microsoft.Extensions.DependencyInjection.FacebookAuthenticationOptionsExtensions", "Visibility": "Public", "Kind": "Class", "Abstract": true, @@ -65,215 +12,204 @@ "Members": [ { "Kind": "Method", - "Name": "GetId", + "Name": "AddFacebook", "Parameters": [ { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" } ], - "ReturnType": "System.String", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetAgeRangeMin", + "Name": "AddFacebook", "Parameters": [ { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetAgeRangeMax", - "Parameters": [ + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "configureOptions", + "Type": "System.Action" } ], - "ReturnType": "System.String", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetBirthday", + "Name": "AddFacebook", "Parameters": [ { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetEmail", - "Parameters": [ + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetFirstName", - "Parameters": [ + "Name": "authenticationScheme", + "Type": "System.String" + }, { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "configureOptions", + "Type": "System.Action" } ], - "ReturnType": "System.String", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetGender", + "Name": "AddFacebook", "Parameters": [ { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" } ], - "ReturnType": "System.String", + "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": "Method", - "Name": "GetLastName", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], + "Kind": "Field", + "Name": "DisplayName", + "Parameters": [], "ReturnType": "System.String", "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "GetLink", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], + "Kind": "Field", + "Name": "AuthorizationEndpoint", + "Parameters": [], "ReturnType": "System.String", "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "GetLocation", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], + "Kind": "Field", + "Name": "TokenEndpoint", + "Parameters": [], "ReturnType": "System.String", "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "GetLocale", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], + "Kind": "Field", + "Name": "UserInformationEndpoint", + "Parameters": [], "ReturnType": "System.String", "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "GetMiddleName", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], + "Kind": "Field", + "Name": "AuthenticationScheme", + "Parameters": [], "ReturnType": "System.String", "Static": true, "Visibility": "Public", - "GenericParameter": [] - }, + "GenericParameter": [], + "Constant": true, + "Literal": "\"Facebook\"" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.Facebook.FacebookHandler", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "GetName", + "Name": "CreateTicketAsync", "Parameters": [ { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "identity", + "Type": "System.Security.Claims.ClaimsIdentity" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + }, + { + "Name": "tokens", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse" } ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetTimeZone", + "Name": "FormatScope", "Parameters": [ { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "scopes", + "Type": "System.Collections.Generic.IEnumerable" } ], "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Facebook.FacebookMiddleware", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthMiddleware", - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Method", - "Name": "CreateHandler", + "Name": "FormatScope", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "ReturnType": "System.String", "Virtual": true, "Override": true, "Visibility": "Protected", @@ -284,15 +220,11 @@ "Name": ".ctor", "Parameters": [ { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" }, { - "Name": "loggerFactory", + "Name": "logger", "Type": "Microsoft.Extensions.Logging.ILoggerFactory" }, { @@ -300,12 +232,8 @@ "Type": "System.Text.Encodings.Web.UrlEncoder" }, { - "Name": "sharedOptions", - "Type": "Microsoft.Extensions.Options.IOptions" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" + "Name": "clock", + "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" } ], "Visibility": "Public", @@ -315,58 +243,22 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Builder.FacebookAppBuilderExtensions", + "Name": "Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions", "Visibility": "Public", "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, + "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "UseFacebookAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, + "Name": "Validate", + "Parameters": [], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, "Visibility": "Public", "GenericParameter": [] }, - { - "Kind": "Method", - "Name": "UseFacebookAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.FacebookOptions" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.FacebookOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.OAuthOptions", - "ImplementedInterfaces": [], - "Members": [ { "Kind": "Method", "Name": "get_AppId", @@ -447,7 +339,52 @@ } ], "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": [] } - ], - "SourceFilters": [] + ] } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Facebook/project.json b/src/Microsoft.AspNetCore.Authentication.Facebook/project.json deleted file mode 100644 index 4d581dce1..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Facebook/project.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core middleware that enables an application to support Facebook's OAuth 2.0 authentication workflow.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/security" - }, - "tags": [ - "aspnetcore", - "authentication", - "security" - ] - }, - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "dependencies": { - "Microsoft.AspNetCore.Authentication.OAuth": { - "target": "project" - }, - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Google/GoogleAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Authentication.Google/GoogleAppBuilderExtensions.cs index 85a193d82..4302d20db 100644 --- a/src/Microsoft.AspNetCore.Authentication.Google/GoogleAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Authentication.Google/GoogleAppBuilderExtensions.cs @@ -3,7 +3,6 @@ using System; using Microsoft.AspNetCore.Authentication.Google; -using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Builder { @@ -13,41 +12,26 @@ namespace Microsoft.AspNetCore.Builder public static class GoogleAppBuilderExtensions { /// - /// Adds the middleware to the specified , - /// which enables Google authentication capabilities. + /// UseGoogleAuthentication is obsolete. Configure Google authentication with AddAuthentication().AddGoogle in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. + /// The to add the handler to. /// A reference to this instance after the operation has completed. + [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) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - - return app.UseMiddleware(); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } /// - /// Adds the middleware to the specified , - /// which enables Google authentication capabilities. + /// UseGoogleAuthentication is obsolete. Configure Google authentication with AddAuthentication().AddGoogle in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. - /// A that specifies options for the middleware. + /// The to add the handler to. + /// A that specifies options for the handler. /// A reference to this instance after the operation has completed. + [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) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - return app.UseMiddleware(Options.Create(options)); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } } } diff --git a/src/Microsoft.AspNetCore.Authentication.Google/GoogleChallengeProperties.cs b/src/Microsoft.AspNetCore.Authentication.Google/GoogleChallengeProperties.cs new file mode 100644 index 000000000..714df4565 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.Google/GoogleChallengeProperties.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using Microsoft.AspNetCore.Authentication.OAuth; + +namespace Microsoft.AspNetCore.Authentication.Google +{ + public class GoogleChallengeProperties : OAuthChallengeProperties + { + /// + /// The parameter key for the "access_type" argument being used for a challenge request. + /// + public static readonly string AccessTypeKey = "access_type"; + + /// + /// The parameter key for the "approval_prompt" argument being used for a challenge request. + /// + public static readonly string ApprovalPromptKey = "approval_prompt"; + + /// + /// The parameter key for the "include_granted_scopes" argument being used for a challenge request. + /// + public static readonly string IncludeGrantedScopesKey = "include_granted_scopes"; + + /// + /// The parameter key for the "login_hint" argument being used for a challenge request. + /// + public static readonly string LoginHintKey = "login_hint"; + + /// + /// The parameter key for the "prompt" argument being used for a challenge request. + /// + public static readonly string PromptParameterKey = "prompt"; + + public GoogleChallengeProperties() + { } + + public GoogleChallengeProperties(IDictionary items) + : base(items) + { } + + public GoogleChallengeProperties(IDictionary items, IDictionary parameters) + : base(items, parameters) + { } + + /// + /// The "access_type" parameter value being used for a challenge request. + /// + public string AccessType + { + get => GetParameter(AccessTypeKey); + set => SetParameter(AccessTypeKey, value); + } + + /// + /// The "approval_prompt" parameter value being used for a challenge request. + /// + public string ApprovalPrompt + { + get => GetParameter(ApprovalPromptKey); + set => SetParameter(ApprovalPromptKey, value); + } + + /// + /// The "include_granted_scopes" parameter value being used for a challenge request. + /// + public bool? IncludeGrantedScopes + { + get => GetParameter(IncludeGrantedScopesKey); + set => SetParameter(IncludeGrantedScopesKey, value); + } + + /// + /// The "login_hint" parameter value being used for a challenge request. + /// + public string LoginHint + { + get => GetParameter(LoginHintKey); + set => SetParameter(LoginHintKey, value); + } + + /// + /// The "prompt" parameter value being used for a challenge request. + /// + public string Prompt + { + get => GetParameter(PromptParameterKey); + set => SetParameter(PromptParameterKey, value); + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.Google/GoogleDefaults.cs b/src/Microsoft.AspNetCore.Authentication.Google/GoogleDefaults.cs index 77d68aed9..26b3b8f01 100644 --- a/src/Microsoft.AspNetCore.Authentication.Google/GoogleDefaults.cs +++ b/src/Microsoft.AspNetCore.Authentication.Google/GoogleDefaults.cs @@ -10,10 +10,14 @@ public static class GoogleDefaults { public const string AuthenticationScheme = "Google"; - public static readonly string AuthorizationEndpoint = "https://accounts.google.com/o/oauth2/auth"; + public static readonly string DisplayName = "Google"; + + // https://developers.google.com/identity/protocols/OAuth2WebServer + 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"; + // https://developers.google.com/+/web/people/ public static readonly string UserInformationEndpoint = "https://www.googleapis.com/plus/v1/people/me"; } } diff --git a/src/Microsoft.AspNetCore.Authentication.Google/GoogleExtensions.cs b/src/Microsoft.AspNetCore.Authentication.Google/GoogleExtensions.cs new file mode 100644 index 000000000..95547014c --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.Google/GoogleExtensions.cs @@ -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 configureOptions) + => builder.AddGoogle(GoogleDefaults.AuthenticationScheme, configureOptions); + + public static AuthenticationBuilder AddGoogle(this AuthenticationBuilder builder, string authenticationScheme, Action configureOptions) + => builder.AddGoogle(authenticationScheme, GoogleDefaults.DisplayName, configureOptions); + + public static AuthenticationBuilder AddGoogle(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions) + => builder.AddOAuth(authenticationScheme, displayName, configureOptions); + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.Google/GoogleHandler.cs b/src/Microsoft.AspNetCore.Authentication.Google/GoogleHandler.cs index f28ab4d14..88d48d446 100644 --- a/src/Microsoft.AspNetCore.Authentication.Google/GoogleHandler.cs +++ b/src/Microsoft.AspNetCore.Authentication.Google/GoogleHandler.cs @@ -6,21 +6,21 @@ 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.Builder; -using Microsoft.AspNetCore.Http.Authentication; using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; namespace Microsoft.AspNetCore.Authentication.Google { - internal class GoogleHandler : OAuthHandler + public class GoogleHandler : OAuthHandler { - public GoogleHandler(HttpClient httpClient) - : base(httpClient) - { - } + public GoogleHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) + : base(options, logger, encoder, clock) + { } protected override async Task CreateTicketAsync( ClaimsIdentity identity, @@ -34,54 +34,16 @@ protected override async Task CreateTicketAsync( var response = await Backchannel.SendAsync(request, Context.RequestAborted); if (!response.IsSuccessStatusCode) { - throw new HttpRequestException($"An error occurred when retrieving user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Google+ API is enabled."); + 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 principal = new ClaimsPrincipal(identity); - var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme); - var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload); - - var identifier = GoogleHelper.GetId(payload); - if (!string.IsNullOrEmpty(identifier)) - { - identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, identifier, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var givenName = GoogleHelper.GetGivenName(payload); - if (!string.IsNullOrEmpty(givenName)) - { - identity.AddClaim(new Claim(ClaimTypes.GivenName, givenName, ClaimValueTypes.String, Options.ClaimsIssuer)); - } + var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload); + context.RunClaimActions(); - var familyName = GoogleHelper.GetFamilyName(payload); - if (!string.IsNullOrEmpty(familyName)) - { - identity.AddClaim(new Claim(ClaimTypes.Surname, familyName, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var name = GoogleHelper.GetName(payload); - if (!string.IsNullOrEmpty(name)) - { - identity.AddClaim(new Claim(ClaimTypes.Name, name, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var email = GoogleHelper.GetEmail(payload); - if (!string.IsNullOrEmpty(email)) - { - identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var profile = GoogleHelper.GetProfile(payload); - if (!string.IsNullOrEmpty(profile)) - { - identity.AddClaim(new Claim("urn:google:profile", profile, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - await Options.Events.CreatingTicket(context); - - return context.Ticket; + await Events.CreatingTicket(context); + return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name); } // TODO: Abstract this properties override pattern into the base class? @@ -95,12 +57,12 @@ protected override string BuildChallengeUrl(AuthenticationProperties properties, queryStrings.Add("client_id", Options.ClientId); queryStrings.Add("redirect_uri", redirectUri); - AddQueryString(queryStrings, properties, "scope", FormatScope()); - AddQueryString(queryStrings, properties, "access_type", Options.AccessType); - AddQueryString(queryStrings, properties, "approval_prompt"); - AddQueryString(queryStrings, properties, "prompt"); - AddQueryString(queryStrings, properties, "login_hint"); - AddQueryString(queryStrings, properties, "include_granted_scopes"); + 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); @@ -109,29 +71,38 @@ protected override string BuildChallengeUrl(AuthenticationProperties properties, return authorizationEndpoint; } - private static void AddQueryString( + private void AddQueryString( IDictionary queryStrings, AuthenticationProperties properties, string name, - string defaultValue = null) + Func formatter, + T defaultValue) { - string value; - if (!properties.Items.TryGetValue(name, out value)) + string value = null; + var parameterValue = properties.GetParameter(name); + if (parameterValue != null) { - value = defaultValue; + value = formatter(parameterValue); } - else + else if (!properties.Items.TryGetValue(name, out value)) { - // Remove the parameter from AuthenticationProperties so it won't be serialized to state parameter - properties.Items.Remove(name); + value = formatter(defaultValue); } - if (value == null) + // Remove the parameter from AuthenticationProperties so it won't be serialized into the state + properties.Items.Remove(name); + + if (value != null) { - return; + queryStrings[name] = value; } - - queryStrings[name] = value; } + + private void AddQueryString( + IDictionary queryStrings, + AuthenticationProperties properties, + string name, + string defaultValue = null) + => AddQueryString(queryStrings, properties, name, x => x, defaultValue); } } diff --git a/src/Microsoft.AspNetCore.Authentication.Google/GoogleHelper.cs b/src/Microsoft.AspNetCore.Authentication.Google/GoogleHelper.cs index 336536c51..2cac949a0 100644 --- a/src/Microsoft.AspNetCore.Authentication.Google/GoogleHelper.cs +++ b/src/Microsoft.AspNetCore.Authentication.Google/GoogleHelper.cs @@ -12,71 +12,6 @@ namespace Microsoft.AspNetCore.Authentication.Google /// public static class GoogleHelper { - /// - /// Gets the Google user ID. - /// - public static string GetId(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("id"); - } - - /// - /// Gets the user's name. - /// - public static string GetName(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("displayName"); - } - - /// - /// Gets the user's given name. - /// - public static string GetGivenName(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return TryGetValue(user, "name", "givenName"); - } - - /// - /// Gets the user's family name. - /// - public static string GetFamilyName(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return TryGetValue(user, "name", "familyName"); - } - - /// - /// Gets the user's profile link. - /// - public static string GetProfile(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("url"); - } - /// /// Gets the user's email. /// @@ -90,21 +25,6 @@ public static string GetEmail(JObject user) return TryGetFirstValue(user, "emails", "value"); } - // Get the given subProperty from a property. - private static string TryGetValue(JObject user, string propertyName, string subProperty) - { - JToken value; - if (user.TryGetValue(propertyName, out value)) - { - var subObject = JObject.Parse(value.ToString()); - if (subObject != null && subObject.TryGetValue(subProperty, out value)) - { - return value.ToString(); - } - } - return null; - } - // Get the given subProperty from a list property. private static string TryGetFirstValue(JObject user, string propertyName, string subProperty) { diff --git a/src/Microsoft.AspNetCore.Authentication.Google/GoogleMiddleware.cs b/src/Microsoft.AspNetCore.Authentication.Google/GoogleMiddleware.cs deleted file mode 100644 index 5f8afaff2..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Google/GoogleMiddleware.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Text.Encodings.Web; -using Microsoft.AspNetCore.Authentication.OAuth; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.DataProtection; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace Microsoft.AspNetCore.Authentication.Google -{ - /// - /// An ASP.NET Core middleware for authenticating users using Google OAuth 2.0. - /// - public class GoogleMiddleware : OAuthMiddleware - { - /// - /// Initializes a new . - /// - /// The next middleware in the HTTP pipeline to invoke. - /// - /// - /// - /// - /// Configuration options for the middleware. - public GoogleMiddleware( - RequestDelegate next, - IDataProtectionProvider dataProtectionProvider, - ILoggerFactory loggerFactory, - UrlEncoder encoder, - IOptions sharedOptions, - IOptions options) - : base(next, dataProtectionProvider, loggerFactory, encoder, sharedOptions, options) - { - if (next == null) - { - throw new ArgumentNullException(nameof(next)); - } - - if (dataProtectionProvider == null) - { - throw new ArgumentNullException(nameof(dataProtectionProvider)); - } - - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - if (encoder == null) - { - throw new ArgumentNullException(nameof(encoder)); - } - - if (sharedOptions == null) - { - throw new ArgumentNullException(nameof(sharedOptions)); - } - - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - } - - /// - /// Provides the object for processing authentication-related requests. - /// - /// - /// An configured with the - /// supplied to the constructor. - /// - protected override AuthenticationHandler CreateHandler() - { - return new GoogleHandler(Backchannel); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Google/GoogleOptions.cs b/src/Microsoft.AspNetCore.Authentication.Google/GoogleOptions.cs index 3d93b96ea..34028bc52 100644 --- a/src/Microsoft.AspNetCore.Authentication.Google/GoogleOptions.cs +++ b/src/Microsoft.AspNetCore.Authentication.Google/GoogleOptions.cs @@ -1,13 +1,15 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Authentication.Google; +using System.Security.Claims; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.OAuth; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Builder +namespace Microsoft.AspNetCore.Authentication.Google { /// - /// Configuration options for . + /// Configuration options for . /// public class GoogleOptions : OAuthOptions { @@ -16,8 +18,6 @@ public class GoogleOptions : OAuthOptions /// public GoogleOptions() { - AuthenticationScheme = GoogleDefaults.AuthenticationScheme; - DisplayName = AuthenticationScheme; CallbackPath = new PathString("/signin-google"); AuthorizationEndpoint = GoogleDefaults.AuthorizationEndpoint; TokenEndpoint = GoogleDefaults.TokenEndpoint; @@ -25,6 +25,13 @@ public GoogleOptions() 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); } /// diff --git a/src/Microsoft.AspNetCore.Authentication.Google/Microsoft.AspNetCore.Authentication.Google.csproj b/src/Microsoft.AspNetCore.Authentication.Google/Microsoft.AspNetCore.Authentication.Google.csproj new file mode 100644 index 000000000..eba5b98ad --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.Google/Microsoft.AspNetCore.Authentication.Google.csproj @@ -0,0 +1,15 @@ + + + + ASP.NET Core contains middleware to support Google's OpenId and OAuth 2.0 authentication workflows. + netcoreapp3.0 + $(NoWarn);CS1591 + true + aspnetcore;authentication;security + + + + + + + diff --git a/src/Microsoft.AspNetCore.Authentication.Google/Microsoft.AspNetCore.Authentication.Google.xproj b/src/Microsoft.AspNetCore.Authentication.Google/Microsoft.AspNetCore.Authentication.Google.xproj deleted file mode 100644 index ab6048872..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Google/Microsoft.AspNetCore.Authentication.Google.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 76579c39-b829-490d-b8be-1bd35fe8412e - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Google/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Authentication.Google/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Google/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.Authentication.Google/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Authentication.Google/Properties/Resources.Designer.cs index 690c5a280..03448b408 100644 --- a/src/Microsoft.AspNetCore.Authentication.Google/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Authentication.Google/Properties/Resources.Designer.cs @@ -15,32 +15,28 @@ private static readonly ResourceManager _resourceManager /// internal static string Exception_OptionMustBeProvided { - get { return GetString("Exception_OptionMustBeProvided"); } + get => GetString("Exception_OptionMustBeProvided"); } /// /// The '{0}' option must be provided. /// internal static string FormatException_OptionMustBeProvided(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); /// /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler. /// internal static string Exception_ValidatorHandlerMismatch { - get { return GetString("Exception_ValidatorHandlerMismatch"); } + get => GetString("Exception_ValidatorHandlerMismatch"); } /// /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler. /// internal static string FormatException_ValidatorHandlerMismatch() - { - return GetString("Exception_ValidatorHandlerMismatch"); - } + => GetString("Exception_ValidatorHandlerMismatch"); private static string GetString(string name, params string[] formatterNames) { diff --git a/src/Microsoft.AspNetCore.Authentication.Google/baseline.net45.json b/src/Microsoft.AspNetCore.Authentication.Google/baseline.net45.json deleted file mode 100644 index 647633afa..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Google/baseline.net45.json +++ /dev/null @@ -1,291 +0,0 @@ -{ - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Google, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", - "Types": [ - { - "Name": "Microsoft.AspNetCore.Authentication.Google.GoogleDefaults", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "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.GoogleHelper", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "GetId", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetName", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetGivenName", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetFamilyName", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetProfile", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "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.GoogleMiddleware", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthMiddleware", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "CreateHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" - }, - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" - }, - { - "Name": "sharedOptions", - "Type": "Microsoft.Extensions.Options.IOptions" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" - } - ], - "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.Builder.GoogleOptions" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.GoogleOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.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": [] - } - ], - "SourceFilters": [] -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Google/baseline.netcore.json b/src/Microsoft.AspNetCore.Authentication.Google/baseline.netcore.json index 647633afa..0a623b3b8 100644 --- a/src/Microsoft.AspNetCore.Authentication.Google/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Authentication.Google/baseline.netcore.json @@ -1,8 +1,8 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Google, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Google, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { - "Name": "Microsoft.AspNetCore.Authentication.Google.GoogleDefaults", + "Name": "Microsoft.Extensions.DependencyInjection.GoogleExtensions", "Visibility": "Public", "Kind": "Class", "Abstract": true, @@ -11,139 +11,286 @@ "ImplementedInterfaces": [], "Members": [ { - "Kind": "Field", - "Name": "AuthorizationEndpoint", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "AddGoogle", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, - "ReadOnly": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "TokenEndpoint", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "AddGoogle", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, - "ReadOnly": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "UserInformationEndpoint", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "AddGoogle", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, - "ReadOnly": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", + "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" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, + "Extension": true, "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"Google\"" + "GenericParameter": [] } ], "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.Google.GoogleHelper", + "Name": "Microsoft.AspNetCore.Authentication.Google.GoogleChallengeProperties", "Visibility": "Public", "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, + "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthChallengeProperties", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "GetId", + "Name": "get_AccessType", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_AccessType", "Parameters": [ { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "value", + "Type": "System.String" } ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ApprovalPrompt", + "Parameters": [], "ReturnType": "System.String", - "Static": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetName", + "Name": "set_ApprovalPrompt", "Parameters": [ { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "value", + "Type": "System.String" } ], - "ReturnType": "System.String", - "Static": true, + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_IncludeGrantedScopes", + "Parameters": [], + "ReturnType": "System.Nullable", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetGivenName", + "Name": "set_IncludeGrantedScopes", "Parameters": [ { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "value", + "Type": "System.Nullable" } ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_LoginHint", + "Parameters": [], "ReturnType": "System.String", - "Static": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetFamilyName", + "Name": "set_LoginHint", "Parameters": [ { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "value", + "Type": "System.String" } ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Prompt", + "Parameters": [], "ReturnType": "System.String", - "Static": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetProfile", + "Name": "set_Prompt", "Parameters": [ { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "value", + "Type": "System.String" } ], - "ReturnType": "System.String", - "Static": true, + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "GetEmail", + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "items", + "Type": "System.Collections.Generic.IDictionary" } ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "items", + "Type": "System.Collections.Generic.IDictionary" + }, + { + "Name": "parameters", + "Type": "System.Collections.Generic.IDictionary" + } + ], + "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": [] } @@ -151,36 +298,127 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.Google.GoogleMiddleware", + "Name": "Microsoft.AspNetCore.Authentication.Google.GoogleDefaults", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthMiddleware", + "Abstract": true, + "Static": true, + "Sealed": true, "ImplementedInterfaces": [], "Members": [ { - "Kind": "Method", - "Name": "CreateHandler", + "Kind": "Field", + "Name": "DisplayName", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "AuthorizationEndpoint", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "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", + "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", "Virtual": true, "Override": true, "Visibility": "Protected", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "BuildChallengeUrl", "Parameters": [ { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" }, { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" + "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" }, { - "Name": "loggerFactory", + "Name": "logger", "Type": "Microsoft.Extensions.Logging.ILoggerFactory" }, { @@ -188,12 +426,8 @@ "Type": "System.Text.Encodings.Web.UrlEncoder" }, { - "Name": "sharedOptions", - "Type": "Microsoft.Extensions.Options.IOptions" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" + "Name": "clock", + "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" } ], "Visibility": "Public", @@ -203,7 +437,7 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Builder.GoogleAppBuilderExtensions", + "Name": "Microsoft.AspNetCore.Authentication.Google.GoogleHelper", "Visibility": "Public", "Kind": "Class", "Abstract": true, @@ -213,35 +447,15 @@ "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", + "Name": "GetEmail", "Parameters": [ { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.GoogleOptions" + "Name": "user", + "Type": "Newtonsoft.Json.Linq.JObject" } ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "ReturnType": "System.String", "Static": true, - "Extension": true, "Visibility": "Public", "GenericParameter": [] } @@ -249,10 +463,10 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Builder.GoogleOptions", + "Name": "Microsoft.AspNetCore.Authentication.Google.GoogleOptions", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.OAuthOptions", + "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions", "ImplementedInterfaces": [], "Members": [ { @@ -285,7 +499,52 @@ } ], "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": [] } - ], - "SourceFilters": [] + ] } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Google/project.json b/src/Microsoft.AspNetCore.Authentication.Google/project.json deleted file mode 100644 index f8d8e3417..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Google/project.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core contains middleware to support Google's OpenId and OAuth 2.0 authentication workflows.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/security" - }, - "tags": [ - "aspnetcore", - "authentication", - "security" - ] - }, - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "dependencies": { - "Microsoft.AspNetCore.Authentication.OAuth": { - "target": "project" - }, - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/AuthenticationFailedContext.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/AuthenticationFailedContext.cs index b3e0f0bdc..1c2efd6c7 100644 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/AuthenticationFailedContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/AuthenticationFailedContext.cs @@ -2,17 +2,17 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Authentication.JwtBearer { - public class AuthenticationFailedContext : BaseJwtBearerContext + public class AuthenticationFailedContext : ResultContext { - public AuthenticationFailedContext(HttpContext context, JwtBearerOptions options) - : base(context, options) - { - } + public AuthenticationFailedContext( + HttpContext context, + AuthenticationScheme scheme, + JwtBearerOptions options) + : base(context, scheme, options) { } public Exception Exception { get; set; } } diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/BaseJwtBearerContext.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/BaseJwtBearerContext.cs deleted file mode 100644 index 5c28f2976..000000000 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/BaseJwtBearerContext.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Authentication.JwtBearer -{ - public class BaseJwtBearerContext : BaseControlContext - { - public BaseJwtBearerContext(HttpContext context, JwtBearerOptions options) - : base(context) - { - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - Options = options; - } - - public JwtBearerOptions Options { get; } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/IJwtBearerEvents.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/IJwtBearerEvents.cs deleted file mode 100644 index a7b8aeb55..000000000 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/IJwtBearerEvents.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Authentication.JwtBearer -{ - /// - /// Specifies events which the invokes to enable developer control over the authentication process. - /// - public interface IJwtBearerEvents - { - /// - /// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed. - /// - Task AuthenticationFailed(AuthenticationFailedContext context); - - /// - /// Invoked when a protocol message is first received. - /// - Task MessageReceived(MessageReceivedContext context); - - /// - /// Invoked after the security token has passed validation and a ClaimsIdentity has been generated. - /// - Task TokenValidated(TokenValidatedContext context); - - /// - /// Invoked to apply a challenge sent back to the caller. - /// - Task Challenge(JwtBearerChallengeContext context); - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/JwtBearerChallengeContext.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/JwtBearerChallengeContext.cs index 584681253..6500e1e3f 100644 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/JwtBearerChallengeContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/JwtBearerChallengeContext.cs @@ -2,21 +2,18 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; namespace Microsoft.AspNetCore.Authentication.JwtBearer { - public class JwtBearerChallengeContext : BaseJwtBearerContext + public class JwtBearerChallengeContext : PropertiesContext { - public JwtBearerChallengeContext(HttpContext context, JwtBearerOptions options, AuthenticationProperties properties) - : base(context, options) - { - Properties = properties; - } - - public AuthenticationProperties Properties { get; } + public JwtBearerChallengeContext( + HttpContext context, + AuthenticationScheme scheme, + JwtBearerOptions options, + AuthenticationProperties properties) + : base(context, scheme, options, properties) { } /// /// Any failures encountered during the authentication process. @@ -42,5 +39,15 @@ public JwtBearerChallengeContext(HttpContext context, JwtBearerOptions options, /// WWW-Authenticate header. This property is always null unless explicitly set. /// public string ErrorUri { get; set; } + + /// + /// If true, will skip any default logic for this challenge. + /// + public bool Handled { get; private set; } + + /// + /// Skips any default logic for this challenge. + /// + public void HandleResponse() => Handled = true; } } diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/JwtBearerEvents.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/JwtBearerEvents.cs index 8ac1c3631..a9b35c310 100644 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/JwtBearerEvents.cs +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/JwtBearerEvents.cs @@ -3,34 +3,33 @@ using System; using System.Threading.Tasks; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Authentication.JwtBearer { /// - /// Specifies events which the invokes to enable developer control over the authentication process. + /// Specifies events which the invokes to enable developer control over the authentication process. /// - public class JwtBearerEvents : IJwtBearerEvents + public class JwtBearerEvents { /// /// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed. /// - public Func OnAuthenticationFailed { get; set; } = context => TaskCache.CompletedTask; + public Func OnAuthenticationFailed { get; set; } = context => Task.CompletedTask; /// /// Invoked when a protocol message is first received. /// - public Func OnMessageReceived { get; set; } = context => TaskCache.CompletedTask; + public Func OnMessageReceived { get; set; } = context => Task.CompletedTask; /// /// Invoked after the security token has passed validation and a ClaimsIdentity has been generated. /// - public Func OnTokenValidated { get; set; } = context => TaskCache.CompletedTask; + public Func OnTokenValidated { get; set; } = context => Task.CompletedTask; /// /// Invoked before a challenge is sent back to the caller. /// - public Func OnChallenge { get; set; } = context => TaskCache.CompletedTask; + public Func OnChallenge { get; set; } = context => Task.CompletedTask; public virtual Task AuthenticationFailed(AuthenticationFailedContext context) => OnAuthenticationFailed(context); diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/MessageReceivedContext.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/MessageReceivedContext.cs index a23f8356d..1850ad049 100644 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/MessageReceivedContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/MessageReceivedContext.cs @@ -1,20 +1,20 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Authentication.JwtBearer { - public class MessageReceivedContext : BaseJwtBearerContext + public class MessageReceivedContext : ResultContext { - public MessageReceivedContext(HttpContext context, JwtBearerOptions options) - : base(context, options) - { - } + public MessageReceivedContext( + HttpContext context, + AuthenticationScheme scheme, + JwtBearerOptions options) + : base(context, scheme, options) { } /// - /// Bearer Token. This will give application an opportunity to retrieve token from an alternation location. + /// Bearer Token. This will give the application an opportunity to retrieve a token from an alternative location. /// public string Token { get; set; } } diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/TokenValidatedContext.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/TokenValidatedContext.cs index d6de5ca87..39b677b96 100644 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/TokenValidatedContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/TokenValidatedContext.cs @@ -1,18 +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. -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.IdentityModel.Tokens; namespace Microsoft.AspNetCore.Authentication.JwtBearer { - public class TokenValidatedContext : BaseJwtBearerContext + public class TokenValidatedContext : ResultContext { - public TokenValidatedContext(HttpContext context, JwtBearerOptions options) - : base(context, options) - { - } + public TokenValidatedContext( + HttpContext context, + AuthenticationScheme scheme, + JwtBearerOptions options) + : base(context, scheme, options) { } public SecurityToken SecurityToken { get; set; } } diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerAppBuilderExtensions.cs index 13c06ca38..0cfc97573 100644 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerAppBuilderExtensions.cs @@ -1,9 +1,8 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Builder { @@ -13,50 +12,26 @@ namespace Microsoft.AspNetCore.Builder public static class JwtBearerAppBuilderExtensions { /// - /// Adds the middleware to the specified , which enables Bearer token processing capabilities. - /// This middleware understands appropriately - /// formatted and secured tokens which appear in the request header. If the Options.AuthenticationMode is Active, the - /// claims within the bearer token are added to the current request's IPrincipal User. If the Options.AuthenticationMode - /// is Passive, then the current request is not modified, but IAuthenticationManager AuthenticateAsync may be used at - /// any time to obtain the claims from the request's bearer token. - /// See also http://tools.ietf.org/html/rfc6749 + /// UseJwtBearerAuthentication is obsolete. Configure JwtBearer authentication with AddAuthentication().AddJwtBearer in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. + /// The to add the handler to. /// A reference to this instance after the operation has completed. + [Obsolete("UseJwtBearerAuthentication is obsolete. Configure JwtBearer authentication with AddAuthentication().AddJwtBearer in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)] public static IApplicationBuilder UseJwtBearerAuthentication(this IApplicationBuilder app) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - - return app.UseMiddleware(); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } /// - /// Adds the middleware to the specified , which enables Bearer token processing capabilities. - /// This middleware understands appropriately - /// formatted and secured tokens which appear in the request header. If the Options.AuthenticationMode is Active, the - /// claims within the bearer token are added to the current request's IPrincipal User. If the Options.AuthenticationMode - /// is Passive, then the current request is not modified, but IAuthenticationManager AuthenticateAsync may be used at - /// any time to obtain the claims from the request's bearer token. - /// See also http://tools.ietf.org/html/rfc6749 + /// UseJwtBearerAuthentication is obsolete. Configure JwtBearer authentication with AddAuthentication().AddJwtBearer in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. - /// A that specifies options for the middleware. + /// The to add the handler to. + /// A that specifies options for the handler. /// A reference to this instance after the operation has completed. + [Obsolete("UseJwtBearerAuthentication is obsolete. Configure JwtBearer authentication with AddAuthentication().AddJwtBearer in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)] public static IApplicationBuilder UseJwtBearerAuthentication(this IApplicationBuilder app, JwtBearerOptions options) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - return app.UseMiddleware(Options.Create(options)); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerExtensions.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerExtensions.cs new file mode 100644 index 000000000..334407c0d --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerExtensions.cs @@ -0,0 +1,29 @@ +// 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.JwtBearer; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class JwtBearerExtensions + { + public static AuthenticationBuilder AddJwtBearer(this AuthenticationBuilder builder) + => builder.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, _ => { }); + + public static AuthenticationBuilder AddJwtBearer(this AuthenticationBuilder builder, Action configureOptions) + => builder.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, configureOptions); + + public static AuthenticationBuilder AddJwtBearer(this AuthenticationBuilder builder, string authenticationScheme, Action configureOptions) + => builder.AddJwtBearer(authenticationScheme, displayName: null, configureOptions: configureOptions); + + public static AuthenticationBuilder AddJwtBearer(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions) + { + builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton, JwtBearerPostConfigureOptions>()); + return builder.AddScheme(authenticationScheme, displayName, configureOptions); + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerHandler.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerHandler.cs index ee5575251..4f03ccd69 100644 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerHandler.cs +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerHandler.cs @@ -6,22 +6,38 @@ using System.Linq; using System.Security.Claims; using System.Text; +using System.Text.Encodings.Web; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Tokens; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Authentication.JwtBearer { - internal class JwtBearerHandler : AuthenticationHandler + public class JwtBearerHandler : AuthenticationHandler { private OpenIdConnectConfiguration _configuration; + public JwtBearerHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) + : base(options, logger, encoder, clock) + { } + + /// + /// 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. + /// + protected new JwtBearerEvents Events + { + get => (JwtBearerEvents)base.Events; + set => base.Events = value; + } + + protected override Task CreateEventsAsync() => Task.FromResult(new JwtBearerEvents()); + /// /// Searches the 'Authorization' header for a 'Bearer' token. If the 'Bearer' token is found, it is validated using set in the options. /// @@ -29,17 +45,16 @@ internal class JwtBearerHandler : AuthenticationHandler protected override async Task HandleAuthenticateAsync() { string token = null; - AuthenticateResult result = null; try { // Give application opportunity to find from a different location, adjust, or reject token - var messageReceivedContext = new MessageReceivedContext(Context, Options); + var messageReceivedContext = new MessageReceivedContext(Context, Scheme, Options); // event can set the token - await Options.Events.MessageReceived(messageReceivedContext); - if (messageReceivedContext.CheckEventResult(out result)) + await Events.MessageReceived(messageReceivedContext); + if (messageReceivedContext.Result != null) { - return result; + return messageReceivedContext.Result; } // If application retrieved token from somewhere else, use that. @@ -52,7 +67,7 @@ protected override async Task HandleAuthenticateAsync() // If no authorization header found, nothing to process further if (string.IsNullOrEmpty(authorization)) { - return AuthenticateResult.Skip(); + return AuthenticateResult.NoResult(); } if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) @@ -63,7 +78,7 @@ protected override async Task HandleAuthenticateAsync() // If no token found, no further work possible if (string.IsNullOrEmpty(token)) { - return AuthenticateResult.Skip(); + return AuthenticateResult.NoResult(); } } @@ -75,17 +90,11 @@ protected override async Task HandleAuthenticateAsync() var validationParameters = Options.TokenValidationParameters.Clone(); if (_configuration != null) { - if (validationParameters.ValidIssuer == null && !string.IsNullOrEmpty(_configuration.Issuer)) - { - validationParameters.ValidIssuer = _configuration.Issuer; - } - else - { - var issuers = new[] { _configuration.Issuer }; - validationParameters.ValidIssuers = (validationParameters.ValidIssuers == null ? issuers : validationParameters.ValidIssuers.Concat(issuers)); - } + var issuers = new[] { _configuration.Issuer }; + validationParameters.ValidIssuers = validationParameters.ValidIssuers?.Concat(issuers) ?? issuers; - validationParameters.IssuerSigningKeys = (validationParameters.IssuerSigningKeys == null ? _configuration.SigningKeys : validationParameters.IssuerSigningKeys.Concat(_configuration.SigningKeys)); + validationParameters.IssuerSigningKeys = validationParameters.IssuerSigningKeys?.Concat(_configuration.SigningKeys) + ?? _configuration.SigningKeys; } List validationFailures = null; @@ -101,7 +110,7 @@ protected override async Task HandleAuthenticateAsync() } catch (Exception ex) { - Logger.TokenValidationFailed(token, ex); + Logger.TokenValidationFailed(ex); // Refresh the configuration for exceptions that may be caused by key rollovers. The user can also request a refresh in the event. if (Options.RefreshOnIssuerKeyNotFound && Options.ConfigurationManager != null @@ -120,43 +129,42 @@ protected override async Task HandleAuthenticateAsync() Logger.TokenValidationSucceeded(); - var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Options.AuthenticationScheme); - var tokenValidatedContext = new TokenValidatedContext(Context, Options) + var tokenValidatedContext = new TokenValidatedContext(Context, Scheme, Options) { - Ticket = ticket, - SecurityToken = validatedToken, + Principal = principal, + SecurityToken = validatedToken }; - await Options.Events.TokenValidated(tokenValidatedContext); - if (tokenValidatedContext.CheckEventResult(out result)) + await Events.TokenValidated(tokenValidatedContext); + if (tokenValidatedContext.Result != null) { - return result; + return tokenValidatedContext.Result; } - ticket = tokenValidatedContext.Ticket; if (Options.SaveToken) { - ticket.Properties.StoreTokens(new[] + tokenValidatedContext.Properties.StoreTokens(new[] { new AuthenticationToken { Name = "access_token", Value = token } }); } - return AuthenticateResult.Success(ticket); + tokenValidatedContext.Success(); + return tokenValidatedContext.Result; } } if (validationFailures != null) { - var authenticationFailedContext = new AuthenticationFailedContext(Context, Options) + var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options) { Exception = (validationFailures.Count == 1) ? validationFailures[0] : new AggregateException(validationFailures) }; - await Options.Events.AuthenticationFailed(authenticationFailedContext); - if (authenticationFailedContext.CheckEventResult(out result)) + await Events.AuthenticationFailed(authenticationFailedContext); + if (authenticationFailedContext.Result != null) { - return result; + return authenticationFailedContext.Result; } return AuthenticateResult.Fail(authenticationFailedContext.Exception); @@ -168,26 +176,25 @@ protected override async Task HandleAuthenticateAsync() { Logger.ErrorProcessingMessage(ex); - var authenticationFailedContext = new AuthenticationFailedContext(Context, Options) + var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options) { Exception = ex }; - await Options.Events.AuthenticationFailed(authenticationFailedContext); - if (authenticationFailedContext.CheckEventResult(out result)) + await Events.AuthenticationFailed(authenticationFailedContext); + if (authenticationFailedContext.Result != null) { - return result; + return authenticationFailedContext.Result; } throw; } } - protected override async Task HandleUnauthorizedAsync(ChallengeContext context) + protected override async Task HandleChallengeAsync(AuthenticationProperties properties) { var authResult = await HandleAuthenticateOnceSafeAsync(); - - var eventContext = new JwtBearerChallengeContext(Context, Options, new AuthenticationProperties(context.Properties)) + var eventContext = new JwtBearerChallengeContext(Context, Scheme, Options, properties) { AuthenticateFailure = authResult?.Failure }; @@ -199,14 +206,10 @@ protected override async Task HandleUnauthorizedAsync(ChallengeContext con eventContext.ErrorDescription = CreateErrorDescription(eventContext.AuthenticateFailure); } - await Options.Events.Challenge(eventContext); - if (eventContext.HandledResponse) - { - return true; - } - if (eventContext.Skipped) + await Events.Challenge(eventContext); + if (eventContext.Handled) { - return false; + return; } Response.StatusCode = 401; @@ -259,16 +262,13 @@ protected override async Task HandleUnauthorizedAsync(ChallengeContext con Response.Headers.Append(HeaderNames.WWWAuthenticate, builder.ToString()); } - - return false; } private static string CreateErrorDescription(Exception authFailure) { IEnumerable exceptions; - if (authFailure is AggregateException) + if (authFailure is AggregateException agEx) { - var agEx = authFailure as AggregateException; exceptions = agEx.InnerExceptions; } else @@ -282,51 +282,36 @@ private static string CreateErrorDescription(Exception authFailure) { // Order sensitive, some of these exceptions derive from others // and we want to display the most specific message possible. - if (ex is SecurityTokenInvalidAudienceException) - { - messages.Add("The audience is invalid"); - } - else if (ex is SecurityTokenInvalidIssuerException) + switch (ex) { - messages.Add("The issuer is invalid"); - } - else if (ex is SecurityTokenNoExpirationException) - { - messages.Add("The token has no expiration"); - } - else if (ex is SecurityTokenInvalidLifetimeException) - { - messages.Add("The token lifetime is invalid"); - } - else if (ex is SecurityTokenNotYetValidException) - { - messages.Add("The token is not valid yet"); - } - else if (ex is SecurityTokenExpiredException) - { - messages.Add("The token is expired"); - } - else if (ex is SecurityTokenSignatureKeyNotFoundException) - { - messages.Add("The signature key was not found"); - } - else if (ex is SecurityTokenInvalidSignatureException) - { - messages.Add("The signature is invalid"); + case SecurityTokenInvalidAudienceException _: + messages.Add("The audience is invalid"); + break; + case SecurityTokenInvalidIssuerException _: + messages.Add("The issuer is invalid"); + break; + case SecurityTokenNoExpirationException _: + messages.Add("The token has no expiration"); + break; + case SecurityTokenInvalidLifetimeException _: + messages.Add("The token lifetime is invalid"); + break; + case SecurityTokenNotYetValidException _: + messages.Add("The token is not valid yet"); + break; + case SecurityTokenExpiredException _: + messages.Add("The token is expired"); + break; + case SecurityTokenSignatureKeyNotFoundException _: + messages.Add("The signature key was not found"); + break; + case SecurityTokenInvalidSignatureException _: + messages.Add("The signature is invalid"); + break; } } return string.Join("; ", messages); } - - protected override Task HandleSignOutAsync(SignOutContext context) - { - throw new NotSupportedException(); - } - - protected override Task HandleSignInAsync(SignInContext context) - { - throw new NotSupportedException(); - } } } diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerMiddleware.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerMiddleware.cs deleted file mode 100644 index bfb38793f..000000000 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerMiddleware.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Net.Http; -using System.Text.Encodings.Web; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Microsoft.IdentityModel.Protocols; -using Microsoft.IdentityModel.Protocols.OpenIdConnect; - -namespace Microsoft.AspNetCore.Authentication.JwtBearer -{ - /// - /// Bearer authentication middleware component which is added to an HTTP pipeline. This class is not - /// created by application code directly, instead it is added by calling the the IAppBuilder UseJwtBearerAuthentication - /// extension method. - /// - public class JwtBearerMiddleware : AuthenticationMiddleware - { - /// - /// Bearer authentication component which is added to an HTTP pipeline. This constructor is not - /// called by application code directly, instead it is added by calling the the IAppBuilder UseJwtBearerAuthentication - /// extension method. - /// - public JwtBearerMiddleware( - RequestDelegate next, - ILoggerFactory loggerFactory, - UrlEncoder encoder, - IOptions options) - : base(next, options, loggerFactory, encoder) - { - if (next == null) - { - throw new ArgumentNullException(nameof(next)); - } - - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - if (encoder == null) - { - throw new ArgumentNullException(nameof(encoder)); - } - - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - if (Options.Events == null) - { - Options.Events = new JwtBearerEvents(); - } - - if (string.IsNullOrEmpty(Options.TokenValidationParameters.ValidAudience) && !string.IsNullOrEmpty(Options.Audience)) - { - Options.TokenValidationParameters.ValidAudience = Options.Audience; - } - - if (Options.ConfigurationManager == null) - { - if (Options.Configuration != null) - { - Options.ConfigurationManager = new StaticConfigurationManager(Options.Configuration); - } - else if (!(string.IsNullOrEmpty(Options.MetadataAddress) && string.IsNullOrEmpty(Options.Authority))) - { - if (string.IsNullOrEmpty(Options.MetadataAddress) && !string.IsNullOrEmpty(Options.Authority)) - { - Options.MetadataAddress = Options.Authority; - if (!Options.MetadataAddress.EndsWith("/", StringComparison.Ordinal)) - { - Options.MetadataAddress += "/"; - } - - Options.MetadataAddress += ".well-known/openid-configuration"; - } - - if (Options.RequireHttpsMetadata && !Options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidOperationException("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false."); - } - - var httpClient = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler()); - httpClient.Timeout = Options.BackchannelTimeout; - httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB - - Options.ConfigurationManager = new ConfigurationManager(Options.MetadataAddress, new OpenIdConnectConfigurationRetriever(), - new HttpDocumentRetriever(httpClient) { RequireHttps = Options.RequireHttpsMetadata }); - } - } - } - - /// - /// Called by the AuthenticationMiddleware base class to create a per-request handler. - /// - /// A new instance of the request handler - protected override AuthenticationHandler CreateHandler() - { - return new JwtBearerHandler(); - } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerOptions.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerOptions.cs index 2aedf30d5..0d0a88e24 100644 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerOptions.cs +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerOptions.cs @@ -3,32 +3,19 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.IdentityModel.Tokens.Jwt; using System.Net.Http; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Protocols; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Tokens; -namespace Microsoft.AspNetCore.Builder +namespace Microsoft.AspNetCore.Authentication.JwtBearer { /// - /// Options class provides information needed to control Bearer Authentication middleware behavior + /// Options class provides information needed to control Bearer Authentication handler behavior /// - public class JwtBearerOptions : AuthenticationOptions + public class JwtBearerOptions : AuthenticationSchemeOptions { - /// - /// Creates an instance of bearer authentication options with default values. - /// - public JwtBearerOptions() : base() - { - AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme; - AutomaticAuthenticate = true; - AutomaticChallenge = true; - } - /// /// Gets or sets if HTTPS is required for the metadata address or authority. /// The default is true. This should be disabled only in development environments. @@ -59,11 +46,15 @@ public JwtBearerOptions() : base() public string Challenge { get; set; } = JwtBearerDefaults.AuthenticationScheme; /// - /// The object provided by the application to process events raised by the bearer authentication middleware. - /// The application may implement the interface fully, or it may create an instance of JwtBearerAuthenticationEvents + /// The object provided by the application to process events raised by the bearer authentication handler. + /// The application may implement the interface fully, or it may create an instance of JwtBearerEvents /// and assign delegates only to the events it wants to process. /// - public IJwtBearerEvents Events { get; set; } = new JwtBearerEvents(); + public new JwtBearerEvents Events + { + get { return (JwtBearerEvents)base.Events; } + set { base.Events = value; } + } /// /// The HttpMessageHandler used to retrieve metadata. @@ -115,7 +106,7 @@ public JwtBearerOptions() : base() /// /// Defines whether the token validation errors should be returned to the caller. - /// Enabled by default, this option can be disabled to prevent the JWT middleware + /// Enabled by default, this option can be disabled to prevent the JWT handler /// from returning an error and an error_description in the WWW-Authenticate header. /// public bool IncludeErrorDetails { get; set; } = true; diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerPostConfigureOptions.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerPostConfigureOptions.cs new file mode 100644 index 000000000..8829bfac0 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerPostConfigureOptions.cs @@ -0,0 +1,63 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Net.Http; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Protocols; +using Microsoft.IdentityModel.Protocols.OpenIdConnect; + +namespace Microsoft.AspNetCore.Authentication.JwtBearer +{ + /// + /// Used to setup defaults for all . + /// + public class JwtBearerPostConfigureOptions : IPostConfigureOptions + { + /// + /// Invoked to post configure a JwtBearerOptions instance. + /// + /// The name of the options instance being configured. + /// The options instance to configure. + public void PostConfigure(string name, JwtBearerOptions options) + { + if (string.IsNullOrEmpty(options.TokenValidationParameters.ValidAudience) && !string.IsNullOrEmpty(options.Audience)) + { + options.TokenValidationParameters.ValidAudience = options.Audience; + } + + if (options.ConfigurationManager == null) + { + if (options.Configuration != null) + { + options.ConfigurationManager = new StaticConfigurationManager(options.Configuration); + } + else if (!(string.IsNullOrEmpty(options.MetadataAddress) && string.IsNullOrEmpty(options.Authority))) + { + if (string.IsNullOrEmpty(options.MetadataAddress) && !string.IsNullOrEmpty(options.Authority)) + { + options.MetadataAddress = options.Authority; + if (!options.MetadataAddress.EndsWith("/", StringComparison.Ordinal)) + { + options.MetadataAddress += "/"; + } + + options.MetadataAddress += ".well-known/openid-configuration"; + } + + if (options.RequireHttpsMetadata && !options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false."); + } + + var httpClient = new HttpClient(options.BackchannelHttpHandler ?? new HttpClientHandler()); + httpClient.Timeout = options.BackchannelTimeout; + httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB + + options.ConfigurationManager = new ConfigurationManager(options.MetadataAddress, new OpenIdConnectConfigurationRetriever(), + new HttpDocumentRetriever(httpClient) { RequireHttps = options.RequireHttpsMetadata }); + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/LoggingExtensions.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/LoggingExtensions.cs index 008190f51..5c6ca088a 100644 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/LoggingExtensions.cs +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/LoggingExtensions.cs @@ -7,16 +7,16 @@ namespace Microsoft.Extensions.Logging { internal static class LoggingExtensions { - private static Action _tokenValidationFailed; + private static Action _tokenValidationFailed; private static Action _tokenValidationSucceeded; private static Action _errorProcessingMessage; static LoggingExtensions() { - _tokenValidationFailed = LoggerMessage.Define( + _tokenValidationFailed = LoggerMessage.Define( eventId: 1, logLevel: LogLevel.Information, - formatString: "Failed to validate the token {Token}."); + formatString: "Failed to validate the token."); _tokenValidationSucceeded = LoggerMessage.Define( eventId: 2, logLevel: LogLevel.Information, @@ -27,19 +27,13 @@ static LoggingExtensions() formatString: "Exception occurred while processing message."); } - public static void TokenValidationFailed(this ILogger logger, string token, Exception ex) - { - _tokenValidationFailed(logger, token, ex); - } + public static void TokenValidationFailed(this ILogger logger, Exception ex) + => _tokenValidationFailed(logger, ex); public static void TokenValidationSucceeded(this ILogger logger) - { - _tokenValidationSucceeded(logger, null); - } + => _tokenValidationSucceeded(logger, null); public static void ErrorProcessingMessage(this ILogger logger, Exception ex) - { - _errorProcessingMessage(logger, ex); - } + => _errorProcessingMessage(logger, ex); } } diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Microsoft.AspNetCore.Authentication.JwtBearer.csproj b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Microsoft.AspNetCore.Authentication.JwtBearer.csproj new file mode 100644 index 000000000..8a26c58f3 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Microsoft.AspNetCore.Authentication.JwtBearer.csproj @@ -0,0 +1,19 @@ + + + + ASP.NET Core middleware that enables an application to receive an OpenID Connect bearer token. + netcoreapp3.0 + $(NoWarn);CS1591 + true + aspnetcore;authentication;security + + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Microsoft.AspNetCore.Authentication.JwtBearer.xproj b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Microsoft.AspNetCore.Authentication.JwtBearer.xproj deleted file mode 100644 index 738458398..000000000 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Microsoft.AspNetCore.Authentication.JwtBearer.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 2755BFE5-7421-4A31-A644-F817DF5CAA98 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff..000000000 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Properties/Resources.Designer.cs index ef1d784f2..e95b8e061 100644 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/Properties/Resources.Designer.cs @@ -15,32 +15,28 @@ private static readonly ResourceManager _resourceManager /// internal static string Exception_OptionMustBeProvided { - get { return GetString("Exception_OptionMustBeProvided"); } + get => GetString("Exception_OptionMustBeProvided"); } /// /// The '{0}' option must be provided. /// internal static string FormatException_OptionMustBeProvided(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); /// /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler. /// internal static string Exception_ValidatorHandlerMismatch { - get { return GetString("Exception_ValidatorHandlerMismatch"); } + get => GetString("Exception_ValidatorHandlerMismatch"); } /// /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler. /// internal static string FormatException_ValidatorHandlerMismatch() - { - return GetString("Exception_ValidatorHandlerMismatch"); - } + => GetString("Exception_ValidatorHandlerMismatch"); private static string GetString(string name, params string[] formatterNames) { diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/baseline.net45.json b/src/Microsoft.AspNetCore.Authentication.JwtBearer/baseline.net45.json deleted file mode 100644 index 37e18e53e..000000000 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/baseline.net45.json +++ /dev/null @@ -1,976 +0,0 @@ -{ - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.JwtBearer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", - "Types": [ - { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"Bearer\"" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "CreateHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.AuthenticationFailedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.JwtBearer.BaseJwtBearerContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Exception", - "Parameters": [], - "ReturnType": "System.Exception", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Exception", - "Parameters": [ - { - "Name": "value", - "Type": "System.Exception" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.JwtBearerOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.BaseJwtBearerContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseControlContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.JwtBearerOptions", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.JwtBearerOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "AuthenticationFailed", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.AuthenticationFailedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "MessageReceived", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.MessageReceivedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "TokenValidated", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Challenge", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerChallengeContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerChallengeContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.JwtBearer.BaseJwtBearerContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AuthenticateFailure", - "Parameters": [], - "ReturnType": "System.Exception", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_AuthenticateFailure", - "Parameters": [ - { - "Name": "value", - "Type": "System.Exception" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Error", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Error", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ErrorDescription", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ErrorDescription", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ErrorUri", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ErrorUri", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.JwtBearerOptions" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_OnAuthenticationFailed", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnAuthenticationFailed", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnMessageReceived", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnMessageReceived", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnTokenValidated", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnTokenValidated", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnChallenge", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnChallenge", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AuthenticationFailed", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.AuthenticationFailedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "MessageReceived", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.MessageReceivedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "TokenValidated", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Challenge", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerChallengeContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.MessageReceivedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.JwtBearer.BaseJwtBearerContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Token", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Token", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.JwtBearerOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.JwtBearer.BaseJwtBearerContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_SecurityToken", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Tokens.SecurityToken", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SecurityToken", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Tokens.SecurityToken" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.JwtBearerOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.JwtBearerAppBuilderExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "UseJwtBearerAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "UseJwtBearerAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.JwtBearerOptions" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.JwtBearerOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.AuthenticationOptions", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_RequireHttpsMetadata", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_RequireHttpsMetadata", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_MetadataAddress", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_MetadataAddress", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Authority", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Authority", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Audience", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Audience", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Challenge", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Challenge", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Events", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Events", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_BackchannelHttpHandler", - "Parameters": [], - "ReturnType": "System.Net.Http.HttpMessageHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_BackchannelHttpHandler", - "Parameters": [ - { - "Name": "value", - "Type": "System.Net.Http.HttpMessageHandler" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_BackchannelTimeout", - "Parameters": [], - "ReturnType": "System.TimeSpan", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_BackchannelTimeout", - "Parameters": [ - { - "Name": "value", - "Type": "System.TimeSpan" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Configuration", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfiguration", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Configuration", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfiguration" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ConfigurationManager", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.IConfigurationManager", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ConfigurationManager", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.IConfigurationManager" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_RefreshOnIssuerKeyNotFound", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_RefreshOnIssuerKeyNotFound", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SystemClock", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISystemClock", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SystemClock", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SecurityTokenValidators", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IList", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_TokenValidationParameters", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Tokens.TokenValidationParameters", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_TokenValidationParameters", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Tokens.TokenValidationParameters" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SaveToken", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SaveToken", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_IncludeErrorDetails", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_IncludeErrorDetails", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - } - ], - "SourceFilters": [] -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/baseline.netcore.json b/src/Microsoft.AspNetCore.Authentication.JwtBearer/baseline.netcore.json index 37e18e53e..d3839022b 100644 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/baseline.netcore.json @@ -1,8 +1,8 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.JwtBearer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.JwtBearer, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults", + "Name": "Microsoft.Extensions.DependencyInjection.JwtBearerExtensions", "Visibility": "Public", "Kind": "Class", "Abstract": true, @@ -11,104 +11,86 @@ "ImplementedInterfaces": [], "Members": [ { - "Kind": "Field", - "Name": "AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "AddJwtBearer", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, + "Extension": true, "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"Bearer\"" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "CreateHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "Virtual": true, - "Override": true, - "Visibility": "Protected", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "AddJwtBearer", "Parameters": [ { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" }, { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" + "Name": "configureOptions", + "Type": "System.Action" } ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.AuthenticationFailedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.JwtBearer.BaseJwtBearerContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Exception", - "Parameters": [], - "ReturnType": "System.Exception", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Exception", + "Name": "AddJwtBearer", "Parameters": [ { - "Name": "value", - "Type": "System.Exception" + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" } ], - "ReturnType": "System.Void", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "AddJwtBearer", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" }, { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.JwtBearerOptions" + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" } ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] } @@ -116,33 +98,45 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.BaseJwtBearerContext", + "Name": "Microsoft.AspNetCore.Builder.JwtBearerAppBuilderExtensions", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseControlContext", + "Abstract": true, + "Static": true, + "Sealed": true, "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.JwtBearerOptions", + "Name": "UseJwtBearerAuthentication", + "Parameters": [ + { + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "UseJwtBearerAuthentication", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" }, { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.JwtBearerOptions" + "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions" } ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] } @@ -150,58 +144,51 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents", + "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.AuthenticationFailedContext", "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.ResultContext", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "AuthenticationFailed", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.AuthenticationFailedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", + "Name": "get_Exception", + "Parameters": [], + "ReturnType": "System.Exception", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "MessageReceived", + "Name": "set_Exception", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.MessageReceivedContext" + "Name": "value", + "Type": "System.Exception" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "TokenValidated", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Challenge", - "Parameters": [ + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerChallengeContext" + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions" } ], - "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Public", "GenericParameter": [] } ], @@ -211,17 +198,9 @@ "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerChallengeContext", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.JwtBearer.BaseJwtBearerContext", + "BaseType": "Microsoft.AspNetCore.Authentication.PropertiesContext", "ImplementedInterfaces": [], "Members": [ - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, { "Kind": "Method", "Name": "get_AuthenticateFailure", @@ -306,6 +285,22 @@ "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Method", + "Name": "get_Handled", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleResponse", + "Parameters": [], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Constructor", "Name": ".ctor", @@ -314,13 +309,17 @@ "Name": "context", "Type": "Microsoft.AspNetCore.Http.HttpContext" }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.JwtBearerOptions" + "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions" }, { "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], "Visibility": "Public", @@ -333,9 +332,7 @@ "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents", "Visibility": "Public", "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents" - ], + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", @@ -432,7 +429,6 @@ ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -447,7 +443,6 @@ ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -462,7 +457,6 @@ ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -477,7 +471,6 @@ ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -495,7 +488,7 @@ "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.MessageReceivedContext", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.JwtBearer.BaseJwtBearerContext", + "BaseType": "Microsoft.AspNetCore.Authentication.ResultContext", "ImplementedInterfaces": [], "Members": [ { @@ -527,9 +520,13 @@ "Name": "context", "Type": "Microsoft.AspNetCore.Http.HttpContext" }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.JwtBearerOptions" + "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions" } ], "Visibility": "Public", @@ -542,7 +539,7 @@ "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.JwtBearer.BaseJwtBearerContext", + "BaseType": "Microsoft.AspNetCore.Authentication.ResultContext", "ImplementedInterfaces": [], "Members": [ { @@ -574,9 +571,13 @@ "Name": "context", "Type": "Microsoft.AspNetCore.Http.HttpContext" }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.JwtBearerOptions" + "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions" } ], "Visibility": "Public", @@ -586,45 +587,116 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Builder.JwtBearerAppBuilderExtensions", + "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults", "Visibility": "Public", "Kind": "Class", "Abstract": true, "Static": true, "Sealed": true, "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "AuthenticationScheme", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"Bearer\"" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "UseJwtBearerAuthentication", + "Name": "get_Events", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents", + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Events", "Parameters": [ { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + "Name": "value", + "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents" } ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", + "ReturnType": "System.Void", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "UseJwtBearerAuthentication", + "Name": "CreateEventsAsync", + "Parameters": [], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleAuthenticateAsync", + "Parameters": [], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleChallengeAsync", "Parameters": [ { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.JwtBearerOptions" + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" + }, + { + "Name": "logger", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "encoder", + "Type": "System.Text.Encodings.Web.UrlEncoder" + }, + { + "Name": "dataProtection", + "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" + }, + { + "Name": "clock", + "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" } ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, "Visibility": "Public", "GenericParameter": [] } @@ -632,10 +704,10 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Builder.JwtBearerOptions", + "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.AuthenticationOptions", + "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", "ImplementedInterfaces": [], "Members": [ { @@ -747,7 +819,7 @@ "Kind": "Method", "Name": "get_Events", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents", + "ReturnType": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -757,7 +829,7 @@ "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents" + "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents" } ], "ReturnType": "System.Void", @@ -869,27 +941,6 @@ "Visibility": "Public", "GenericParameter": [] }, - { - "Kind": "Method", - "Name": "get_SystemClock", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISystemClock", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SystemClock", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, { "Kind": "Method", "Name": "get_SecurityTokenValidators", @@ -970,7 +1021,44 @@ } ], "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerPostConfigureOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Options.IPostConfigureOptions" + ], + "Members": [ + { + "Kind": "Method", + "Name": "PostConfigure", + "Parameters": [ + { + "Name": "name", + "Type": "System.String" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Options.IPostConfigureOptions", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] } - ], - "SourceFilters": [] + ] } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/breakingchanges.netcore.json b/src/Microsoft.AspNetCore.Authentication.JwtBearer/breakingchanges.netcore.json new file mode 100644 index 000000000..d17003a80 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.JwtBearer/breakingchanges.netcore.json @@ -0,0 +1,7 @@ + [ + { + "TypeId": "public class Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler : Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "MemberId": "public .ctor(Microsoft.Extensions.Options.IOptionsMonitor options, Microsoft.Extensions.Logging.ILoggerFactory logger, System.Text.Encodings.Web.UrlEncoder encoder, Microsoft.AspNetCore.DataProtection.IDataProtectionProvider dataProtection, Microsoft.AspNetCore.Authentication.ISystemClock clock)", + "Kind": "Removal" + } + ] \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.JwtBearer/project.json b/src/Microsoft.AspNetCore.Authentication.JwtBearer/project.json deleted file mode 100644 index 271e35339..000000000 --- a/src/Microsoft.AspNetCore.Authentication.JwtBearer/project.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core middleware that enables an application to receive an OpenID Connect bearer token.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/security" - }, - "tags": [ - "aspnetcore", - "authentication", - "security" - ] - }, - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "dependencies": { - "Microsoft.AspNetCore.Authentication": { - "target": "project" - }, - "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.2.0-*", - "type": "build" - }, - "Microsoft.IdentityModel.Protocols.OpenIdConnect": "2.1.0", - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": {}, - "netstandard1.4": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Microsoft.AspNetCore.Authentication.MicrosoftAccount.csproj b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Microsoft.AspNetCore.Authentication.MicrosoftAccount.csproj new file mode 100644 index 000000000..1841157c9 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Microsoft.AspNetCore.Authentication.MicrosoftAccount.csproj @@ -0,0 +1,15 @@ + + + + ASP.NET Core middleware that enables an application to support the Microsoft Account authentication workflow. + netcoreapp3.0 + $(NoWarn);CS1591 + true + aspnetcore;authentication;security + + + + + + + diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Microsoft.AspNetCore.Authentication.MicrosoftAccount.xproj b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Microsoft.AspNetCore.Authentication.MicrosoftAccount.xproj deleted file mode 100644 index a4ccc9863..000000000 --- a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Microsoft.AspNetCore.Authentication.MicrosoftAccount.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - acb45e19-f520-4d0c-8916-b0ceb9c017fe - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountAppBuilderExtensions.cs index 660dd2e81..7fd71d7a9 100644 --- a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountAppBuilderExtensions.cs @@ -1,9 +1,8 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.AspNetCore.Authentication.MicrosoftAccount; -using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Builder { @@ -13,38 +12,26 @@ namespace Microsoft.AspNetCore.Builder public static class MicrosoftAccountAppBuilderExtensions { /// - /// Adds the middleware to the specified , which enables Microsoft Account authentication capabilities. + /// UseMicrosoftAccountAuthentication is obsolete. Configure MicrosoftAccount authentication with AddAuthentication().AddMicrosoftAccount in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. + /// The to add the handler to. /// A reference to this instance after the operation has completed. + [Obsolete("UseMicrosoftAccountAuthentication is obsolete. Configure MicrosoftAccount authentication with AddAuthentication().AddMicrosoftAccount in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)] public static IApplicationBuilder UseMicrosoftAccountAuthentication(this IApplicationBuilder app) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - - return app.UseMiddleware(); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } /// - /// Adds the middleware to the specified , which enables Microsoft Account authentication capabilities. + /// UseMicrosoftAccountAuthentication is obsolete. Configure MicrosoftAccount authentication with AddAuthentication().AddMicrosoftAccount in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. - /// A that specifies options for the middleware. + /// The to add the handler to. + /// A that specifies options for the handler. /// A reference to this instance after the operation has completed. + [Obsolete("UseMicrosoftAccountAuthentication is obsolete. Configure MicrosoftAccount authentication with AddAuthentication().AddMicrosoftAccount in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)] public static IApplicationBuilder UseMicrosoftAccountAuthentication(this IApplicationBuilder app, MicrosoftAccountOptions options) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - return app.UseMiddleware(Options.Create(options)); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountDefaults.cs b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountDefaults.cs index 0d272f979..0421fa14b 100644 --- a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountDefaults.cs +++ b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountDefaults.cs @@ -7,6 +7,9 @@ public static class MicrosoftAccountDefaults { public const string AuthenticationScheme = "Microsoft"; + public static readonly string DisplayName = "Microsoft"; + + // https://developer.microsoft.com/en-us/graph/docs/concepts/auth_v2_user public static readonly string AuthorizationEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"; public static readonly string TokenEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/token"; diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountExtensions.cs b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountExtensions.cs new file mode 100644 index 000000000..7f24e5af7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountExtensions.cs @@ -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.MicrosoftAccount; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class MicrosoftAccountExtensions + { + public static AuthenticationBuilder AddMicrosoftAccount(this AuthenticationBuilder builder) + => builder.AddMicrosoftAccount(MicrosoftAccountDefaults.AuthenticationScheme, _ => { }); + + public static AuthenticationBuilder AddMicrosoftAccount(this AuthenticationBuilder builder, Action configureOptions) + => builder.AddMicrosoftAccount(MicrosoftAccountDefaults.AuthenticationScheme, configureOptions); + + public static AuthenticationBuilder AddMicrosoftAccount(this AuthenticationBuilder builder, string authenticationScheme, Action configureOptions) + => builder.AddMicrosoftAccount(authenticationScheme, MicrosoftAccountDefaults.DisplayName, configureOptions); + + public static AuthenticationBuilder AddMicrosoftAccount(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions) + => builder.AddOAuth(authenticationScheme, displayName, configureOptions); + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountHandler.cs b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountHandler.cs index 21f567d15..bba547277 100644 --- a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountHandler.cs +++ b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountHandler.cs @@ -1,24 +1,23 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; 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.Builder; -using Microsoft.AspNetCore.Http.Authentication; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount { - internal class MicrosoftAccountHandler : OAuthHandler + public class MicrosoftAccountHandler : OAuthHandler { - public MicrosoftAccountHandler(HttpClient httpClient) - : base(httpClient) - { - } + public MicrosoftAccountHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) + : base(options, logger, encoder, clock) + { } protected override async Task CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens) { @@ -28,49 +27,16 @@ protected override async Task CreateTicketAsync(ClaimsIden var response = await Backchannel.SendAsync(request, Context.RequestAborted); if (!response.IsSuccessStatusCode) { - throw new HttpRequestException($"Failed to retrived Microsoft user information ({response.StatusCode}) Please check if the authentication information is correct and the corresponding Microsoft Account API is enabled."); + throw new HttpRequestException($"An error occurred when retrieving Microsoft user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Microsoft Account API is enabled."); } var payload = JObject.Parse(await response.Content.ReadAsStringAsync()); - var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Options.AuthenticationScheme); - var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload); - var identifier = MicrosoftAccountHelper.GetId(payload); - if (!string.IsNullOrEmpty(identifier)) - { - identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, identifier, ClaimValueTypes.String, Options.ClaimsIssuer)); - identity.AddClaim(new Claim("urn:microsoftaccount:id", identifier, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var name = MicrosoftAccountHelper.GetDisplayName(payload); - if (!string.IsNullOrEmpty(name)) - { - identity.AddClaim(new Claim(ClaimTypes.Name, name, ClaimValueTypes.String, Options.ClaimsIssuer)); - identity.AddClaim(new Claim("urn:microsoftaccount:name", name, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var givenName = MicrosoftAccountHelper.GetGivenName(payload); - if (!string.IsNullOrEmpty(givenName)) - { - identity.AddClaim(new Claim(ClaimTypes.GivenName, givenName, ClaimValueTypes.String, Options.ClaimsIssuer)); - identity.AddClaim(new Claim("urn:microsoftaccount:givenname", givenName, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var surname = MicrosoftAccountHelper.GetSurname(payload); - if (!string.IsNullOrEmpty(surname)) - { - identity.AddClaim(new Claim(ClaimTypes.Surname, surname, ClaimValueTypes.String, Options.ClaimsIssuer)); - identity.AddClaim(new Claim("urn:microsoftaccount:surname", surname, ClaimValueTypes.String, Options.ClaimsIssuer)); - } - - var email = MicrosoftAccountHelper.GetEmail(payload); - if (!string.IsNullOrEmpty(email)) - { - identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String, Options.ClaimsIssuer)); - } + var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload); + context.RunClaimActions(); - await Options.Events.CreatingTicket(context); - return context.Ticket; + await Events.CreatingTicket(context); + return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name); } } } diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountHelper.cs b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountHelper.cs deleted file mode 100644 index cce8dcc73..000000000 --- a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountHelper.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Newtonsoft.Json.Linq; - -namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount -{ - /// - /// Contains static methods that allow to extract user's information from a - /// instance retrieved from Microsoft after a successful authentication process. - /// http://graph.microsoft.io/en-us/docs/api-reference/v1.0/resources/user - /// - public static class MicrosoftAccountHelper - { - /// - /// Gets the Microsoft Account user ID. - /// - public static string GetId(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("id"); - } - - /// - /// Gets the user's name. - /// - public static string GetDisplayName(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("displayName"); - } - - /// - /// Gets the user's given name. - /// - public static string GetGivenName(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("givenName"); - } - - /// - /// Gets the user's surname. - /// - public static string GetSurname(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("surname"); - } - - /// - /// Gets the user's email address. - /// - public static string GetEmail(JObject user) - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - return user.Value("mail") ?? user.Value("userPrincipalName"); - } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountMiddleware.cs b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountMiddleware.cs deleted file mode 100644 index 3ad1bf557..000000000 --- a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountMiddleware.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Text.Encodings.Web; -using Microsoft.AspNetCore.Authentication.OAuth; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.DataProtection; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount -{ - /// - /// An ASP.NET Core middleware for authenticating users using the Microsoft Account service. - /// - public class MicrosoftAccountMiddleware : OAuthMiddleware - { - /// - /// Initializes a new . - /// - /// The next middleware in the HTTP pipeline to invoke. - /// - /// - /// - /// - /// Configuration options for the middleware. - public MicrosoftAccountMiddleware( - RequestDelegate next, - IDataProtectionProvider dataProtectionProvider, - ILoggerFactory loggerFactory, - UrlEncoder encoder, - IOptions sharedOptions, - IOptions options) - : base(next, dataProtectionProvider, loggerFactory, encoder, sharedOptions, options) - { - if (next == null) - { - throw new ArgumentNullException(nameof(next)); - } - - if (dataProtectionProvider == null) - { - throw new ArgumentNullException(nameof(dataProtectionProvider)); - } - - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - if (encoder == null) - { - throw new ArgumentNullException(nameof(encoder)); - } - - if (sharedOptions == null) - { - throw new ArgumentNullException(nameof(sharedOptions)); - } - - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - } - - /// - /// Provides the object for processing authentication-related requests. - /// - /// An configured with the supplied to the constructor. - protected override AuthenticationHandler CreateHandler() - { - return new MicrosoftAccountHandler(Backchannel); - } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountOptions.cs b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountOptions.cs index 625d4baf9..dbca3507e 100644 --- a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountOptions.cs +++ b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/MicrosoftAccountOptions.cs @@ -1,13 +1,16 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Http; +using System.Security.Claims; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.MicrosoftAccount; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Authentication.OAuth; -namespace Microsoft.AspNetCore.Builder +namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount { /// - /// Configuration options for . + /// Configuration options for . /// public class MicrosoftAccountOptions : OAuthOptions { @@ -16,13 +19,17 @@ public class MicrosoftAccountOptions : OAuthOptions /// public MicrosoftAccountOptions() { - AuthenticationScheme = MicrosoftAccountDefaults.AuthenticationScheme; - DisplayName = AuthenticationScheme; CallbackPath = new PathString("/signin-microsoft"); AuthorizationEndpoint = MicrosoftAccountDefaults.AuthorizationEndpoint; TokenEndpoint = MicrosoftAccountDefaults.TokenEndpoint; UserInformationEndpoint = MicrosoftAccountDefaults.UserInformationEndpoint; Scope.Add("https://graph.microsoft.com/user.read"); + + ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id"); + ClaimActions.MapJsonKey(ClaimTypes.Name, "displayName"); + ClaimActions.MapJsonKey(ClaimTypes.GivenName, "givenName"); + ClaimActions.MapJsonKey(ClaimTypes.Surname, "surname"); + ClaimActions.MapCustomJson(ClaimTypes.Email, user => user.Value("mail") ?? user.Value("userPrincipalName")); } } } diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff..000000000 --- a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Properties/Resources.Designer.cs index 618d143ee..7ef5acecb 100644 --- a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/Properties/Resources.Designer.cs @@ -15,48 +15,42 @@ private static readonly ResourceManager _resourceManager /// internal static string Exception_MissingId { - get { return GetString("Exception_MissingId"); } + get => GetString("Exception_MissingId"); } /// /// The user does not have an id. /// internal static string FormatException_MissingId() - { - return GetString("Exception_MissingId"); - } + => GetString("Exception_MissingId"); /// /// The '{0}' option must be provided. /// internal static string Exception_OptionMustBeProvided { - get { return GetString("Exception_OptionMustBeProvided"); } + get => GetString("Exception_OptionMustBeProvided"); } /// /// The '{0}' option must be provided. /// internal static string FormatException_OptionMustBeProvided(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); /// /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler. /// internal static string Exception_ValidatorHandlerMismatch { - get { return GetString("Exception_ValidatorHandlerMismatch"); } + get => GetString("Exception_ValidatorHandlerMismatch"); } /// /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler. /// internal static string FormatException_ValidatorHandlerMismatch() - { - return GetString("Exception_ValidatorHandlerMismatch"); - } + => GetString("Exception_ValidatorHandlerMismatch"); private static string GetString(string name, params string[] formatterNames) { diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/baseline.net45.json b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/baseline.net45.json deleted file mode 100644 index 06b3cd0d5..000000000 --- a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/baseline.net45.json +++ /dev/null @@ -1,256 +0,0 @@ -{ - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.MicrosoftAccount, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", - "Types": [ - { - "Name": "Microsoft.AspNetCore.Authentication.MicrosoftAccount.MicrosoftAccountDefaults", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "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": "\"Microsoft\"" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.MicrosoftAccount.MicrosoftAccountHelper", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "GetId", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetDisplayName", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetGivenName", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetSurname", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "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.MicrosoftAccount.MicrosoftAccountMiddleware", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthMiddleware", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "CreateHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" - }, - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" - }, - { - "Name": "sharedOptions", - "Type": "Microsoft.Extensions.Options.IOptions" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.MicrosoftAccountAppBuilderExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "UseMicrosoftAccountAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "UseMicrosoftAccountAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.MicrosoftAccountOptions" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.MicrosoftAccountOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.OAuthOptions", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - } - ], - "SourceFilters": [] -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/baseline.netcore.json b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/baseline.netcore.json index 06b3cd0d5..877e9035a 100644 --- a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/baseline.netcore.json @@ -1,8 +1,8 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.MicrosoftAccount, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.MicrosoftAccount, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { - "Name": "Microsoft.AspNetCore.Authentication.MicrosoftAccount.MicrosoftAccountDefaults", + "Name": "Microsoft.Extensions.DependencyInjection.MicrosoftAccountExtensions", "Visibility": "Public", "Kind": "Class", "Abstract": true, @@ -11,51 +11,94 @@ "ImplementedInterfaces": [], "Members": [ { - "Kind": "Field", - "Name": "AuthorizationEndpoint", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "AddMicrosoftAccount", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, - "ReadOnly": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "TokenEndpoint", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "AddMicrosoftAccount", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, - "ReadOnly": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "UserInformationEndpoint", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "AddMicrosoftAccount", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, - "ReadOnly": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "AddMicrosoftAccount", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, + "Extension": true, "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"Microsoft\"" + "GenericParameter": [] } ], "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.MicrosoftAccount.MicrosoftAccountHelper", + "Name": "Microsoft.AspNetCore.Authentication.MicrosoftAccount.MicrosoftAccountDefaults", "Visibility": "Public", "Kind": "Class", "Abstract": true, @@ -64,90 +107,84 @@ "ImplementedInterfaces": [], "Members": [ { - "Kind": "Method", - "Name": "GetId", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], + "Kind": "Field", + "Name": "DisplayName", + "Parameters": [], "ReturnType": "System.String", "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "GetDisplayName", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], + "Kind": "Field", + "Name": "AuthorizationEndpoint", + "Parameters": [], "ReturnType": "System.String", "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "GetGivenName", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], + "Kind": "Field", + "Name": "TokenEndpoint", + "Parameters": [], "ReturnType": "System.String", "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "GetSurname", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], + "Kind": "Field", + "Name": "UserInformationEndpoint", + "Parameters": [], "ReturnType": "System.String", "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "GetEmail", - "Parameters": [ - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], + "Kind": "Field", + "Name": "AuthenticationScheme", + "Parameters": [], "ReturnType": "System.String", "Static": true, "Visibility": "Public", - "GenericParameter": [] + "GenericParameter": [], + "Constant": true, + "Literal": "\"Microsoft\"" } ], "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.MicrosoftAccount.MicrosoftAccountMiddleware", + "Name": "Microsoft.AspNetCore.Authentication.MicrosoftAccount.MicrosoftAccountHandler", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthMiddleware", + "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "CreateHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "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", "Virtual": true, "Override": true, "Visibility": "Protected", @@ -158,15 +195,11 @@ "Name": ".ctor", "Parameters": [ { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" }, { - "Name": "loggerFactory", + "Name": "logger", "Type": "Microsoft.Extensions.Logging.ILoggerFactory" }, { @@ -174,12 +207,8 @@ "Type": "System.Text.Encodings.Web.UrlEncoder" }, { - "Name": "sharedOptions", - "Type": "Microsoft.Extensions.Options.IOptions" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" + "Name": "clock", + "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" } ], "Visibility": "Public", @@ -188,6 +217,23 @@ ], "GenericParameters": [] }, + { + "Name": "Microsoft.AspNetCore.Authentication.MicrosoftAccount.MicrosoftAccountOptions", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, { "Name": "Microsoft.AspNetCore.Builder.MicrosoftAccountAppBuilderExtensions", "Visibility": "Public", @@ -222,7 +268,7 @@ }, { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.MicrosoftAccountOptions" + "Type": "Microsoft.AspNetCore.Authentication.MicrosoftAccount.MicrosoftAccountOptions" } ], "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", @@ -233,24 +279,6 @@ } ], "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.MicrosoftAccountOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.OAuthOptions", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] } - ], - "SourceFilters": [] + ] } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/project.json b/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/project.json deleted file mode 100644 index 634b455af..000000000 --- a/src/Microsoft.AspNetCore.Authentication.MicrosoftAccount/project.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core middleware that enables an application to support the Microsoft Account authentication workflow.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/security" - }, - "tags": [ - "aspnetcore", - "authentication", - "security" - ] - }, - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "dependencies": { - "Microsoft.AspNetCore.Authentication.OAuth": { - "target": "project" - }, - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/ClaimAction.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/ClaimAction.cs new file mode 100644 index 000000000..78b63bb38 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/ClaimAction.cs @@ -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 Newtonsoft.Json.Linq; + +namespace Microsoft.AspNetCore.Authentication.OAuth.Claims +{ + /// + /// Infrastructure for mapping user data from a json structure to claims on the ClaimsIdentity. + /// + public abstract class ClaimAction + { + /// + /// Create a new claim manipulation action. + /// + /// The value to use for Claim.Type when creating a Claim. + /// The value to use for Claim.ValueType when creating a Claim. + public ClaimAction(string claimType, string valueType) + { + ClaimType = claimType; + ValueType = valueType; + } + + /// + /// The value to use for Claim.Type when creating a Claim. + /// + public string ClaimType { get; } + + // The value to use for Claim.ValueType when creating a Claim. + public string ValueType { get; } + + /// + /// Examine the given userData json, determine if the requisite data is present, and optionally add it + /// as a new Claim on the ClaimsIdentity. + /// + /// The source data to examine. This value may be null. + /// The identity to add Claims to. + /// The value to use for Claim.Issuer when creating a Claim. + public abstract void Run(JObject userData, ClaimsIdentity identity, string issuer); + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/ClaimActionCollection.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/ClaimActionCollection.cs new file mode 100644 index 000000000..63da155d7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/ClaimActionCollection.cs @@ -0,0 +1,52 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.AspNetCore.Authentication.OAuth.Claims +{ + /// + /// A collection of ClaimActions used when mapping user data to Claims. + /// + public class ClaimActionCollection : IEnumerable + { + private IList Actions { get; } = new List(); + + /// + /// Remove all claim actions. + /// + public void Clear() => Actions.Clear(); + + /// + /// Remove all claim actions for the given ClaimType. + /// + /// The ClaimType of maps to remove. + public void Remove(string claimType) + { + var itemsToRemove = Actions.Where(map => string.Equals(claimType, map.ClaimType, StringComparison.OrdinalIgnoreCase)).ToList(); + itemsToRemove.ForEach(map => Actions.Remove(map)); + } + + /// + /// Add a claim action to the collection. + /// + /// The claim action to add. + public void Add(ClaimAction action) + { + Actions.Add(action); + } + + public IEnumerator GetEnumerator() + { + return Actions.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return Actions.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/ClaimActionCollectionMapExtensions.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/ClaimActionCollectionMapExtensions.cs new file mode 100644 index 000000000..5a178957a --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/ClaimActionCollectionMapExtensions.cs @@ -0,0 +1,139 @@ +// 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.Authentication.OAuth.Claims; +using Newtonsoft.Json.Linq; + +namespace Microsoft.AspNetCore.Authentication +{ + public static class ClaimActionCollectionMapExtensions + { + /// + /// Select a top level value from the json user data with the given key name and add it as a Claim. + /// This no-ops if the key is not found or the value is empty. + /// + /// + /// The value to use for Claim.Type when creating a Claim. + /// The top level key to look for in the json user data. + public static void MapJsonKey(this ClaimActionCollection collection, string claimType, string jsonKey) + { + collection.MapJsonKey(claimType, jsonKey, ClaimValueTypes.String); + } + + /// + /// Select a top level value from the json user data with the given key name and add it as a Claim. + /// This no-ops if the key is not found or the value is empty. + /// + /// + /// The value to use for Claim.Type when creating a Claim. + /// The top level key to look for in the json user data. + /// The value to use for Claim.ValueType when creating a Claim. + public static void MapJsonKey(this ClaimActionCollection collection, string claimType, string jsonKey, string valueType) + { + collection.Add(new JsonKeyClaimAction(claimType, valueType, jsonKey)); + } + + /// + /// Select a second level value from the json user data with the given top level key name and second level sub key name and add it as a Claim. + /// This no-ops if the keys are not found or the value is empty. + /// + /// + /// The value to use for Claim.Type when creating a Claim. + /// The top level key to look for in the json user data. + /// The second level key to look for in the json user data. + public static void MapJsonSubKey(this ClaimActionCollection collection, string claimType, string jsonKey, string subKey) + { + collection.MapJsonSubKey(claimType, jsonKey, subKey, ClaimValueTypes.String); + } + + /// + /// Select a second level value from the json user data with the given top level key name and second level sub key name and add it as a Claim. + /// This no-ops if the keys are not found or the value is empty. + /// + /// + /// The value to use for Claim.Type when creating a Claim. + /// The top level key to look for in the json user data. + /// The second level key to look for in the json user data. + /// The value to use for Claim.ValueType when creating a Claim. + public static void MapJsonSubKey(this ClaimActionCollection collection, string claimType, string jsonKey, string subKey, string valueType) + { + collection.Add(new JsonSubKeyClaimAction(claimType, valueType, jsonKey, subKey)); + } + + /// + /// Run the given resolver to select a value from the json user data to add as a claim. + /// This no-ops if the returned value is empty. + /// + /// + /// The value to use for Claim.Type when creating a Claim. + /// The Func that will be called to select value from the given json user data. + public static void MapCustomJson(this ClaimActionCollection collection, string claimType, Func resolver) + { + collection.MapCustomJson(claimType, ClaimValueTypes.String, resolver); + } + + /// + /// Run the given resolver to select a value from the json user data to add as a claim. + /// This no-ops if the returned value is empty. + /// + /// + /// The value to use for Claim.Type when creating a Claim. + /// The value to use for Claim.ValueType when creating a Claim. + /// The Func that will be called to select value from the given json user data. + public static void MapCustomJson(this ClaimActionCollection collection, string claimType, string valueType, Func resolver) + { + collection.Add(new CustomJsonClaimAction(claimType, valueType, resolver)); + } + + /// + /// Clears any current ClaimsActions and maps all values from the json user data as claims, excluding duplicates. + /// + /// + public static void MapAll(this ClaimActionCollection collection) + { + collection.Clear(); + collection.Add(new MapAllClaimsAction()); + } + + /// + /// Clears any current ClaimsActions and maps all values from the json user data as claims, excluding the specified types. + /// + /// + /// + public static void MapAllExcept(this ClaimActionCollection collection, params string[] exclusions) + { + collection.MapAll(); + collection.DeleteClaims(exclusions); + } + + /// + /// Delete all claims from the given ClaimsIdentity with the given ClaimType. + /// + /// + /// + public static void DeleteClaim(this ClaimActionCollection collection, string claimType) + { + collection.Add(new DeleteClaimAction(claimType)); + } + + /// + /// Delete all claims from the ClaimsIdentity with the given claimTypes. + /// + /// + /// + public static void DeleteClaims(this ClaimActionCollection collection, params string[] claimTypes) + { + if (claimTypes == null) + { + throw new ArgumentNullException(nameof(claimTypes)); + } + + foreach (var claimType in claimTypes) + { + collection.Add(new DeleteClaimAction(claimType)); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/CustomJsonClaimAction.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/CustomJsonClaimAction.cs new file mode 100644 index 000000000..21a4f70e1 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/CustomJsonClaimAction.cs @@ -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 System; +using System.Security.Claims; +using Newtonsoft.Json.Linq; + +namespace Microsoft.AspNetCore.Authentication.OAuth.Claims +{ + /// + /// A ClaimAction that selects the value from the json user data by running the given Func resolver. + /// + public class CustomJsonClaimAction : ClaimAction + { + /// + /// Creates a new CustomJsonClaimAction. + /// + /// The value to use for Claim.Type when creating a Claim. + /// The value to use for Claim.ValueType when creating a Claim. + /// The Func that will be called to select value from the given json user data. + public CustomJsonClaimAction(string claimType, string valueType, Func resolver) + : base(claimType, valueType) + { + Resolver = resolver; + } + + /// + /// The Func that will be called to select value from the given json user data. + /// + public Func Resolver { get; } + + /// + public override void Run(JObject userData, ClaimsIdentity identity, string issuer) + { + if (userData == null) + { + return; + } + var value = Resolver(userData); + if (!string.IsNullOrEmpty(value)) + { + identity.AddClaim(new Claim(ClaimType, value, ValueType, issuer)); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/DeleteClaimAction.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/DeleteClaimAction.cs new file mode 100644 index 000000000..75167cabc --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/DeleteClaimAction.cs @@ -0,0 +1,33 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Linq; +using System.Security.Claims; +using Newtonsoft.Json.Linq; + +namespace Microsoft.AspNetCore.Authentication.OAuth.Claims +{ + /// + /// A ClaimAction that deletes all claims from the given ClaimsIdentity with the given ClaimType. + /// + public class DeleteClaimAction : ClaimAction + { + /// + /// Creates a new DeleteClaimAction. + /// + /// The ClaimType of Claims to delete. + public DeleteClaimAction(string claimType) + : base(claimType, ClaimValueTypes.String) + { + } + + /// + public override void Run(JObject userData, ClaimsIdentity identity, string issuer) + { + foreach (var claim in identity.FindAll(ClaimType).ToList()) + { + identity.TryRemoveClaim(claim); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/JsonKeyClaimAction.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/JsonKeyClaimAction.cs new file mode 100644 index 000000000..ccd1a965d --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/JsonKeyClaimAction.cs @@ -0,0 +1,57 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Security.Claims; +using Newtonsoft.Json.Linq; + +namespace Microsoft.AspNetCore.Authentication.OAuth.Claims +{ + /// + /// A ClaimAction that selects a top level value from the json user data with the given key name and adds it as a Claim. + /// This no-ops if the key is not found or the value is empty. + /// + public class JsonKeyClaimAction : ClaimAction + { + /// + /// Creates a new JsonKeyClaimAction. + /// + /// The value to use for Claim.Type when creating a Claim. + /// The value to use for Claim.ValueType when creating a Claim. + /// The top level key to look for in the json user data. + public JsonKeyClaimAction(string claimType, string valueType, string jsonKey) + : base(claimType, valueType) + { + JsonKey = jsonKey; + } + + /// + /// The top level key to look for in the json user data. + /// + public string JsonKey { get; } + + /// + public override void Run(JObject userData, ClaimsIdentity identity, string issuer) + { + var value = userData?[JsonKey]; + if (value is JValue) + { + AddClaim(value?.ToString(), identity, issuer); + } + else if (value is JArray) + { + foreach (var v in value) + { + AddClaim(v?.ToString(), identity, issuer); + } + } + } + + private void AddClaim(string value, ClaimsIdentity identity, string issuer) + { + if (!string.IsNullOrEmpty(value)) + { + identity.AddClaim(new Claim(ClaimType, value, ValueType, issuer)); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/JsonSubKeyClaimAction.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/JsonSubKeyClaimAction.cs new file mode 100644 index 000000000..bc29672d0 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/JsonSubKeyClaimAction.cs @@ -0,0 +1,58 @@ +// 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 Newtonsoft.Json.Linq; +using System.Security.Claims; + +namespace Microsoft.AspNetCore.Authentication.OAuth.Claims +{ + /// + /// A ClaimAction that selects a second level value from the json user data with the given top level key + /// name and second level sub key name and add it as a Claim. + /// This no-ops if the keys are not found or the value is empty. + /// + public class JsonSubKeyClaimAction : JsonKeyClaimAction + { + /// + /// Creates a new JsonSubKeyClaimAction. + /// + /// The value to use for Claim.Type when creating a Claim. + /// The value to use for Claim.ValueType when creating a Claim. + /// The top level key to look for in the json user data. + /// The second level key to look for in the json user data. + public JsonSubKeyClaimAction(string claimType, string valueType, string jsonKey, string subKey) + : base(claimType, valueType, jsonKey) + { + SubKey = subKey; + } + + /// + /// The second level key to look for in the json user data. + /// + public string SubKey { get; } + + /// + public override void Run(JObject userData, ClaimsIdentity identity, string issuer) + { + var value = GetValue(userData, JsonKey, SubKey); + if (!string.IsNullOrEmpty(value)) + { + identity.AddClaim(new Claim(ClaimType, value, ValueType, issuer)); + } + } + + // Get the given subProperty from a property. + private static string GetValue(JObject userData, string propertyName, string subProperty) + { + if (userData != null && userData.TryGetValue(propertyName, out var value)) + { + var subObject = JObject.Parse(value.ToString()); + if (subObject != null && subObject.TryGetValue(subProperty, out value)) + { + return value.ToString(); + } + } + return null; + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/MapAllClaimsAction.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/MapAllClaimsAction.cs new file mode 100644 index 000000000..b3bf5d99f --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/Claims/MapAllClaimsAction.cs @@ -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; +using System.Security.Claims; +using Newtonsoft.Json.Linq; + +namespace Microsoft.AspNetCore.Authentication.OAuth.Claims +{ + /// + /// A ClaimAction that selects all top level values from the json user data and adds them as Claims. + /// This excludes duplicate sets of names and values. + /// + public class MapAllClaimsAction : ClaimAction + { + public MapAllClaimsAction() : base("All", ClaimValueTypes.String) + { + } + + public override void Run(JObject userData, ClaimsIdentity identity, string issuer) + { + if (userData == null) + { + return; + } + foreach (var pair in userData) + { + var claimValue = userData.TryGetValue(pair.Key, out var value) ? value.ToString() : null; + + // Avoid adding a claim if there's a duplicate name and value. This often happens in OIDC when claims are + // retrieved both from the id_token and from the user-info endpoint. + var duplicate = identity.FindFirst(c => string.Equals(c.Type, pair.Key, StringComparison.OrdinalIgnoreCase) + && string.Equals(c.Value, claimValue, StringComparison.Ordinal)) != null; + + if (!duplicate) + { + identity.AddClaim(new Claim(pair.Key, claimValue, ClaimValueTypes.String, issuer)); + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Events/IOAuthEvents.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Events/IOAuthEvents.cs deleted file mode 100644 index 29316732c..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/Events/IOAuthEvents.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Authentication.OAuth -{ - /// - /// Specifies callback methods which the invokes to enable developer control over the authentication process. - /// - public interface IOAuthEvents : IRemoteAuthenticationEvents - { - /// - /// Invoked after the provider successfully authenticates a user. This can be used to retrieve user information. - /// This event may not be invoked by sub-classes of OAuthAuthenticationHandler if they override CreateTicketAsync. - /// - /// Contains information about the login session. - /// A representing the completed operation. - Task CreatingTicket(OAuthCreatingTicketContext context); - - /// - /// Called when a Challenge causes a redirect to the authorize endpoint. - /// - /// Contains redirect URI and of the challenge. - Task RedirectToAuthorizationEndpoint(OAuthRedirectToAuthorizationContext context); - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Events/OAuthCreatingTicketContext.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Events/OAuthCreatingTicketContext.cs index 15f9c91c7..f660dd224 100644 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/Events/OAuthCreatingTicketContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/Events/OAuthCreatingTicketContext.cs @@ -5,7 +5,6 @@ using System.Globalization; using System.Net.Http; using System.Security.Claims; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Newtonsoft.Json.Linq; @@ -14,54 +13,51 @@ namespace Microsoft.AspNetCore.Authentication.OAuth /// /// Contains information about the login session as well as the user . /// - public class OAuthCreatingTicketContext : BaseContext + public class OAuthCreatingTicketContext : ResultContext { /// /// Initializes a new . /// - /// The . + /// The . + /// The . /// The HTTP environment. + /// The authentication scheme. /// The options used by the authentication middleware. /// The HTTP client used by the authentication middleware /// The tokens returned from the token endpoint. public OAuthCreatingTicketContext( - AuthenticationTicket ticket, + ClaimsPrincipal principal, + AuthenticationProperties properties, HttpContext context, + AuthenticationScheme scheme, OAuthOptions options, HttpClient backchannel, OAuthTokenResponse tokens) - : this(ticket, context, options, backchannel, tokens, user: new JObject()) - { - } + : this(principal, properties, context, scheme, options, backchannel, tokens, user: new JObject()) + { } /// /// Initializes a new . /// - /// The . + /// The . + /// The . /// The HTTP environment. + /// The authentication scheme. /// The options used by the authentication middleware. /// The HTTP client used by the authentication middleware /// The tokens returned from the token endpoint. /// The JSON-serialized user. public OAuthCreatingTicketContext( - AuthenticationTicket ticket, + ClaimsPrincipal principal, + AuthenticationProperties properties, HttpContext context, + AuthenticationScheme scheme, OAuthOptions options, HttpClient backchannel, OAuthTokenResponse tokens, JObject user) - : base(context) + : base(context, scheme, options) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - if (backchannel == null) { throw new ArgumentNullException(nameof(backchannel)); @@ -80,12 +76,10 @@ public OAuthCreatingTicketContext( TokenResponse = tokens; Backchannel = backchannel; User = user; - Options = options; - Ticket = ticket; + Principal = principal; + Properties = properties; } - public OAuthOptions Options { get; } - /// /// Gets the JSON-serialized user or an empty /// if it is not available. @@ -135,14 +129,24 @@ public TimeSpan? ExpiresIn public HttpClient Backchannel { get; } /// - /// The that will be created. + /// Gets the main identity exposed by the authentication ticket. + /// This property returns null when the ticket is null. /// - public AuthenticationTicket Ticket { get; set; } + public ClaimsIdentity Identity => Principal?.Identity as ClaimsIdentity; - /// - /// Gets the main identity exposed by . - /// This property returns null when is null. - /// - public ClaimsIdentity Identity => Ticket?.Principal.Identity as ClaimsIdentity; + public void RunClaimActions() => RunClaimActions(User); + + public void RunClaimActions(JObject userData) + { + if (userData == null) + { + throw new ArgumentNullException(nameof(userData)); + } + + foreach (var action in Options.ClaimActions) + { + action.Run(userData, Identity, Options.ClaimsIssuer ?? Scheme.Name); + } + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Events/OAuthEvents.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Events/OAuthEvents.cs index 066b324b7..9e194491b 100644 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/Events/OAuthEvents.cs +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/Events/OAuthEvents.cs @@ -3,27 +3,26 @@ using System; using System.Threading.Tasks; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Authentication.OAuth { /// - /// Default implementation. + /// Default implementation. /// - public class OAuthEvents : RemoteAuthenticationEvents, IOAuthEvents + public class OAuthEvents : RemoteAuthenticationEvents { /// /// Gets or sets the function that is invoked when the CreatingTicket method is invoked. /// - public Func OnCreatingTicket { get; set; } = context => TaskCache.CompletedTask; + public Func OnCreatingTicket { get; set; } = context => Task.CompletedTask; /// /// Gets or sets the delegate that is invoked when the RedirectToAuthorizationEndpoint method is invoked. /// - public Func OnRedirectToAuthorizationEndpoint { get; set; } = context => + public Func, Task> OnRedirectToAuthorizationEndpoint { get; set; } = context => { context.Response.Redirect(context.RedirectUri); - return TaskCache.CompletedTask; + return Task.CompletedTask; }; /// @@ -34,9 +33,9 @@ public class OAuthEvents : RemoteAuthenticationEvents, IOAuthEvents public virtual Task CreatingTicket(OAuthCreatingTicketContext context) => OnCreatingTicket(context); /// - /// Called when a Challenge causes a redirect to authorize endpoint in the OAuth middleware. + /// Called when a Challenge causes a redirect to authorize endpoint in the OAuth handler. /// - /// Contains redirect URI and of the challenge. - public virtual Task RedirectToAuthorizationEndpoint(OAuthRedirectToAuthorizationContext context) => OnRedirectToAuthorizationEndpoint(context); + /// Contains redirect URI and of the challenge. + public virtual Task RedirectToAuthorizationEndpoint(RedirectContext context) => OnRedirectToAuthorizationEndpoint(context); } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Events/OAuthRedirectToAuthorizationContext.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Events/OAuthRedirectToAuthorizationContext.cs deleted file mode 100644 index 63eaa3537..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/Events/OAuthRedirectToAuthorizationContext.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; - -namespace Microsoft.AspNetCore.Authentication.OAuth -{ - /// - /// Context passed when a Challenge causes a redirect to authorize endpoint in the middleware. - /// - public class OAuthRedirectToAuthorizationContext : BaseContext - { - /// - /// Creates a new context object. - /// - /// The HTTP request context. - /// The . - /// The authentication properties of the challenge. - /// The initial redirect URI. - public OAuthRedirectToAuthorizationContext(HttpContext context, OAuthOptions options, AuthenticationProperties properties, string redirectUri) - : base(context) - { - RedirectUri = redirectUri; - Properties = properties; - Options = options; - } - - public OAuthOptions Options { get; } - - /// - /// Gets the URI used for the redirect operation. - /// - public string RedirectUri { get; private set; } - - /// - /// Gets the authentication properties of the challenge. - /// - public AuthenticationProperties Properties { get; private set; } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Microsoft.AspNetCore.Authentication.OAuth.csproj b/src/Microsoft.AspNetCore.Authentication.OAuth/Microsoft.AspNetCore.Authentication.OAuth.csproj new file mode 100644 index 000000000..97d4a9703 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/Microsoft.AspNetCore.Authentication.OAuth.csproj @@ -0,0 +1,19 @@ + + + + ASP.NET Core middleware that enables an application to support any standard OAuth 2.0 authentication workflow. + netcoreapp3.0 + $(NoWarn);CS1591 + true + aspnetcore;authentication;security + + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Microsoft.AspNetCore.Authentication.OAuth.xproj b/src/Microsoft.AspNetCore.Authentication.OAuth/Microsoft.AspNetCore.Authentication.OAuth.xproj deleted file mode 100644 index 20b825dca..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/Microsoft.AspNetCore.Authentication.OAuth.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 1657c79e-7755-4aee-9d61-571295b69a30 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthAppBuilderExtensions.cs index eebeaf7a3..d55f311f7 100644 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthAppBuilderExtensions.cs @@ -1,9 +1,8 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.AspNetCore.Authentication.OAuth; -using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Builder { @@ -13,38 +12,26 @@ namespace Microsoft.AspNetCore.Builder public static class OAuthAppBuilderExtensions { /// - /// Adds the middleware to the specified , which enables OAuth 2.0 authentication capabilities. + /// UseOAuthAuthentication is obsolete. Configure OAuth authentication with AddAuthentication().AddOAuth in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. + /// The to add the handler to. /// A reference to this instance after the operation has completed. + [Obsolete("UseOAuthAuthentication is obsolete. Configure OAuth authentication with AddAuthentication().AddOAuth in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)] public static IApplicationBuilder UseOAuthAuthentication(this IApplicationBuilder app) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - - return app.UseMiddleware>(); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } /// - /// Adds the middleware to the specified , which enables OAuth 2.0 authentication capabilities. + /// UseOAuthAuthentication is obsolete. Configure OAuth authentication with AddAuthentication().AddOAuth in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. - /// A that specifies options for the middleware. + /// The to add the handler to. + /// A that specifies options for the handler. /// A reference to this instance after the operation has completed. + [Obsolete("UseOAuthAuthentication is obsolete. Configure OAuth authentication with AddAuthentication().AddOAuth in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)] public static IApplicationBuilder UseOAuthAuthentication(this IApplicationBuilder app, OAuthOptions options) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - return app.UseMiddleware>(Options.Create(options)); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthChallengeProperties.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthChallengeProperties.cs new file mode 100644 index 000000000..fc768a8ac --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthChallengeProperties.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Authentication.OAuth +{ + public class OAuthChallengeProperties : AuthenticationProperties + { + /// + /// The parameter key for the "scope" argument being used for a challenge request. + /// + public static readonly string ScopeKey = "scope"; + + public OAuthChallengeProperties() + { } + + public OAuthChallengeProperties(IDictionary items) + : base(items) + { } + + public OAuthChallengeProperties(IDictionary items, IDictionary parameters) + : base(items, parameters) + { } + + /// + /// The "scope" parameter value being used for a challenge request. + /// + public ICollection Scope + { + get => GetParameter>(ScopeKey); + set => SetParameter(ScopeKey, value); + } + + /// + /// Set the "scope" parameter value. + /// + /// List of scopes. + public virtual void SetScope(params string[] scopes) + { + Scope = scopes; + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthDefaults.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthDefaults.cs new file mode 100644 index 000000000..376f8ab01 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthDefaults.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Authentication.OAuth +{ + public static class OAuthDefaults + { + public static readonly string DisplayName = "OAuth"; + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthExtensions.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthExtensions.cs new file mode 100644 index 000000000..22c541a0a --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthExtensions.cs @@ -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; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.OAuth; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class OAuthExtensions + { + public static AuthenticationBuilder AddOAuth(this AuthenticationBuilder builder, string authenticationScheme, Action configureOptions) + => builder.AddOAuth>(authenticationScheme, configureOptions); + + public static AuthenticationBuilder AddOAuth(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions) + => builder.AddOAuth>(authenticationScheme, displayName, configureOptions); + + public static AuthenticationBuilder AddOAuth(this AuthenticationBuilder builder, string authenticationScheme, Action configureOptions) + where TOptions : OAuthOptions, new() + where THandler : OAuthHandler + => builder.AddOAuth(authenticationScheme, OAuthDefaults.DisplayName, configureOptions); + + public static AuthenticationBuilder AddOAuth(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions) + where TOptions : OAuthOptions, new() + where THandler : OAuthHandler + { + builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton, OAuthPostConfigureOptions>()); + return builder.AddRemoteScheme(authenticationScheme, displayName, configureOptions); + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthHandler.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthHandler.cs index 1c5143842..05ba4df68 100644 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthHandler.cs +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthHandler.cs @@ -8,34 +8,71 @@ using System.Net.Http.Headers; using System.Security.Claims; using System.Text; +using System.Text.Encodings.Web; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.AspNetCore.Http.Features.Authentication; +using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; using Newtonsoft.Json.Linq; -using Microsoft.AspNetCore.WebUtilities; namespace Microsoft.AspNetCore.Authentication.OAuth { - public class OAuthHandler : RemoteAuthenticationHandler where TOptions : OAuthOptions + public class OAuthHandler : RemoteAuthenticationHandler where TOptions : OAuthOptions, new() { - public OAuthHandler(HttpClient backchannel) + protected HttpClient Backchannel => Options.Backchannel; + + /// + /// 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. + /// + protected new OAuthEvents Events { - Backchannel = backchannel; + get { return (OAuthEvents)base.Events; } + set { base.Events = value; } } - protected HttpClient Backchannel { get; private set; } + public OAuthHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) + : base(options, logger, encoder, clock) + { } - protected override async Task HandleRemoteAuthenticateAsync() + /// + /// Creates a new instance of the events instance. + /// + /// A new instance of the events instance. + protected override Task CreateEventsAsync() => Task.FromResult(new OAuthEvents()); + + protected override async Task HandleRemoteAuthenticateAsync() { - AuthenticationProperties properties = null; var query = Request.Query; + var state = query["state"]; + var properties = Options.StateDataFormat.Unprotect(state); + + if (properties == null) + { + return HandleRequestResult.Fail("The oauth state was missing or invalid."); + } + + // OAuth2 10.12 CSRF + if (!ValidateCorrelationId(properties)) + { + return HandleRequestResult.Fail("Correlation failed.", properties); + } + var error = query["error"]; if (!StringValues.IsNullOrEmpty(error)) { + // Note: access_denied errors are special protocol errors indicating the user didn't + // approve the authorization demand requested by the remote authorization server. + // Since it's a frequent scenario (that is not caused by incorrect configuration), + // denied errors are handled differently using HandleAccessDeniedErrorAsync(). + // Visit https://tools.ietf.org/html/rfc6749#section-4.1.2.1 for more information. + if (StringValues.Equals(error, "access_denied")) + { + return await HandleAccessDeniedErrorAsync(properties); + } + var failureMessage = new StringBuilder(); failureMessage.Append(error); var errorDescription = query["error_description"]; @@ -49,42 +86,29 @@ protected override async Task HandleRemoteAuthenticateAsync( failureMessage.Append(";Uri=").Append(errorUri); } - return AuthenticateResult.Fail(failureMessage.ToString()); + return HandleRequestResult.Fail(failureMessage.ToString(), properties); } var code = query["code"]; - var state = query["state"]; - - properties = Options.StateDataFormat.Unprotect(state); - if (properties == null) - { - return AuthenticateResult.Fail("The oauth state was missing or invalid."); - } - - // OAuth2 10.12 CSRF - if (!ValidateCorrelationId(properties)) - { - return AuthenticateResult.Fail("Correlation failed."); - } if (StringValues.IsNullOrEmpty(code)) { - return AuthenticateResult.Fail("Code was not found."); + return HandleRequestResult.Fail("Code was not found.", properties); } var tokens = await ExchangeCodeAsync(code, BuildRedirectUri(Options.CallbackPath)); if (tokens.Error != null) { - return AuthenticateResult.Fail(tokens.Error); + return HandleRequestResult.Fail(tokens.Error, properties); } if (string.IsNullOrEmpty(tokens.AccessToken)) { - return AuthenticateResult.Fail("Failed to retrieve access token."); + return HandleRequestResult.Fail("Failed to retrieve access token.", properties); } - var identity = new ClaimsIdentity(Options.ClaimsIssuer); + var identity = new ClaimsIdentity(ClaimsIssuer); if (Options.SaveTokens) { @@ -108,7 +132,7 @@ protected override async Task HandleRemoteAuthenticateAsync( { // https://www.w3.org/TR/xmlschema-2/#dateTime // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx - var expiresAt = Options.SystemClock.UtcNow + TimeSpan.FromSeconds(value); + var expiresAt = Clock.UtcNow + TimeSpan.FromSeconds(value); authTokens.Add(new AuthenticationToken { Name = "expires_at", @@ -123,11 +147,11 @@ protected override async Task HandleRemoteAuthenticateAsync( var ticket = await CreateTicketAsync(identity, properties, tokens); if (ticket != null) { - return AuthenticateResult.Success(ticket); + return HandleRequestResult.Success(ticket); } else { - return AuthenticateResult.Fail("Failed to retrieve user information from remote server."); + return HandleRequestResult.Fail("Failed to retrieve user information from remote server.", properties); } } @@ -171,40 +195,32 @@ private static async Task Display(HttpResponseMessage response) protected virtual async Task CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens) { - var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Options.AuthenticationScheme); - var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens); - await Options.Events.CreatingTicket(context); - return context.Ticket; + var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens); + await Events.CreatingTicket(context); + return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name); } - protected override async Task HandleUnauthorizedAsync(ChallengeContext context) + protected override async Task HandleChallengeAsync(AuthenticationProperties properties) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - var properties = new AuthenticationProperties(context.Properties); - if (string.IsNullOrEmpty(properties.RedirectUri)) { - properties.RedirectUri = CurrentUri; + properties.RedirectUri = OriginalPathBase + OriginalPath + Request.QueryString; } // OAuth2 10.12 CSRF GenerateCorrelationId(properties); var authorizationEndpoint = BuildChallengeUrl(properties, BuildRedirectUri(Options.CallbackPath)); - var redirectContext = new OAuthRedirectToAuthorizationContext( - Context, Options, + var redirectContext = new RedirectContext( + Context, Scheme, Options, properties, authorizationEndpoint); - await Options.Events.RedirectToAuthorizationEndpoint(redirectContext); - return true; + await Events.RedirectToAuthorizationEndpoint(redirectContext); } protected virtual string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri) { - var scope = FormatScope(); + var scopeParameter = properties.GetParameter>(OAuthChallengeProperties.ScopeKey); + var scope = scopeParameter != null ? FormatScope(scopeParameter) : FormatScope(); var state = Options.StateDataFormat.Protect(properties); var parameters = new Dictionary @@ -218,10 +234,20 @@ protected virtual string BuildChallengeUrl(AuthenticationProperties properties, return QueryHelpers.AddQueryString(Options.AuthorizationEndpoint, parameters); } + /// + /// Format a list of OAuth scopes. + /// + /// List of scopes. + /// Formatted scopes. + protected virtual string FormatScope(IEnumerable scopes) + => string.Join(" ", scopes); // OAuth2 3.3 space separated + + /// + /// Format the property. + /// + /// Formatted scopes. + /// Subclasses should rather override . protected virtual string FormatScope() - { - // OAuth2 3.3 space separated - return string.Join(" ", Options.Scope); - } + => FormatScope(Options.Scope); } -} \ No newline at end of file +} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthMiddleware.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthMiddleware.cs deleted file mode 100644 index 75139c1c8..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthMiddleware.cs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Globalization; -using System.Net.Http; -using System.Text.Encodings.Web; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.DataProtection; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace Microsoft.AspNetCore.Authentication.OAuth -{ - /// - /// An ASP.NET Core middleware for authenticating users using OAuth services. - /// - public class OAuthMiddleware : AuthenticationMiddleware where TOptions : OAuthOptions, new() - { - /// - /// Initializes a new . - /// - /// The next middleware in the HTTP pipeline to invoke. - /// - /// - /// The . - /// The configuration options for this middleware. - /// Configuration options for the middleware. - public OAuthMiddleware( - RequestDelegate next, - IDataProtectionProvider dataProtectionProvider, - ILoggerFactory loggerFactory, - UrlEncoder encoder, - IOptions sharedOptions, - IOptions options) - : base(next, options, loggerFactory, encoder) - { - if (next == null) - { - throw new ArgumentNullException(nameof(next)); - } - - if (dataProtectionProvider == null) - { - throw new ArgumentNullException(nameof(dataProtectionProvider)); - } - - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - if (encoder == null) - { - throw new ArgumentNullException(nameof(encoder)); - } - - if (sharedOptions == null) - { - throw new ArgumentNullException(nameof(sharedOptions)); - } - - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - // todo: review error handling - if (string.IsNullOrEmpty(Options.AuthenticationScheme)) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.AuthenticationScheme))); - } - - if (string.IsNullOrEmpty(Options.ClientId)) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.ClientId))); - } - - if (string.IsNullOrEmpty(Options.ClientSecret)) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.ClientSecret))); - } - - if (string.IsNullOrEmpty(Options.AuthorizationEndpoint)) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.AuthorizationEndpoint))); - } - - if (string.IsNullOrEmpty(Options.TokenEndpoint)) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.TokenEndpoint))); - } - - if (!Options.CallbackPath.HasValue) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.CallbackPath))); - } - - if (Options.Events == null) - { - Options.Events = new OAuthEvents(); - } - - if (Options.StateDataFormat == null) - { - var dataProtector = dataProtectionProvider.CreateProtector( - GetType().FullName, Options.AuthenticationScheme, "v1"); - Options.StateDataFormat = new PropertiesDataFormat(dataProtector); - } - - Backchannel = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler()); - Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OAuth middleware"); - Backchannel.Timeout = Options.BackchannelTimeout; - Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB - - if (string.IsNullOrEmpty(Options.SignInScheme)) - { - Options.SignInScheme = sharedOptions.Value.SignInScheme; - } - if (string.IsNullOrEmpty(Options.SignInScheme)) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.SignInScheme))); - } - } - - protected HttpClient Backchannel { get; private set; } - - /// - /// Provides the object for processing authentication-related requests. - /// - /// An configured with the supplied to the constructor. - protected override AuthenticationHandler CreateHandler() - { - return new OAuthHandler(Backchannel); - } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthOptions.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthOptions.cs index 9591d9c44..4eacbd0b3 100644 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthOptions.cs +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthOptions.cs @@ -1,16 +1,16 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; -using System.ComponentModel; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.OAuth; -using Microsoft.AspNetCore.Http.Authentication; +using System.Globalization; +using Microsoft.AspNetCore.Authentication.OAuth.Claims; +using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Builder +namespace Microsoft.AspNetCore.Authentication.OAuth { /// - /// Configuration options for . + /// Configuration options OAuth. /// public class OAuthOptions : RemoteAuthenticationOptions { @@ -19,6 +19,39 @@ public OAuthOptions() Events = new OAuthEvents(); } + /// + /// Check that the options are valid. Should throw an exception if things are not ok. + /// + public override void Validate() + { + base.Validate(); + + if (string.IsNullOrEmpty(ClientId)) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(ClientId)), nameof(ClientId)); + } + + if (string.IsNullOrEmpty(ClientSecret)) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(ClientSecret)), nameof(ClientSecret)); + } + + if (string.IsNullOrEmpty(AuthorizationEndpoint)) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(AuthorizationEndpoint)), nameof(AuthorizationEndpoint)); + } + + if (string.IsNullOrEmpty(TokenEndpoint)) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(TokenEndpoint)), nameof(TokenEndpoint)); + } + + if (!CallbackPath.HasValue) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(CallbackPath)), nameof(CallbackPath)); + } + } + /// /// Gets or sets the provider-assigned client id. /// @@ -47,14 +80,19 @@ public OAuthOptions() public string UserInformationEndpoint { get; set; } /// - /// Gets or sets the used to handle authentication events. + /// Gets or sets the used to handle authentication events. /// - public new IOAuthEvents Events + public new OAuthEvents Events { - get { return (IOAuthEvents)base.Events; } + get { return (OAuthEvents)base.Events; } set { base.Events = value; } } + /// + /// A collection of claim actions used to select values from the json user data and create Claims. + /// + public ClaimActionCollection ClaimActions { get; } = new ClaimActionCollection(); + /// /// Gets the list of permissions to request. /// diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthPostConfigureOptions.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthPostConfigureOptions.cs new file mode 100644 index 000000000..e97346413 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthPostConfigureOptions.cs @@ -0,0 +1,45 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Net.Http; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.OAuth; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// Used to setup defaults for the OAuthOptions. + /// + public class OAuthPostConfigureOptions : IPostConfigureOptions + where TOptions : OAuthOptions, new() + where THandler : OAuthHandler + { + private readonly IDataProtectionProvider _dp; + + public OAuthPostConfigureOptions(IDataProtectionProvider dataProtection) + { + _dp = dataProtection; + } + + public void PostConfigure(string name, TOptions options) + { + options.DataProtectionProvider = options.DataProtectionProvider ?? _dp; + if (options.Backchannel == null) + { + options.Backchannel = new HttpClient(options.BackchannelHttpHandler ?? new HttpClientHandler()); + options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OAuth handler"); + options.Backchannel.Timeout = options.BackchannelTimeout; + options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB + } + + if (options.StateDataFormat == null) + { + var dataProtector = options.DataProtectionProvider.CreateProtector( + typeof(THandler).FullName, name, "v1"); + options.StateDataFormat = new PropertiesDataFormat(dataProtector); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Authentication.OAuth/Properties/Resources.Designer.cs index 00c7b848b..5a38ade0b 100644 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/Properties/Resources.Designer.cs @@ -15,32 +15,28 @@ private static readonly ResourceManager _resourceManager /// internal static string Exception_OptionMustBeProvided { - get { return GetString("Exception_OptionMustBeProvided"); } + get => GetString("Exception_OptionMustBeProvided"); } /// /// The '{0}' option must be provided. /// internal static string FormatException_OptionMustBeProvided(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); /// /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler. /// internal static string Exception_ValidatorHandlerMismatch { - get { return GetString("Exception_ValidatorHandlerMismatch"); } + get => GetString("Exception_ValidatorHandlerMismatch"); } /// /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler. /// internal static string FormatException_ValidatorHandlerMismatch() - { - return GetString("Exception_ValidatorHandlerMismatch"); - } + => GetString("Exception_ValidatorHandlerMismatch"); private static string GetString(string name, params string[] formatterNames) { diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/baseline.net45.json b/src/Microsoft.AspNetCore.Authentication.OAuth/baseline.net45.json deleted file mode 100644 index d485aedb1..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/baseline.net45.json +++ /dev/null @@ -1,955 +0,0 @@ -{ - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.OAuth, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", - "Types": [ - { - "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Backchannel", - "Parameters": [], - "ReturnType": "System.Net.Http.HttpClient", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleRemoteAuthenticateAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ExchangeCodeAsync", - "Parameters": [ - { - "Name": "code", - "Type": "System.String" - }, - { - "Name": "redirectUri", - "Type": "System.String" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "CreateTicketAsync", - "Parameters": [ - { - "Name": "identity", - "Type": "System.Security.Claims.ClaimsIdentity" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - }, - { - "Name": "tokens", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleUnauthorizedAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "BuildChallengeUrl", - "Parameters": [ - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - }, - { - "Name": "redirectUri", - "Type": "System.String" - } - ], - "ReturnType": "System.String", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "FormatScope", - "Parameters": [], - "ReturnType": "System.String", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "backchannel", - "Type": "System.Net.Http.HttpClient" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [ - { - "ParameterName": "TOptions", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [ - "Microsoft.AspNetCore.Builder.OAuthOptions" - ] - } - ] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthMiddleware", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Backchannel", - "Parameters": [], - "ReturnType": "System.Net.Http.HttpClient", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "CreateHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" - }, - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" - }, - { - "Name": "sharedOptions", - "Type": "Microsoft.Extensions.Options.IOptions" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [ - { - "ParameterName": "TOptions", - "ParameterPosition": 0, - "New": true, - "BaseTypeOrInterfaces": [ - "Microsoft.AspNetCore.Builder.OAuthOptions" - ] - } - ] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Success", - "Parameters": [ - { - "Name": "response", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Failed", - "Parameters": [ - { - "Name": "error", - "Type": "System.Exception" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Response", - "Parameters": [], - "ReturnType": "Newtonsoft.Json.Linq.JObject", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Response", - "Parameters": [ - { - "Name": "value", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AccessToken", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_AccessToken", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_TokenType", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_TokenType", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_RefreshToken", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_RefreshToken", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ExpiresIn", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ExpiresIn", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Error", - "Parameters": [], - "ReturnType": "System.Exception", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Error", - "Parameters": [ - { - "Name": "value", - "Type": "System.Exception" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OAuth.IOAuthEvents", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents" - ], - "Members": [ - { - "Kind": "Method", - "Name": "CreatingTicket", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthCreatingTicketContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToAuthorizationEndpoint", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthRedirectToAuthorizationContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthCreatingTicketContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.OAuthOptions", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_User", - "Parameters": [], - "ReturnType": "Newtonsoft.Json.Linq.JObject", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_TokenResponse", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AccessToken", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_TokenType", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_RefreshToken", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ExpiresIn", - "Parameters": [], - "ReturnType": "System.Nullable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Backchannel", - "Parameters": [], - "ReturnType": "System.Net.Http.HttpClient", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Ticket", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Ticket", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Identity", - "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsIdentity", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OAuthOptions" - }, - { - "Name": "backchannel", - "Type": "System.Net.Http.HttpClient" - }, - { - "Name": "tokens", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse" - } - ], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OAuthOptions" - }, - { - "Name": "backchannel", - "Type": "System.Net.Http.HttpClient" - }, - { - "Name": "tokens", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse" - }, - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthEvents", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.OAuth.IOAuthEvents" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_OnCreatingTicket", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnCreatingTicket", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnRedirectToAuthorizationEndpoint", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnRedirectToAuthorizationEndpoint", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "CreatingTicket", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthCreatingTicketContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OAuth.IOAuthEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToAuthorizationEndpoint", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthRedirectToAuthorizationContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OAuth.IOAuthEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthRedirectToAuthorizationContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.OAuthOptions", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_RedirectUri", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OAuthOptions" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - }, - { - "Name": "redirectUri", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.OAuthAppBuilderExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "UseOAuthAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "UseOAuthAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OAuthOptions" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.OAuthOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_ClientId", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ClientId", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ClientSecret", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ClientSecret", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AuthorizationEndpoint", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_AuthorizationEndpoint", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_TokenEndpoint", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_TokenEndpoint", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_UserInformationEndpoint", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_UserInformationEndpoint", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Events", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.IOAuthEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Events", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.IOAuthEvents" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Scope", - "Parameters": [], - "ReturnType": "System.Collections.Generic.ICollection", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_StateDataFormat", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_StateDataFormat", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISecureDataFormat" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SystemClock", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISystemClock", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SystemClock", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - } - ], - "SourceFilters": [] -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/baseline.netcore.json b/src/Microsoft.AspNetCore.Authentication.OAuth/baseline.netcore.json index d485aedb1..9c2394704 100644 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Authentication.OAuth/baseline.netcore.json @@ -1,6 +1,870 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.OAuth, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.OAuth, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ + { + "Name": "Microsoft.Extensions.DependencyInjection.OAuthExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AddOAuth", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddOAuth", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddOAuth", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions" + ] + }, + { + "ParameterName": "THandler", + "ParameterPosition": 1, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler" + ] + } + ] + }, + { + "Kind": "Method", + "Name": "AddOAuth", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions" + ] + }, + { + "ParameterName": "THandler", + "ParameterPosition": 1, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler" + ] + } + ] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.DependencyInjection.OAuthPostConfigureOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Options.IPostConfigureOptions" + ], + "Members": [ + { + "Kind": "Method", + "Name": "PostConfigure", + "Parameters": [ + { + "Name": "name", + "Type": "System.String" + }, + { + "Name": "options", + "Type": "T0" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Options.IPostConfigureOptions", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "dataProtection", + "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions" + ] + }, + { + "ParameterName": "THandler", + "ParameterPosition": 1, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler" + ] + } + ] + }, + { + "Name": "Microsoft.AspNetCore.Builder.OAuthAppBuilderExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseOAuthAuthentication", + "Parameters": [ + { + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "UseOAuthAuthentication", + "Parameters": [ + { + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.ClaimActionCollectionMapExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "MapJsonKey", + "Parameters": [ + { + "Name": "collection", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection" + }, + { + "Name": "claimType", + "Type": "System.String" + }, + { + "Name": "jsonKey", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "MapJsonKey", + "Parameters": [ + { + "Name": "collection", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection" + }, + { + "Name": "claimType", + "Type": "System.String" + }, + { + "Name": "jsonKey", + "Type": "System.String" + }, + { + "Name": "valueType", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "MapJsonSubKey", + "Parameters": [ + { + "Name": "collection", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection" + }, + { + "Name": "claimType", + "Type": "System.String" + }, + { + "Name": "jsonKey", + "Type": "System.String" + }, + { + "Name": "subKey", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "MapJsonSubKey", + "Parameters": [ + { + "Name": "collection", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection" + }, + { + "Name": "claimType", + "Type": "System.String" + }, + { + "Name": "jsonKey", + "Type": "System.String" + }, + { + "Name": "subKey", + "Type": "System.String" + }, + { + "Name": "valueType", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "MapCustomJson", + "Parameters": [ + { + "Name": "collection", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection" + }, + { + "Name": "claimType", + "Type": "System.String" + }, + { + "Name": "resolver", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "MapCustomJson", + "Parameters": [ + { + "Name": "collection", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection" + }, + { + "Name": "claimType", + "Type": "System.String" + }, + { + "Name": "valueType", + "Type": "System.String" + }, + { + "Name": "resolver", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "MapAll", + "Parameters": [ + { + "Name": "collection", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection" + } + ], + "ReturnType": "System.Void", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "MapAllExcept", + "Parameters": [ + { + "Name": "collection", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection" + }, + { + "Name": "exclusions", + "Type": "System.String[]", + "IsParams": true + } + ], + "ReturnType": "System.Void", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "DeleteClaim", + "Parameters": [ + { + "Name": "collection", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection" + }, + { + "Name": "claimType", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "DeleteClaims", + "Parameters": [ + { + "Name": "collection", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection" + }, + { + "Name": "claimTypes", + "Type": "System.String[]", + "IsParams": true + } + ], + "ReturnType": "System.Void", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthCreatingTicketContext", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.ResultContext", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_User", + "Parameters": [], + "ReturnType": "Newtonsoft.Json.Linq.JObject", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_TokenResponse", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_AccessToken", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_TokenType", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_RefreshToken", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ExpiresIn", + "Parameters": [], + "ReturnType": "System.Nullable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Backchannel", + "Parameters": [], + "ReturnType": "System.Net.Http.HttpClient", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Identity", + "Parameters": [], + "ReturnType": "System.Security.Claims.ClaimsIdentity", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "RunClaimActions", + "Parameters": [], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "RunClaimActions", + "Parameters": [ + { + "Name": "userData", + "Type": "Newtonsoft.Json.Linq.JObject" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "principal", + "Type": "System.Security.Claims.ClaimsPrincipal" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions" + }, + { + "Name": "backchannel", + "Type": "System.Net.Http.HttpClient" + }, + { + "Name": "tokens", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "principal", + "Type": "System.Security.Claims.ClaimsPrincipal" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions" + }, + { + "Name": "backchannel", + "Type": "System.Net.Http.HttpClient" + }, + { + "Name": "tokens", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse" + }, + { + "Name": "user", + "Type": "Newtonsoft.Json.Linq.JObject" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthEvents", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_OnCreatingTicket", + "Parameters": [], + "ReturnType": "System.Func", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_OnCreatingTicket", + "Parameters": [ + { + "Name": "value", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_OnRedirectToAuthorizationEndpoint", + "Parameters": [], + "ReturnType": "System.Func, System.Threading.Tasks.Task>", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_OnRedirectToAuthorizationEndpoint", + "Parameters": [ + { + "Name": "value", + "Type": "System.Func, System.Threading.Tasks.Task>" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "CreatingTicket", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthCreatingTicketContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "RedirectToAuthorizationEndpoint", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Authentication.RedirectContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthChallengeProperties", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationProperties", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Scope", + "Parameters": [], + "ReturnType": "System.Collections.Generic.ICollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Scope", + "Parameters": [ + { + "Name": "value", + "Type": "System.Collections.Generic.ICollection" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "SetScope", + "Parameters": [ + { + "Name": "scopes", + "Type": "System.String[]", + "IsParams": true + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "items", + "Type": "System.Collections.Generic.IDictionary" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "items", + "Type": "System.Collections.Generic.IDictionary" + }, + { + "Name": "parameters", + "Type": "System.Collections.Generic.IDictionary" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "ScopeKey", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthDefaults", + "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": [] + } + ], + "GenericParameters": [] + }, { "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler", "Visibility": "Public", @@ -16,11 +880,42 @@ "Visibility": "Protected", "GenericParameter": [] }, + { + "Kind": "Method", + "Name": "get_Events", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthEvents", + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Events", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthEvents" + } + ], + "ReturnType": "System.Void", + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "CreateEventsAsync", + "Parameters": [], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", + "GenericParameter": [] + }, { "Kind": "Method", "Name": "HandleRemoteAuthenticateAsync", "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, "Override": true, "Visibility": "Protected", @@ -54,7 +949,7 @@ }, { "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" }, { "Name": "tokens", @@ -68,14 +963,14 @@ }, { "Kind": "Method", - "Name": "HandleUnauthorizedAsync", + "Name": "HandleChallengeAsync", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, "Override": true, "Visibility": "Protected", @@ -87,7 +982,7 @@ "Parameters": [ { "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" }, { "Name": "redirectUri", @@ -102,57 +997,23 @@ { "Kind": "Method", "Name": "FormatScope", - "Parameters": [], - "ReturnType": "System.String", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", "Parameters": [ { - "Name": "backchannel", - "Type": "System.Net.Http.HttpClient" + "Name": "scopes", + "Type": "System.Collections.Generic.IEnumerable" } ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [ - { - "ParameterName": "TOptions", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [ - "Microsoft.AspNetCore.Builder.OAuthOptions" - ] - } - ] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthMiddleware", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Backchannel", - "Parameters": [], - "ReturnType": "System.Net.Http.HttpClient", + "ReturnType": "System.String", + "Virtual": true, "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "CreateHandler", + "Name": "FormatScope", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "ReturnType": "System.String", "Virtual": true, - "Override": true, "Visibility": "Protected", "GenericParameter": [] }, @@ -161,15 +1022,11 @@ "Name": ".ctor", "Parameters": [ { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" }, { - "Name": "loggerFactory", + "Name": "logger", "Type": "Microsoft.Extensions.Logging.ILoggerFactory" }, { @@ -177,12 +1034,8 @@ "Type": "System.Text.Encodings.Web.UrlEncoder" }, { - "Name": "sharedOptions", - "Type": "Microsoft.Extensions.Options.IOptions" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" + "Name": "clock", + "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" } ], "Visibility": "Public", @@ -195,60 +1048,64 @@ "ParameterPosition": 0, "New": true, "BaseTypeOrInterfaces": [ - "Microsoft.AspNetCore.Builder.OAuthOptions" + "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions" ] } ] }, { - "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse", + "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions", "Visibility": "Public", "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "Success", - "Parameters": [ - { - "Name": "response", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse", - "Static": true, + "Name": "Validate", + "Parameters": [], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_ClientId", + "Parameters": [], + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Failed", + "Name": "set_ClientId", "Parameters": [ { - "Name": "error", - "Type": "System.Exception" + "Name": "value", + "Type": "System.String" } ], - "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse", - "Static": true, + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Response", + "Name": "get_ClientSecret", "Parameters": [], - "ReturnType": "Newtonsoft.Json.Linq.JObject", + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Response", + "Name": "set_ClientSecret", "Parameters": [ { "Name": "value", - "Type": "Newtonsoft.Json.Linq.JObject" + "Type": "System.String" } ], "ReturnType": "System.Void", @@ -257,7 +1114,7 @@ }, { "Kind": "Method", - "Name": "get_AccessToken", + "Name": "get_AuthorizationEndpoint", "Parameters": [], "ReturnType": "System.String", "Visibility": "Public", @@ -265,7 +1122,7 @@ }, { "Kind": "Method", - "Name": "set_AccessToken", + "Name": "set_AuthorizationEndpoint", "Parameters": [ { "Name": "value", @@ -278,7 +1135,7 @@ }, { "Kind": "Method", - "Name": "get_TokenType", + "Name": "get_TokenEndpoint", "Parameters": [], "ReturnType": "System.String", "Visibility": "Public", @@ -286,7 +1143,7 @@ }, { "Kind": "Method", - "Name": "set_TokenType", + "Name": "set_TokenEndpoint", "Parameters": [ { "Name": "value", @@ -299,7 +1156,7 @@ }, { "Kind": "Method", - "Name": "get_RefreshToken", + "Name": "get_UserInformationEndpoint", "Parameters": [], "ReturnType": "System.String", "Visibility": "Public", @@ -307,7 +1164,7 @@ }, { "Kind": "Method", - "Name": "set_RefreshToken", + "Name": "set_UserInformationEndpoint", "Parameters": [ { "Name": "value", @@ -320,19 +1177,19 @@ }, { "Kind": "Method", - "Name": "get_ExpiresIn", + "Name": "get_Events", "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthEvents", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_ExpiresIn", + "Name": "set_Events", "Parameters": [ { "Name": "value", - "Type": "System.String" + "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthEvents" } ], "ReturnType": "System.Void", @@ -341,82 +1198,88 @@ }, { "Kind": "Method", - "Name": "get_Error", + "Name": "get_ClaimActions", "Parameters": [], - "ReturnType": "System.Exception", + "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Error", + "Name": "get_Scope", + "Parameters": [], + "ReturnType": "System.Collections.Generic.ICollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_StateDataFormat", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_StateDataFormat", "Parameters": [ { "Name": "value", - "Type": "System.Exception" + "Type": "Microsoft.AspNetCore.Authentication.ISecureDataFormat" } ], "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] } ], "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.OAuth.IOAuthEvents", + "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse", "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents" - ], + "Kind": "Class", + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "CreatingTicket", + "Name": "Success", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthCreatingTicketContext" + "Name": "response", + "Type": "Newtonsoft.Json.Linq.JObject" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse", + "Static": true, + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RedirectToAuthorizationEndpoint", + "Name": "Failed", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthRedirectToAuthorizationContext" + "Name": "error", + "Type": "System.Exception" } ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthCreatingTicketContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.OAuthOptions", + "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse", + "Static": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_User", + "Name": "get_Response", "Parameters": [], "ReturnType": "Newtonsoft.Json.Linq.JObject", "Visibility": "Public", @@ -424,9 +1287,14 @@ }, { "Kind": "Method", - "Name": "get_TokenResponse", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse", + "Name": "set_Response", + "Parameters": [ + { + "Name": "value", + "Type": "Newtonsoft.Json.Linq.JObject" + } + ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, @@ -440,15 +1308,20 @@ }, { "Kind": "Method", - "Name": "get_TokenType", - "Parameters": [], - "ReturnType": "System.String", + "Name": "set_AccessToken", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_RefreshToken", + "Name": "get_TokenType", "Parameters": [], "ReturnType": "System.String", "Visibility": "Public", @@ -456,35 +1329,32 @@ }, { "Kind": "Method", - "Name": "get_ExpiresIn", - "Parameters": [], - "ReturnType": "System.Nullable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Backchannel", - "Parameters": [], - "ReturnType": "System.Net.Http.HttpClient", + "Name": "set_TokenType", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Ticket", + "Name": "get_RefreshToken", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Ticket", + "Name": "set_RefreshToken", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" + "Type": "System.String" } ], "ReturnType": "System.Void", @@ -493,69 +1363,43 @@ }, { "Kind": "Method", - "Name": "get_Identity", + "Name": "get_ExpiresIn", "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsIdentity", + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "set_ExpiresIn", "Parameters": [ { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OAuthOptions" - }, - { - "Name": "backchannel", - "Type": "System.Net.Http.HttpClient" - }, - { - "Name": "tokens", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse" + "Name": "value", + "Type": "System.String" } ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "get_Error", + "Parameters": [], + "ReturnType": "System.Exception", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Error", "Parameters": [ { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OAuthOptions" - }, - { - "Name": "backchannel", - "Type": "System.Net.Http.HttpClient" - }, - { - "Name": "tokens", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse" - }, - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "value", + "Type": "System.Exception" } ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] } @@ -563,50 +1407,93 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthEvents", + "Name": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.OAuth.IOAuthEvents" - ], + "Abstract": true, + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_OnCreatingTicket", + "Name": "get_ClaimType", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_OnCreatingTicket", + "Name": "get_ValueType", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Run", "Parameters": [ { - "Name": "value", - "Type": "System.Func" + "Name": "userData", + "Type": "Newtonsoft.Json.Linq.JObject" + }, + { + "Name": "identity", + "Type": "System.Security.Claims.ClaimsIdentity" + }, + { + "Name": "issuer", + "Type": "System.String" } ], "ReturnType": "System.Void", + "Virtual": true, + "Abstract": true, "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "claimType", + "Type": "System.String" + }, + { + "Name": "valueType", + "Type": "System.String" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "System.Collections.Generic.IEnumerable" + ], + "Members": [ { "Kind": "Method", - "Name": "get_OnRedirectToAuthorizationEndpoint", + "Name": "Clear", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_OnRedirectToAuthorizationEndpoint", + "Name": "Remove", "Parameters": [ { - "Name": "value", - "Type": "System.Func" + "Name": "claimType", + "Type": "System.String" } ], "ReturnType": "System.Void", @@ -615,31 +1502,25 @@ }, { "Kind": "Method", - "Name": "CreatingTicket", + "Name": "Add", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthCreatingTicketContext" + "Name": "action", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OAuth.IOAuthEvents", + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RedirectToAuthorizationEndpoint", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthRedirectToAuthorizationContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", + "Name": "GetEnumerator", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IEnumerator", + "Sealed": true, "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OAuth.IOAuthEvents", + "ImplementedInterface": "System.Collections.Generic.IEnumerable", "Visibility": "Public", "GenericParameter": [] }, @@ -654,33 +1535,40 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.OAuth.OAuthRedirectToAuthorizationContext", + "Name": "Microsoft.AspNetCore.Authentication.OAuth.Claims.CustomJsonClaimAction", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseContext", + "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.OAuthOptions", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_RedirectUri", + "Name": "get_Resolver", "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", + "Name": "Run", + "Parameters": [ + { + "Name": "userData", + "Type": "Newtonsoft.Json.Linq.JObject" + }, + { + "Name": "identity", + "Type": "System.Security.Claims.ClaimsIdentity" + }, + { + "Name": "issuer", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, "Visibility": "Public", "GenericParameter": [] }, @@ -689,20 +1577,16 @@ "Name": ".ctor", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OAuthOptions" + "Name": "claimType", + "Type": "System.String" }, { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Name": "valueType", + "Type": "System.String" }, { - "Name": "redirectUri", - "Type": "System.String" + "Name": "resolver", + "Type": "System.Func" } ], "Visibility": "Public", @@ -712,45 +1596,44 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Builder.OAuthAppBuilderExtensions", + "Name": "Microsoft.AspNetCore.Authentication.OAuth.Claims.DeleteClaimAction", "Visibility": "Public", "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, + "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "UseOAuthAuthentication", + "Name": "Run", "Parameters": [ { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + "Name": "userData", + "Type": "Newtonsoft.Json.Linq.JObject" + }, + { + "Name": "identity", + "Type": "System.Security.Claims.ClaimsIdentity" + }, + { + "Name": "issuer", + "Type": "System.String" } ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "UseOAuthAuthentication", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OAuthOptions" + "Name": "claimType", + "Type": "System.String" } ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, "Visibility": "Public", "GenericParameter": [] } @@ -758,15 +1641,15 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Builder.OAuthOptions", + "Name": "Microsoft.AspNetCore.Authentication.OAuth.Claims.JsonKeyClaimAction", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions", + "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_ClientId", + "Name": "get_JsonKey", "Parameters": [], "ReturnType": "System.String", "Visibility": "Public", @@ -774,83 +1657,60 @@ }, { "Kind": "Method", - "Name": "set_ClientId", + "Name": "Run", "Parameters": [ { - "Name": "value", + "Name": "userData", + "Type": "Newtonsoft.Json.Linq.JObject" + }, + { + "Name": "identity", + "Type": "System.Security.Claims.ClaimsIdentity" + }, + { + "Name": "issuer", "Type": "System.String" } ], "ReturnType": "System.Void", + "Virtual": true, + "Override": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "get_ClientSecret", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ClientSecret", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { - "Name": "value", + "Name": "claimType", "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AuthorizationEndpoint", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_AuthorizationEndpoint", - "Parameters": [ + }, { - "Name": "value", + "Name": "valueType", "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_TokenEndpoint", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_TokenEndpoint", - "Parameters": [ + }, { - "Name": "value", + "Name": "jsonKey", "Type": "System.String" } ], - "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OAuth.Claims.JsonSubKeyClaimAction", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.Claims.JsonKeyClaimAction", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "get_UserInformationEndpoint", + "Name": "get_SubKey", "Parameters": [], "ReturnType": "System.String", "Visibility": "Public", @@ -858,85 +1718,81 @@ }, { "Kind": "Method", - "Name": "set_UserInformationEndpoint", + "Name": "Run", "Parameters": [ { - "Name": "value", + "Name": "userData", + "Type": "Newtonsoft.Json.Linq.JObject" + }, + { + "Name": "identity", + "Type": "System.Security.Claims.ClaimsIdentity" + }, + { + "Name": "issuer", "Type": "System.String" } ], "ReturnType": "System.Void", + "Virtual": true, + "Override": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "get_Events", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.IOAuthEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Events", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.OAuth.IOAuthEvents" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Scope", - "Parameters": [], - "ReturnType": "System.Collections.Generic.ICollection", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_StateDataFormat", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_StateDataFormat", - "Parameters": [ + "Name": "claimType", + "Type": "System.String" + }, { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISecureDataFormat" + "Name": "valueType", + "Type": "System.String" + }, + { + "Name": "jsonKey", + "Type": "System.String" + }, + { + "Name": "subKey", + "Type": "System.String" } ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SystemClock", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISystemClock", "Visibility": "Public", "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OAuth.Claims.MapAllClaimsAction", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "set_SystemClock", + "Name": "Run", "Parameters": [ { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" + "Name": "userData", + "Type": "Newtonsoft.Json.Linq.JObject" + }, + { + "Name": "identity", + "Type": "System.Security.Claims.ClaimsIdentity" + }, + { + "Name": "issuer", + "Type": "System.String" } ], "ReturnType": "System.Void", + "Virtual": true, + "Override": true, "Visibility": "Public", "GenericParameter": [] }, @@ -950,6 +1806,5 @@ ], "GenericParameters": [] } - ], - "SourceFilters": [] + ] } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OAuth/project.json b/src/Microsoft.AspNetCore.Authentication.OAuth/project.json deleted file mode 100644 index 525f21fc0..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OAuth/project.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core middleware that enables an application to support any standard OAuth 2.0 authentication workflow.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/security" - }, - "tags": [ - "aspnetcore", - "authentication", - "security" - ] - }, - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "dependencies": { - "Microsoft.AspNetCore.Authentication": { - "target": "project" - }, - "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.2.0-*", - "type": "build" - }, - "NETStandard.Library": "1.6.2-*", - "Newtonsoft.Json": "9.0.1" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": { - "dependencies": { - "System.Runtime.Serialization.Primitives": "4.4.0-*" - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Claims/ClaimActionCollectionUniqueExtensions.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Claims/ClaimActionCollectionUniqueExtensions.cs new file mode 100644 index 000000000..4e349579f --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Claims/ClaimActionCollectionUniqueExtensions.cs @@ -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 System.Security.Claims; +using Microsoft.AspNetCore.Authentication.OAuth.Claims; +using Microsoft.AspNetCore.Authentication.OpenIdConnect.Claims; + +namespace Microsoft.AspNetCore.Authentication +{ + public static class ClaimActionCollectionUniqueExtensions + { + /// + /// Selects a top level value from the json user data with the given key name and adds it as a Claim. + /// This no-ops if the ClaimsIdentity already contains a Claim with the given ClaimType. + /// This no-ops if the key is not found or the value is empty. + /// + /// + /// The value to use for Claim.Type when creating a Claim. + /// The top level key to look for in the json user data. + public static void MapUniqueJsonKey(this ClaimActionCollection collection, string claimType, string jsonKey) + { + collection.MapUniqueJsonKey(claimType, jsonKey, ClaimValueTypes.String); + } + + /// + /// Selects a top level value from the json user data with the given key name and adds it as a Claim. + /// This no-ops if the ClaimsIdentity already contains a Claim with the given ClaimType. + /// This no-ops if the key is not found or the value is empty. + /// + /// + /// The value to use for Claim.Type when creating a Claim. + /// The top level key to look for in the json user data. + /// The value to use for Claim.ValueType when creating a Claim. + public static void MapUniqueJsonKey(this ClaimActionCollection collection, string claimType, string jsonKey, string valueType) + { + collection.Add(new UniqueJsonKeyClaimAction(claimType, valueType, jsonKey)); + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Claims/UniqueJsonKeyClaimAction.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Claims/UniqueJsonKeyClaimAction.cs new file mode 100644 index 000000000..132885b3c --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Claims/UniqueJsonKeyClaimAction.cs @@ -0,0 +1,61 @@ +// 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.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using Microsoft.AspNetCore.Authentication.OAuth.Claims; +using Newtonsoft.Json.Linq; + +namespace Microsoft.AspNetCore.Authentication.OpenIdConnect.Claims +{ + /// + /// A ClaimAction that selects a top level value from the json user data with the given key name and adds it as a Claim. + /// This no-ops if the ClaimsIdentity already contains a Claim with the given ClaimType. + /// This no-ops if the key is not found or the value is empty. + /// + public class UniqueJsonKeyClaimAction : JsonKeyClaimAction + { + /// + /// Creates a new UniqueJsonKeyClaimAction. + /// + /// The value to use for Claim.Type when creating a Claim. + /// The value to use for Claim.ValueType when creating a Claim. + /// The top level key to look for in the json user data. + public UniqueJsonKeyClaimAction(string claimType, string valueType, string jsonKey) + : base(claimType, valueType, jsonKey) + { + } + + /// + public override void Run(JObject userData, ClaimsIdentity identity, string issuer) + { + var value = userData?.Value(JsonKey); + if (string.IsNullOrEmpty(value)) + { + // Not found + return; + } + + var claim = identity.FindFirst(c => string.Equals(c.Type, JsonKey, System.StringComparison.OrdinalIgnoreCase)); + if (claim != null && string.Equals(claim.Value, value, System.StringComparison.Ordinal)) + { + // Duplicate + return; + } + + claim = identity.FindFirst(c => + { + // If this claimType is mapped by the JwtSeurityTokenHandler, then this property will be set + return c.Properties.TryGetValue(JwtSecurityTokenHandler.ShortClaimTypeProperty, out var shortType) + && string.Equals(shortType, JsonKey, System.StringComparison.OrdinalIgnoreCase); + }); + if (claim != null && string.Equals(claim.Value, value, System.StringComparison.Ordinal)) + { + // Duplicate with an alternate name. + return; + } + + identity.AddClaim(new Claim(ClaimType, value, ValueType, issuer)); + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/AuthenticationFailedContext.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/AuthenticationFailedContext.cs index 776f78d6e..203da93c5 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/AuthenticationFailedContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/AuthenticationFailedContext.cs @@ -2,17 +2,18 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; +using Microsoft.IdentityModel.Protocols.OpenIdConnect; namespace Microsoft.AspNetCore.Authentication.OpenIdConnect { - public class AuthenticationFailedContext : BaseOpenIdConnectContext + public class AuthenticationFailedContext : RemoteAuthenticationContext { - public AuthenticationFailedContext(HttpContext context, OpenIdConnectOptions options) - : base(context, options) - { - } + public AuthenticationFailedContext(HttpContext context, AuthenticationScheme scheme, OpenIdConnectOptions options) + : base(context, scheme, options, new AuthenticationProperties()) + { } + + public OpenIdConnectMessage ProtocolMessage { get; set; } public Exception Exception { get; set; } } diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/AuthorizationCodeReceivedContext.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/AuthorizationCodeReceivedContext.cs index 49c863e4b..bdf6e4a7f 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/AuthorizationCodeReceivedContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/AuthorizationCodeReceivedContext.cs @@ -3,9 +3,7 @@ using System.IdentityModel.Tokens.Jwt; using System.Net.Http; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; using Microsoft.IdentityModel.Protocols.OpenIdConnect; namespace Microsoft.AspNetCore.Authentication.OpenIdConnect @@ -13,17 +11,19 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect /// /// This Context can be used to be informed when an 'AuthorizationCode' is received over the OpenIdConnect protocol. /// - public class AuthorizationCodeReceivedContext : BaseOpenIdConnectContext + public class AuthorizationCodeReceivedContext : RemoteAuthenticationContext { /// /// Creates a /// - public AuthorizationCodeReceivedContext(HttpContext context, OpenIdConnectOptions options) - : base(context, options) - { - } + public AuthorizationCodeReceivedContext( + HttpContext context, + AuthenticationScheme scheme, + OpenIdConnectOptions options, + AuthenticationProperties properties) + : base(context, scheme, options, properties) { } - public AuthenticationProperties Properties { get; set; } + public OpenIdConnectMessage ProtocolMessage { get; set; } /// /// Gets or sets the that was received in the authentication response, if any. @@ -42,23 +42,23 @@ public AuthorizationCodeReceivedContext(HttpContext context, OpenIdConnectOption /// /// If the developer chooses to redeem the code themselves then they can provide the resulting tokens here. This is the - /// same as calling HandleCodeRedemption. If set then the middleware will not attempt to redeem the code. An IdToken + /// same as calling HandleCodeRedemption. If set then the handler will not attempt to redeem the code. An IdToken /// is required if one had not been previously received in the authorization response. An access token is optional - /// if the middleware is to contact the user-info endpoint. + /// if the handler is to contact the user-info endpoint. /// public OpenIdConnectMessage TokenEndpointResponse { get; set; } /// - /// Indicates if the developer choose to handle (or skip) the code redemption. If true then the middleware will not attempt + /// Indicates if the developer choose to handle (or skip) the code redemption. If true then the handler will not attempt /// to redeem the code. See HandleCodeRedemption and TokenEndpointResponse. /// public bool HandledCodeRedemption => TokenEndpointResponse != null; /// - /// Tells the middleware to skip the code redemption process. The developer may have redeemed the code themselves, or + /// Tells the handler to skip the code redemption process. The developer may have redeemed the code themselves, or /// decided that the redemption was not required. If tokens were retrieved that are needed for further processing then /// call one of the overloads that allows providing tokens. An IdToken is required if one had not been previously received - /// in the authorization response. An access token can optionally be provided for the middleware to contact the + /// in the authorization response. An access token can optionally be provided for the handler to contact the /// user-info endpoint. Calling this is the same as setting TokenEndpointResponse. /// public void HandleCodeRedemption() @@ -67,10 +67,10 @@ public void HandleCodeRedemption() } /// - /// Tells the middleware to skip the code redemption process. The developer may have redeemed the code themselves, or + /// Tells the handler to skip the code redemption process. The developer may have redeemed the code themselves, or /// decided that the redemption was not required. If tokens were retrieved that are needed for further processing then /// call one of the overloads that allows providing tokens. An IdToken is required if one had not been previously received - /// in the authorization response. An access token can optionally be provided for the middleware to contact the + /// in the authorization response. An access token can optionally be provided for the handler to contact the /// user-info endpoint. Calling this is the same as setting TokenEndpointResponse. /// public void HandleCodeRedemption(string accessToken, string idToken) @@ -79,10 +79,10 @@ public void HandleCodeRedemption(string accessToken, string idToken) } /// - /// Tells the middleware to skip the code redemption process. The developer may have redeemed the code themselves, or + /// Tells the handler to skip the code redemption process. The developer may have redeemed the code themselves, or /// decided that the redemption was not required. If tokens were retrieved that are needed for further processing then /// call one of the overloads that allows providing tokens. An IdToken is required if one had not been previously received - /// in the authorization response. An access token can optionally be provided for the middleware to contact the + /// in the authorization response. An access token can optionally be provided for the handler to contact the /// user-info endpoint. Calling this is the same as setting TokenEndpointResponse. /// public void HandleCodeRedemption(OpenIdConnectMessage tokenEndpointResponse) diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/BaseOpenIdConnectContext.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/BaseOpenIdConnectContext.cs deleted file mode 100644 index d2f56a4ce..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/BaseOpenIdConnectContext.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.IdentityModel.Protocols.OpenIdConnect; - -namespace Microsoft.AspNetCore.Authentication.OpenIdConnect -{ - public class BaseOpenIdConnectContext : BaseControlContext - { - public BaseOpenIdConnectContext(HttpContext context, OpenIdConnectOptions options) - : base(context) - { - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - Options = options; - } - - public OpenIdConnectOptions Options { get; } - - public OpenIdConnectMessage ProtocolMessage { get; set; } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/IOpenIdConnectEvents.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/IOpenIdConnectEvents.cs deleted file mode 100644 index 128fa08a3..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/IOpenIdConnectEvents.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Authentication.OpenIdConnect -{ - /// - /// Specifies events which the invokes to enable developer control over the authentication process. - /// - public interface IOpenIdConnectEvents : IRemoteAuthenticationEvents - { - /// - /// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed. - /// - Task AuthenticationFailed(AuthenticationFailedContext context); - - /// - /// Invoked after security token validation if an authorization code is present in the protocol message. - /// - Task AuthorizationCodeReceived(AuthorizationCodeReceivedContext context); - - /// - /// Invoked when a protocol message is first received. - /// - Task MessageReceived(MessageReceivedContext context); - - /// - /// Invoked before redirecting to the identity provider to authenticate. - /// - Task RedirectToIdentityProvider(RedirectContext context); - - /// - /// Invoked before redirecting to the identity provider to sign out. - /// - Task RedirectToIdentityProviderForSignOut(RedirectContext context); - - /// - /// Invoked when a request is received on the RemoteSignOutPath. - /// - Task RemoteSignOut(RemoteSignOutContext context); - - /// - /// Invoked after "authorization code" is redeemed for tokens at the token endpoint. - /// - Task TokenResponseReceived(TokenResponseReceivedContext context); - - /// - /// Invoked when an IdToken has been validated and produced an AuthenticationTicket. - /// - Task TokenValidated(TokenValidatedContext context); - - /// - /// Invoked when user information is retrieved from the UserInfoEndpoint. - /// - Task UserInformationReceived(UserInformationReceivedContext context); - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/MessageReceivedContext.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/MessageReceivedContext.cs index b2554969c..7d06e4479 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/MessageReceivedContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/MessageReceivedContext.cs @@ -1,24 +1,25 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; +using Microsoft.IdentityModel.Protocols.OpenIdConnect; namespace Microsoft.AspNetCore.Authentication.OpenIdConnect { - public class MessageReceivedContext : BaseOpenIdConnectContext + public class MessageReceivedContext : RemoteAuthenticationContext { - public MessageReceivedContext(HttpContext context, OpenIdConnectOptions options) - : base(context, options) - { - } + public MessageReceivedContext( + HttpContext context, + AuthenticationScheme scheme, + OpenIdConnectOptions options, + AuthenticationProperties properties) + : base(context, scheme, options, properties) { } + + public OpenIdConnectMessage ProtocolMessage { get; set; } /// - /// Bearer Token. This will give application an opportunity to retrieve token from an alternation location. + /// Bearer Token. This will give the application an opportunity to retrieve a token from an alternative location. /// public string Token { get; set; } - - public AuthenticationProperties Properties { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/OpenIdConnectEvents.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/OpenIdConnectEvents.cs index f39b554ec..2a48d250b 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/OpenIdConnectEvents.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/OpenIdConnectEvents.cs @@ -3,59 +3,65 @@ using System; using System.Threading.Tasks; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Authentication.OpenIdConnect { /// - /// Specifies events which the invokes to enable developer control over the authentication process. + /// Specifies events which the invokes to enable developer control over the authentication process. /// - public class OpenIdConnectEvents : RemoteAuthenticationEvents, IOpenIdConnectEvents + public class OpenIdConnectEvents : RemoteAuthenticationEvents { /// /// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed. /// - public Func OnAuthenticationFailed { get; set; } = context => TaskCache.CompletedTask; + public Func OnAuthenticationFailed { get; set; } = context => Task.CompletedTask; /// /// Invoked after security token validation if an authorization code is present in the protocol message. /// - public Func OnAuthorizationCodeReceived { get; set; } = context => TaskCache.CompletedTask; + public Func OnAuthorizationCodeReceived { get; set; } = context => Task.CompletedTask; /// /// Invoked when a protocol message is first received. /// - public Func OnMessageReceived { get; set; } = context => TaskCache.CompletedTask; + public Func OnMessageReceived { get; set; } = context => Task.CompletedTask; /// - /// Invoked before redirecting to the identity provider to authenticate. + /// Invoked before redirecting to the identity provider to authenticate. This can be used to set ProtocolMessage.State + /// that will be persisted through the authentication process. The ProtocolMessage can also be used to add or customize + /// parameters sent to the identity provider. /// - public Func OnRedirectToIdentityProvider { get; set; } = context => TaskCache.CompletedTask; + public Func OnRedirectToIdentityProvider { get; set; } = context => Task.CompletedTask; /// /// Invoked before redirecting to the identity provider to sign out. /// - public Func OnRedirectToIdentityProviderForSignOut { get; set; } = context => TaskCache.CompletedTask; + public Func OnRedirectToIdentityProviderForSignOut { get; set; } = context => Task.CompletedTask; + + /// + /// Invoked before redirecting to the at the end of a remote sign-out flow. + /// + public Func OnSignedOutCallbackRedirect { get; set; } = context => Task.CompletedTask; /// /// Invoked when a request is received on the RemoteSignOutPath. /// - public Func OnRemoteSignOut { get; set; } = context => TaskCache.CompletedTask; + public Func OnRemoteSignOut { get; set; } = context => Task.CompletedTask; /// /// Invoked after "authorization code" is redeemed for tokens at the token endpoint. /// - public Func OnTokenResponseReceived { get; set; } = context => TaskCache.CompletedTask; + public Func OnTokenResponseReceived { get; set; } = context => Task.CompletedTask; /// /// Invoked when an IdToken has been validated and produced an AuthenticationTicket. /// - public Func OnTokenValidated { get; set; } = context => TaskCache.CompletedTask; + public Func OnTokenValidated { get; set; } = context => Task.CompletedTask; /// /// Invoked when user information is retrieved from the UserInfoEndpoint. /// - public Func OnUserInformationReceived { get; set; } = context => TaskCache.CompletedTask; + public Func OnUserInformationReceived { get; set; } = context => Task.CompletedTask; public virtual Task AuthenticationFailed(AuthenticationFailedContext context) => OnAuthenticationFailed(context); @@ -67,6 +73,8 @@ public class OpenIdConnectEvents : RemoteAuthenticationEvents, IOpenIdConnectEve public virtual Task RedirectToIdentityProviderForSignOut(RedirectContext context) => OnRedirectToIdentityProviderForSignOut(context); + public virtual Task SignedOutCallbackRedirect(RemoteSignOutContext context) => OnSignedOutCallbackRedirect(context); + public virtual Task RemoteSignOut(RemoteSignOutContext context) => OnRemoteSignOut(context); public virtual Task TokenResponseReceived(TokenResponseReceivedContext context) => OnTokenResponseReceived(context); diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/RedirectContext.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/RedirectContext.cs index 59b1c0efd..9961c237d 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/RedirectContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/RedirectContext.cs @@ -1,24 +1,34 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; +using Microsoft.IdentityModel.Protocols.OpenIdConnect; namespace Microsoft.AspNetCore.Authentication.OpenIdConnect { /// - /// When a user configures the to be notified prior to redirecting to an IdentityProvider + /// When a user configures the to be notified prior to redirecting to an IdentityProvider /// an instance of is passed to the 'RedirectToAuthenticationEndpoint' or 'RedirectToEndSessionEndpoint' events. /// - public class RedirectContext : BaseOpenIdConnectContext + public class RedirectContext : PropertiesContext { - public RedirectContext(HttpContext context, OpenIdConnectOptions options, AuthenticationProperties properties) - : base(context, options) - { - Properties = properties; - } + public RedirectContext( + HttpContext context, + AuthenticationScheme scheme, + OpenIdConnectOptions options, + AuthenticationProperties properties) + : base(context, scheme, options, properties) { } - public AuthenticationProperties Properties { get; } + public OpenIdConnectMessage ProtocolMessage { get; set; } + + /// + /// If true, will skip any default logic for this redirect. + /// + public bool Handled { get; private set; } + + /// + /// Skips any default logic for this redirect. + /// + public void HandleResponse() => Handled = true; } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/RemoteSignoutContext.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/RemoteSignoutContext.cs index a76dc9e59..26720a58f 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/RemoteSignoutContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/RemoteSignoutContext.cs @@ -1,21 +1,17 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.IdentityModel.Protocols.OpenIdConnect; namespace Microsoft.AspNetCore.Authentication.OpenIdConnect { - public class RemoteSignOutContext : BaseOpenIdConnectContext + public class RemoteSignOutContext : RemoteAuthenticationContext { - public RemoteSignOutContext( - HttpContext context, - OpenIdConnectOptions options, - OpenIdConnectMessage message) - : base(context, options) - { - ProtocolMessage = message; - } + public RemoteSignOutContext(HttpContext context, AuthenticationScheme scheme, OpenIdConnectOptions options, OpenIdConnectMessage message) + : base(context, scheme, options, new AuthenticationProperties()) + => ProtocolMessage = message; + + public OpenIdConnectMessage ProtocolMessage { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/TokenResponseReceivedContext.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/TokenResponseReceivedContext.cs index b4a9ad6d1..2bebdb8dc 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/TokenResponseReceivedContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/TokenResponseReceivedContext.cs @@ -1,9 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Builder; +using System.Security.Claims; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; using Microsoft.IdentityModel.Protocols.OpenIdConnect; namespace Microsoft.AspNetCore.Authentication.OpenIdConnect @@ -11,18 +10,16 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect /// /// This Context can be used to be informed when an 'AuthorizationCode' is redeemed for tokens at the token endpoint. /// - public class TokenResponseReceivedContext : BaseOpenIdConnectContext + public class TokenResponseReceivedContext : RemoteAuthenticationContext { /// /// Creates a /// - public TokenResponseReceivedContext(HttpContext context, OpenIdConnectOptions options, AuthenticationProperties properties) - : base(context, options) - { - Properties = properties; - } + public TokenResponseReceivedContext(HttpContext context, AuthenticationScheme scheme, OpenIdConnectOptions options, ClaimsPrincipal user, AuthenticationProperties properties) + : base(context, scheme, options, properties) + => Principal = user; - public AuthenticationProperties Properties { get; } + public OpenIdConnectMessage ProtocolMessage { get; set; } /// /// Gets or sets the that contains the tokens received after redeeming the code at the token endpoint. diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/TokenValidatedContext.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/TokenValidatedContext.cs index 130a4d987..853857dc7 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/TokenValidatedContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/TokenValidatedContext.cs @@ -2,26 +2,23 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.IdentityModel.Tokens.Jwt; -using System.Net.Http; -using Microsoft.AspNetCore.Builder; +using System.Security.Claims; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; using Microsoft.IdentityModel.Protocols.OpenIdConnect; namespace Microsoft.AspNetCore.Authentication.OpenIdConnect { - public class TokenValidatedContext : BaseOpenIdConnectContext + public class TokenValidatedContext : RemoteAuthenticationContext { /// /// Creates a /// - public TokenValidatedContext(HttpContext context, OpenIdConnectOptions options) - : base(context, options) - { - } + public TokenValidatedContext(HttpContext context, AuthenticationScheme scheme, OpenIdConnectOptions options, ClaimsPrincipal principal, AuthenticationProperties properties) + : base(context, scheme, options, properties) + => Principal = principal; + + public OpenIdConnectMessage ProtocolMessage { get; set; } - public AuthenticationProperties Properties { get; set; } - public JwtSecurityToken SecurityToken { get; set; } public OpenIdConnectMessage TokenEndpointResponse { get; set; } diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/UserInformationReceivedContext.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/UserInformationReceivedContext.cs index c0a53db44..0b855eaf3 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/UserInformationReceivedContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Events/UserInformationReceivedContext.cs @@ -1,18 +1,20 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Builder; +using System.Security.Claims; using Microsoft.AspNetCore.Http; +using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Newtonsoft.Json.Linq; namespace Microsoft.AspNetCore.Authentication.OpenIdConnect { - public class UserInformationReceivedContext : BaseOpenIdConnectContext + public class UserInformationReceivedContext : RemoteAuthenticationContext { - public UserInformationReceivedContext(HttpContext context, OpenIdConnectOptions options) - : base(context, options) - { - } + public UserInformationReceivedContext(HttpContext context, AuthenticationScheme scheme, OpenIdConnectOptions options, ClaimsPrincipal principal, AuthenticationProperties properties) + : base(context, scheme, options, properties) + => Principal = principal; + + public OpenIdConnectMessage ProtocolMessage { get; set; } public JObject User { get; set; } } diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/LoggingExtensions.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/LoggingExtensions.cs index aa6d0cbaa..224af87b6 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/LoggingExtensions.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/LoggingExtensions.cs @@ -8,9 +8,9 @@ namespace Microsoft.Extensions.Logging internal static class LoggingExtensions { private static Action _redirectToIdentityProviderForSignOutHandledResponse; - private static Action _redirectToIdentityProviderForSignOutSkipped; private static Action _redirectToIdentityProviderHandledResponse; - private static Action _redirectToIdentityProviderSkipped; + private static Action _signoutCallbackRedirectHandledResponse; + private static Action _signoutCallbackRedirectSkipped; private static Action _updatingConfiguration; private static Action _receivedIdToken; private static Action _redeemingCodeForTokens; @@ -55,6 +55,7 @@ internal static class LoggingExtensions private static Action _remoteSignOut; private static Action _remoteSignOutSessionIdMissing; private static Action _remoteSignOutSessionIdInvalid; + private static Action _signOut; static LoggingExtensions() { @@ -63,10 +64,6 @@ static LoggingExtensions() eventId: 1, logLevel: LogLevel.Debug, formatString: "RedirectToIdentityProviderForSignOut.HandledResponse"); - _redirectToIdentityProviderForSignOutSkipped = LoggerMessage.Define( - eventId: 2, - logLevel: LogLevel.Debug, - formatString: "RedirectToIdentityProviderForSignOut.Skipped"); _invalidLogoutQueryStringRedirectUrl = LoggerMessage.Define( eventId: 3, logLevel: LogLevel.Warning, @@ -87,10 +84,6 @@ static LoggingExtensions() eventId: 6, logLevel: LogLevel.Debug, formatString: "RedirectToIdentityProvider.HandledResponse"); - _redirectToIdentityProviderSkipped = LoggerMessage.Define( - eventId: 7, - logLevel: LogLevel.Debug, - formatString: "RedirectToIdentityProvider.Skipped"); _invalidAuthenticationRequestUrl = LoggerMessage.Define( eventId: 8, logLevel: LogLevel.Warning, @@ -253,6 +246,18 @@ static LoggingExtensions() logLevel: LogLevel.Error, formatString: "The remote signout request was ignored because the 'sid' parameter didn't match " + "the expected value, which may indicate an unsolicited logout."); + _signOut = LoggerMessage.Define( + eventId: 49, + logLevel: LogLevel.Information, + formatString: "AuthenticationScheme: {AuthenticationScheme} signed out."); + _signoutCallbackRedirectHandledResponse = LoggerMessage.Define( + eventId: 50, + logLevel: LogLevel.Debug, + formatString: "RedirectToSignedOutRedirectUri.HandledResponse"); + _signoutCallbackRedirectSkipped = LoggerMessage.Define( + eventId: 51, + logLevel: LogLevel.Debug, + formatString: "RedirectToSignedOutRedirectUri.Skipped"); } public static void UpdatingConfiguration(this ILogger logger) @@ -345,19 +350,19 @@ public static void RedirectToIdentityProviderForSignOutHandledResponse(this ILog _redirectToIdentityProviderForSignOutHandledResponse(logger, null); } - public static void RedirectToIdentityProviderForSignOutSkipped(this ILogger logger) + public static void RedirectToIdentityProviderHandledResponse(this ILogger logger) { - _redirectToIdentityProviderForSignOutSkipped(logger, null); + _redirectToIdentityProviderHandledResponse(logger, null); } - public static void RedirectToIdentityProviderHandledResponse(this ILogger logger) + public static void SignoutCallbackRedirectHandledResponse(this ILogger logger) { - _redirectToIdentityProviderHandledResponse(logger, null); + _signoutCallbackRedirectHandledResponse(logger, null); } - public static void RedirectToIdentityProviderSkipped(this ILogger logger) + public static void SignoutCallbackRedirectSkipped(this ILogger logger) { - _redirectToIdentityProviderSkipped(logger, null); + _signoutCallbackRedirectSkipped(logger, null); } public static void UserInformationReceivedHandledResponse(this ILogger logger) @@ -494,5 +499,10 @@ public static void RemoteSignOutSessionIdInvalid(this ILogger logger) { _remoteSignOutSessionIdInvalid(logger, null); } + + public static void SignedOut(this ILogger logger, string authenticationScheme) + { + _signOut(logger, authenticationScheme, null); + } } } diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj new file mode 100644 index 000000000..65ca6b842 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj @@ -0,0 +1,19 @@ + + + + ASP.NET Core middleware that enables an application to support the OpenID Connect authentication workflow. + netcoreapp3.0 + $(NoWarn);CS1591 + true + aspnetcore;authentication;security + + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Microsoft.AspNetCore.Authentication.OpenIdConnect.xproj b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Microsoft.AspNetCore.Authentication.OpenIdConnect.xproj deleted file mode 100644 index 6a07e8120..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Microsoft.AspNetCore.Authentication.OpenIdConnect.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 35115d55-b69e-46d4-bb33-c9e9e6ec5e7a - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectAppBuilderExtensions.cs index dde12494d..0746ae3fd 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectAppBuilderExtensions.cs @@ -1,9 +1,8 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.AspNetCore.Authentication.OpenIdConnect; -using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Builder { @@ -13,38 +12,26 @@ namespace Microsoft.AspNetCore.Builder public static class OpenIdConnectAppBuilderExtensions { /// - /// Adds the middleware to the specified , which enables OpenID Connect authentication capabilities. + /// UseOpenIdConnectAuthentication is obsolete. Configure OpenIdConnect authentication with AddAuthentication().AddOpenIdConnect in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. + /// The to add the handler to. /// A reference to this instance after the operation has completed. + [Obsolete("UseOpenIdConnectAuthentication is obsolete. Configure OpenIdConnect authentication with AddAuthentication().AddOpenIdConnect in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)] public static IApplicationBuilder UseOpenIdConnectAuthentication(this IApplicationBuilder app) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - - return app.UseMiddleware(); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } /// - /// Adds the middleware to the specified , which enables OpenID Connect authentication capabilities. + /// UseOpenIdConnectAuthentication is obsolete. Configure OpenIdConnect authentication with AddAuthentication().AddOpenIdConnect in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. - /// A that specifies options for the middleware. + /// The to add the handler to. + /// A that specifies options for the handler. /// A reference to this instance after the operation has completed. + [Obsolete("UseOpenIdConnectAuthentication is obsolete. Configure OpenIdConnect authentication with AddAuthentication().AddOpenIdConnect in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)] public static IApplicationBuilder UseOpenIdConnectAuthentication(this IApplicationBuilder app, OpenIdConnectOptions options) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - return app.UseMiddleware(Options.Create(options)); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectChallengeProperties.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectChallengeProperties.cs new file mode 100644 index 000000000..0ced488de --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectChallengeProperties.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Authentication.OAuth; +using Microsoft.IdentityModel.Protocols.OpenIdConnect; + +namespace Microsoft.AspNetCore.Authentication.OpenIdConnect +{ + public class OpenIdConnectChallengeProperties : OAuthChallengeProperties + { + /// + /// The parameter key for the "max_age" argument being used for a challenge request. + /// + public static readonly string MaxAgeKey = OpenIdConnectParameterNames.MaxAge; + + /// + /// The parameter key for the "prompt" argument being used for a challenge request. + /// + public static readonly string PromptKey = OpenIdConnectParameterNames.Prompt; + + public OpenIdConnectChallengeProperties() + { } + + public OpenIdConnectChallengeProperties(IDictionary items) + : base(items) + { } + + public OpenIdConnectChallengeProperties(IDictionary items, IDictionary parameters) + : base(items, parameters) + { } + + /// + /// The "max_age" parameter value being used for a challenge request. + /// + public TimeSpan? MaxAge + { + get => GetParameter(MaxAgeKey); + set => SetParameter(MaxAgeKey, value); + } + + /// + /// The "prompt" parameter value being used for a challenge request. + /// + public string Prompt + { + get => GetParameter(PromptKey); + set => SetParameter(PromptKey, value); + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectDefaults.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectDefaults.cs index a099a7276..f98ba87e0 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectDefaults.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectDefaults.cs @@ -4,7 +4,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect { /// - /// Default values related to OpenIdConnect authentication middleware + /// Default values related to OpenIdConnect authentication handler /// public static class OpenIdConnectDefaults { @@ -19,9 +19,9 @@ public static class OpenIdConnectDefaults public const string AuthenticationScheme = "OpenIdConnect"; /// - /// The default value for OpenIdConnectOptions.Caption. + /// The default value for the display name. /// - public static readonly string Caption = "OpenIdConnect"; + public static readonly string DisplayName = "OpenIdConnect"; /// /// The prefix used to for the nonce in the cookie. diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectExtensions.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectExtensions.cs new file mode 100644 index 000000000..f427bebaf --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectExtensions.cs @@ -0,0 +1,29 @@ +// 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.OpenIdConnect; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class OpenIdConnectExtensions + { + public static AuthenticationBuilder AddOpenIdConnect(this AuthenticationBuilder builder) + => builder.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, _ => { }); + + public static AuthenticationBuilder AddOpenIdConnect(this AuthenticationBuilder builder, Action configureOptions) + => builder.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, configureOptions); + + public static AuthenticationBuilder AddOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, Action configureOptions) + => builder.AddOpenIdConnect(authenticationScheme, OpenIdConnectDefaults.DisplayName, configureOptions); + + public static AuthenticationBuilder AddOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions) + { + builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton, OpenIdConnectPostConfigureOptions>()); + return builder.AddRemoteScheme(authenticationScheme, displayName, configureOptions); + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectHandler.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectHandler.cs index c9c513ea7..8b0b72428 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectHandler.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectHandler.cs @@ -13,12 +13,9 @@ using System.Text; using System.Text.Encodings.Web; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Primitives; +using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Tokens; using Microsoft.Net.Http.Headers; @@ -29,52 +26,50 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect /// /// A per-request authentication handler for the OpenIdConnectAuthenticationMiddleware. /// - public class OpenIdConnectHandler : RemoteAuthenticationHandler + public class OpenIdConnectHandler : RemoteAuthenticationHandler, IAuthenticationSignOutHandler { private const string NonceProperty = "N"; - private const string UriSchemeDelimiter = "://"; - - private const string InputTagFormat = @""; - private const string HtmlFormFormat = @" - - - Please wait while you're being redirected to the identity provider - - -
- {1} - -
- - -"; + + private const string HeaderValueEpocDate = "Thu, 01 Jan 1970 00:00:00 GMT"; private static readonly RandomNumberGenerator CryptoRandom = RandomNumberGenerator.Create(); private OpenIdConnectConfiguration _configuration; - protected HttpClient Backchannel { get; private set; } + protected HttpClient Backchannel => Options.Backchannel; - protected HtmlEncoder HtmlEncoder { get; private set; } + protected HtmlEncoder HtmlEncoder { get; } - public OpenIdConnectHandler(HttpClient backchannel, HtmlEncoder htmlEncoder) + public OpenIdConnectHandler(IOptionsMonitor options, ILoggerFactory logger, HtmlEncoder htmlEncoder, UrlEncoder encoder, ISystemClock clock) + : base(options, logger, encoder, clock) { - Backchannel = backchannel; HtmlEncoder = htmlEncoder; } - public override async Task HandleRequestAsync() + /// + /// 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. + /// + protected new OpenIdConnectEvents Events + { + get { return (OpenIdConnectEvents)base.Events; } + set { base.Events = value; } + } + + protected override Task CreateEventsAsync() => Task.FromResult(new OpenIdConnectEvents()); + + public override Task HandleRequestAsync() { if (Options.RemoteSignOutPath.HasValue && Options.RemoteSignOutPath == Request.Path) { - return await HandleRemoteSignOutAsync(); + return HandleRemoteSignOutAsync(); } else if (Options.SignedOutCallbackPath.HasValue && Options.SignedOutCallbackPath == Request.Path) { - return await HandleSignOutCallbackAsync(); + return HandleSignOutCallbackAsync(); } - return await base.HandleRequestAsync(); + return base.HandleRequestAsync(); } protected virtual async Task HandleRemoteSignOutAsync() @@ -97,18 +92,25 @@ protected virtual async Task HandleRemoteSignOutAsync() message = new OpenIdConnectMessage(form.Select(pair => new KeyValuePair(pair.Key, pair.Value))); } - var remoteSignOutContext = new RemoteSignOutContext(Context, Options, message); - await Options.Events.RemoteSignOut(remoteSignOutContext); + var remoteSignOutContext = new RemoteSignOutContext(Context, Scheme, Options, message); + await Events.RemoteSignOut(remoteSignOutContext); - if (remoteSignOutContext.HandledResponse) + if (remoteSignOutContext.Result != null) { - Logger.RemoteSignOutHandledResponse(); - return true; - } - if (remoteSignOutContext.Skipped) - { - Logger.RemoteSignOutSkipped(); - return false; + if (remoteSignOutContext.Result.Handled) + { + Logger.RemoteSignOutHandledResponse(); + return true; + } + if (remoteSignOutContext.Result.Skipped) + { + Logger.RemoteSignOutSkipped(); + return false; + } + if (remoteSignOutContext.Result.Failure != null) + { + throw new InvalidOperationException("An error was returned from the RemoteSignOut event.", remoteSignOutContext.Result.Failure); + } } if (message == null) @@ -120,7 +122,8 @@ protected virtual async Task HandleRemoteSignOutAsync() // If the identifier cannot be found, bypass the session identifier checks: this may indicate that the // authentication cookie was already cleared, that the session identifier was lost because of a lossy // external/application cookie conversion or that the identity provider doesn't support sessions. - var sid = (await Context.Authentication.AuthenticateAsync(Options.SignOutScheme)) + var sid = (await Context.AuthenticateAsync(Options.SignOutScheme)) + ?.Principal ?.FindFirst(JwtRegisteredClaimNames.Sid) ?.Value; if (!string.IsNullOrEmpty(sid)) @@ -142,7 +145,7 @@ protected virtual async Task HandleRemoteSignOutAsync() Logger.RemoteSignOut(); // We've received a remote sign-out request - await Context.Authentication.SignOutAsync(Options.SignOutScheme); + await Context.SignOutAsync(Options.SignOutScheme); return true; } @@ -150,8 +153,17 @@ protected virtual async Task HandleRemoteSignOutAsync() /// Redirect user to the identity provider for sign out /// /// A task executing the sign out procedure - protected override async Task HandleSignOutAsync(SignOutContext signout) + public async virtual Task SignOutAsync(AuthenticationProperties properties) { + var target = ResolveTarget(Options.ForwardSignOut); + if (target != null) + { + await Context.SignOutAsync(target, properties); + return; + } + + properties = properties ?? new AuthenticationProperties(); + Logger.EnteringOpenIdAuthenticationHandlerHandleSignOutAsync(GetType().FullName); if (_configuration == null && Options.ConfigurationManager != null) @@ -161,6 +173,7 @@ protected override async Task HandleSignOutAsync(SignOutContext signout) var message = new OpenIdConnectMessage() { + EnableTelemetryParameters = !Options.DisableTelemetry, IssuerAddress = _configuration?.EndSessionEndpoint ?? string.Empty, // Redirect back to SigneOutCallbackPath first before user agent is redirected to actual post logout redirect uri @@ -168,36 +181,30 @@ protected override async Task HandleSignOutAsync(SignOutContext signout) }; // Get the post redirect URI. - var properties = new AuthenticationProperties(signout.Properties); if (string.IsNullOrEmpty(properties.RedirectUri)) { - properties.RedirectUri = BuildRedirectUriIfRelative(Options.PostLogoutRedirectUri); + properties.RedirectUri = BuildRedirectUriIfRelative(Options.SignedOutRedirectUri); if (string.IsNullOrWhiteSpace(properties.RedirectUri)) { - properties.RedirectUri = CurrentUri; + properties.RedirectUri = OriginalPathBase + OriginalPath + Request.QueryString; } } Logger.PostSignOutRedirect(properties.RedirectUri); // Attach the identity token to the logout request when possible. - message.IdTokenHint = await Context.Authentication.GetTokenAsync(Options.SignOutScheme, OpenIdConnectParameterNames.IdToken); + message.IdTokenHint = await Context.GetTokenAsync(Options.SignOutScheme, OpenIdConnectParameterNames.IdToken); - var redirectContext = new RedirectContext(Context, Options, properties) + var redirectContext = new RedirectContext(Context, Scheme, Options, properties) { ProtocolMessage = message }; - await Options.Events.RedirectToIdentityProviderForSignOut(redirectContext); - if (redirectContext.HandledResponse) + await Events.RedirectToIdentityProviderForSignOut(redirectContext); + if (redirectContext.Handled) { Logger.RedirectToIdentityProviderForSignOutHandledResponse(); return; } - else if (redirectContext.Skipped) - { - Logger.RedirectToIdentityProviderForSignOutSkipped(); - return; - } message = redirectContext.ProtocolMessage; @@ -210,8 +217,7 @@ protected override async Task HandleSignOutAsync(SignOutContext signout) if (string.IsNullOrEmpty(message.IssuerAddress)) { - throw new InvalidOperationException( - "Cannot redirect to the end session endpoint, the configuration may be missing or invalid."); + throw new InvalidOperationException("Cannot redirect to the end session endpoint, the configuration may be missing or invalid."); } if (Options.AuthenticationMethod == OpenIdConnectRedirectBehavior.RedirectGet) @@ -226,19 +232,7 @@ protected override async Task HandleSignOutAsync(SignOutContext signout) } else if (Options.AuthenticationMethod == OpenIdConnectRedirectBehavior.FormPost) { - var inputs = new StringBuilder(); - foreach (var parameter in message.Parameters) - { - var name = HtmlEncoder.Encode(parameter.Key); - var value = HtmlEncoder.Encode(parameter.Value); - - var input = string.Format(CultureInfo.InvariantCulture, InputTagFormat, name, value); - inputs.AppendLine(input); - } - - var issuer = HtmlEncoder.Encode(message.IssuerAddress); - - var content = string.Format(CultureInfo.InvariantCulture, HtmlFormFormat, issuer, inputs); + var content = message.BuildFormPost(); var buffer = Encoding.UTF8.GetBytes(content); Response.ContentLength = buffer.Length; @@ -247,7 +241,7 @@ protected override async Task HandleSignOutAsync(SignOutContext signout) // Emit Cache-Control=no-cache to prevent client caching. Response.Headers[HeaderNames.CacheControl] = "no-cache"; Response.Headers[HeaderNames.Pragma] = "no-cache"; - Response.Headers[HeaderNames.Expires] = "-1"; + Response.Headers[HeaderNames.Expires] = HeaderValueEpocDate; await Response.Body.WriteAsync(buffer, 0, buffer.Length); } @@ -255,49 +249,70 @@ protected override async Task HandleSignOutAsync(SignOutContext signout) { throw new NotImplementedException($"An unsupported authentication method has been configured: {Options.AuthenticationMethod}"); } + + Logger.SignedOut(Scheme.Name); } /// /// Response to the callback from OpenId provider after session ended. /// /// A task executing the callback procedure - protected virtual Task HandleSignOutCallbackAsync() + protected async virtual Task HandleSignOutCallbackAsync() { - StringValues protectedState; - if (Request.Query.TryGetValue(OpenIdConnectParameterNames.State, out protectedState)) + var message = new OpenIdConnectMessage(Request.Query.Select(pair => new KeyValuePair(pair.Key, pair.Value))); + AuthenticationProperties properties = null; + if (!string.IsNullOrEmpty(message.State)) { - var properties = Options.StateDataFormat.Unprotect(protectedState); - if (!string.IsNullOrEmpty(properties?.RedirectUri)) + properties = Options.StateDataFormat.Unprotect(message.State); + } + + var signOut = new RemoteSignOutContext(Context, Scheme, Options, message) + { + Properties = properties, + }; + + await Events.SignedOutCallbackRedirect(signOut); + if (signOut.Result != null) + { + if (signOut.Result.Handled) { - Response.Redirect(properties.RedirectUri); - return Task.FromResult(true); + Logger.SignoutCallbackRedirectHandledResponse(); + return true; } + if (signOut.Result.Skipped) + { + Logger.SignoutCallbackRedirectSkipped(); + return false; + } + if (signOut.Result.Failure != null) + { + throw new InvalidOperationException("An error was returned from the SignedOutCallbackRedirect event.", signOut.Result.Failure); + } + } + + properties = signOut.Properties; + if (!string.IsNullOrEmpty(properties?.RedirectUri)) + { + Response.Redirect(properties.RedirectUri); } - return Task.FromResult(true); + return true; } /// /// Responds to a 401 Challenge. Sends an OpenIdConnect message to the 'identity authority' to obtain an identity. /// /// - protected override async Task HandleUnauthorizedAsync(ChallengeContext context) + protected override async Task HandleChallengeAsync(AuthenticationProperties properties) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - Logger.EnteringOpenIdAuthenticationHandlerHandleUnauthorizedAsync(GetType().FullName); // order for local RedirectUri // 1. challenge.Properties.RedirectUri // 2. CurrentUri if RedirectUri is not set) - var properties = new AuthenticationProperties(context.Properties); - if (string.IsNullOrEmpty(properties.RedirectUri)) { - properties.RedirectUri = CurrentUri; + properties.RedirectUri = OriginalPathBase + OriginalPath + Request.QueryString; } Logger.PostAuthenticationLocalRedirect(properties.RedirectUri); @@ -309,13 +324,24 @@ protected override async Task HandleUnauthorizedAsync(ChallengeContext con var message = new OpenIdConnectMessage { ClientId = Options.ClientId, + EnableTelemetryParameters = !Options.DisableTelemetry, IssuerAddress = _configuration?.AuthorizationEndpoint ?? string.Empty, RedirectUri = BuildRedirectUri(Options.CallbackPath), Resource = Options.Resource, ResponseType = Options.ResponseType, - Scope = string.Join(" ", Options.Scope) + Prompt = properties.GetParameter(OpenIdConnectParameterNames.Prompt) ?? Options.Prompt, + Scope = string.Join(" ", properties.GetParameter>(OpenIdConnectParameterNames.Scope) ?? Options.Scope), }; + // Add the 'max_age' parameter to the authentication request if MaxAge is not null. + // See http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest + var maxAge = properties.GetParameter(OpenIdConnectParameterNames.MaxAge) ?? Options.MaxAge; + if (maxAge.HasValue) + { + message.MaxAge = Convert.ToInt64(Math.Floor((maxAge.Value).TotalSeconds)) + .ToString(CultureInfo.InvariantCulture); + } + // Omitting the response_mode parameter when it already corresponds to the default // response_mode used for the specified response_type is recommended by the specifications. // See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes @@ -333,21 +359,16 @@ protected override async Task HandleUnauthorizedAsync(ChallengeContext con GenerateCorrelationId(properties); - var redirectContext = new RedirectContext(Context, Options, properties) + var redirectContext = new RedirectContext(Context, Scheme, Options, properties) { ProtocolMessage = message }; - await Options.Events.RedirectToIdentityProvider(redirectContext); - if (redirectContext.HandledResponse) + await Events.RedirectToIdentityProvider(redirectContext); + if (redirectContext.Handled) { Logger.RedirectToIdentityProviderHandledResponse(); - return true; - } - else if (redirectContext.Skipped) - { - Logger.RedirectToIdentityProviderSkipped(); - return false; + return; } message = redirectContext.ProtocolMessage; @@ -377,23 +398,11 @@ protected override async Task HandleUnauthorizedAsync(ChallengeContext con } Response.Redirect(redirectUri); - return true; + return; } else if (Options.AuthenticationMethod == OpenIdConnectRedirectBehavior.FormPost) { - var inputs = new StringBuilder(); - foreach (var parameter in message.Parameters) - { - var name = HtmlEncoder.Encode(parameter.Key); - var value = HtmlEncoder.Encode(parameter.Value); - - var input = string.Format(CultureInfo.InvariantCulture, InputTagFormat, name, value); - inputs.AppendLine(input); - } - - var issuer = HtmlEncoder.Encode(message.IssuerAddress); - - var content = string.Format(CultureInfo.InvariantCulture, HtmlFormFormat, issuer, inputs); + var content = message.BuildFormPost(); var buffer = Encoding.UTF8.GetBytes(content); Response.ContentLength = buffer.Length; @@ -402,10 +411,10 @@ protected override async Task HandleUnauthorizedAsync(ChallengeContext con // Emit Cache-Control=no-cache to prevent client caching. Response.Headers[HeaderNames.CacheControl] = "no-cache"; Response.Headers[HeaderNames.Pragma] = "no-cache"; - Response.Headers[HeaderNames.Expires] = "-1"; + Response.Headers[HeaderNames.Expires] = HeaderValueEpocDate; await Response.Body.WriteAsync(buffer, 0, buffer.Length); - return true; + return; } throw new NotImplementedException($"An unsupported authentication method has been configured: {Options.AuthenticationMethod}"); @@ -414,8 +423,8 @@ protected override async Task HandleUnauthorizedAsync(ChallengeContext con /// /// Invoked to process incoming OpenIdConnect messages. /// - /// An if successful. - protected override async Task HandleRemoteAuthenticateAsync() + /// An . + protected override async Task HandleRemoteAuthenticateAsync() { Logger.EnteringOpenIdAuthenticationHandlerHandleRemoteAuthenticateAsync(GetType().FullName); @@ -433,9 +442,9 @@ protected override async Task HandleRemoteAuthenticateAsync( if (Options.SkipUnrecognizedRequests) { // Not for us? - return AuthenticateResult.Skip(); + return HandleRequestResult.SkipHandler(); } - return AuthenticateResult.Fail("An OpenID Connect response cannot contain an " + + return HandleRequestResult.Fail("An OpenID Connect response cannot contain an " + "identity token or an access token when using response_mode=query"); } } @@ -455,25 +464,20 @@ protected override async Task HandleRemoteAuthenticateAsync( if (Options.SkipUnrecognizedRequests) { // Not for us? - return AuthenticateResult.Skip(); + return HandleRequestResult.SkipHandler(); } - return AuthenticateResult.Fail("No message."); + return HandleRequestResult.Fail("No message."); } - AuthenticateResult result; - + AuthenticationProperties properties = null; try { - AuthenticationProperties properties = null; - if (!string.IsNullOrEmpty(authorizationResponse.State)) - { - properties = Options.StateDataFormat.Unprotect(authorizationResponse.State); - } + properties = ReadPropertiesAndClearState(authorizationResponse); var messageReceivedContext = await RunMessageReceivedEventAsync(authorizationResponse, properties); - if (messageReceivedContext.CheckEventResult(out result)) + if (messageReceivedContext.Result != null) { - return result; + return messageReceivedContext.Result; } authorizationResponse = messageReceivedContext.ProtocolMessage; properties = messageReceivedContext.Properties; @@ -487,13 +491,12 @@ protected override async Task HandleRemoteAuthenticateAsync( Logger.NullOrEmptyAuthorizationResponseState(); if (Options.SkipUnrecognizedRequests) { - return AuthenticateResult.Skip(); + return HandleRequestResult.SkipHandler(); } - return AuthenticateResult.Fail(Resources.MessageStateIsNullOrEmpty); + return HandleRequestResult.Fail(Resources.MessageStateIsNullOrEmpty); } - // if state exists and we failed to 'unprotect' this is not a message we should process. - properties = Options.StateDataFormat.Unprotect(authorizationResponse.State); + properties = ReadPropertiesAndClearState(authorizationResponse); } if (properties == null) @@ -502,24 +505,32 @@ protected override async Task HandleRemoteAuthenticateAsync( if (Options.SkipUnrecognizedRequests) { // Not for us? - return AuthenticateResult.Skip(); + return HandleRequestResult.SkipHandler(); } - return AuthenticateResult.Fail(Resources.MessageStateIsInvalid); - } - string userstate = null; - properties.Items.TryGetValue(OpenIdConnectDefaults.UserstatePropertiesKey, out userstate); - authorizationResponse.State = userstate; + // if state exists and we failed to 'unprotect' this is not a message we should process. + return HandleRequestResult.Fail(Resources.MessageStateIsInvalid); + } if (!ValidateCorrelationId(properties)) { - return AuthenticateResult.Fail("Correlation failed."); + return HandleRequestResult.Fail("Correlation failed.", properties); } // if any of the error fields are set, throw error null if (!string.IsNullOrEmpty(authorizationResponse.Error)) { - return AuthenticateResult.Fail(CreateOpenIdConnectProtocolException(authorizationResponse, response: null)); + // Note: access_denied errors are special protocol errors indicating the user didn't + // approve the authorization demand requested by the remote authorization server. + // Since it's a frequent scenario (that is not caused by incorrect configuration), + // denied errors are handled differently using HandleAccessDeniedErrorAsync(). + // Visit https://tools.ietf.org/html/rfc6749#section-4.1.2.1 for more information. + if (string.Equals(authorizationResponse.Error, "access_denied", StringComparison.Ordinal)) + { + return await HandleAccessDeniedErrorAsync(properties); + } + + return HandleRequestResult.Fail(CreateOpenIdConnectProtocolException(authorizationResponse, response: null), properties); } if (_configuration == null && Options.ConfigurationManager != null) @@ -530,7 +541,7 @@ protected override async Task HandleRemoteAuthenticateAsync( PopulateSessionProperties(authorizationResponse, properties); - AuthenticationTicket ticket = null; + ClaimsPrincipal user = null; JwtSecurityToken jwt = null; string nonce = null; var validationParameters = Options.TokenValidationParameters.Clone(); @@ -539,7 +550,7 @@ protected override async Task HandleRemoteAuthenticateAsync( if (!string.IsNullOrEmpty(authorizationResponse.IdToken)) { Logger.ReceivedIdToken(); - ticket = ValidateToken(authorizationResponse.IdToken, properties, validationParameters, out jwt); + user = ValidateToken(authorizationResponse.IdToken, properties, validationParameters, out jwt); nonce = jwt.Payload.Nonce; if (!string.IsNullOrEmpty(nonce)) @@ -547,14 +558,14 @@ protected override async Task HandleRemoteAuthenticateAsync( nonce = ReadNonceCookie(nonce); } - var tokenValidatedContext = await RunTokenValidatedEventAsync(authorizationResponse, null, properties, ticket, jwt, nonce); - if (tokenValidatedContext.CheckEventResult(out result)) + var tokenValidatedContext = await RunTokenValidatedEventAsync(authorizationResponse, null, user, properties, jwt, nonce); + if (tokenValidatedContext.Result != null) { - return result; + return tokenValidatedContext.Result; } authorizationResponse = tokenValidatedContext.ProtocolMessage; + user = tokenValidatedContext.Principal; properties = tokenValidatedContext.Properties; - ticket = tokenValidatedContext.Ticket; jwt = tokenValidatedContext.SecurityToken; nonce = tokenValidatedContext.Nonce; } @@ -572,17 +583,17 @@ protected override async Task HandleRemoteAuthenticateAsync( // Authorization Code or Hybrid flow if (!string.IsNullOrEmpty(authorizationResponse.Code)) { - var authorizationCodeReceivedContext = await RunAuthorizationCodeReceivedEventAsync(authorizationResponse, properties, ticket, jwt); - if (authorizationCodeReceivedContext.CheckEventResult(out result)) + var authorizationCodeReceivedContext = await RunAuthorizationCodeReceivedEventAsync(authorizationResponse, user, properties, jwt); + if (authorizationCodeReceivedContext.Result != null) { - return result; + return authorizationCodeReceivedContext.Result; } authorizationResponse = authorizationCodeReceivedContext.ProtocolMessage; + user = authorizationCodeReceivedContext.Principal; properties = authorizationCodeReceivedContext.Properties; var tokenEndpointRequest = authorizationCodeReceivedContext.TokenEndpointRequest; // If the developer redeemed the code themselves... tokenEndpointResponse = authorizationCodeReceivedContext.TokenEndpointResponse; - ticket = authorizationCodeReceivedContext.Ticket; jwt = authorizationCodeReceivedContext.JwtSecurityToken; if (!authorizationCodeReceivedContext.HandledCodeRedemption) @@ -590,14 +601,16 @@ protected override async Task HandleRemoteAuthenticateAsync( tokenEndpointResponse = await RedeemAuthorizationCodeAsync(tokenEndpointRequest); } - var tokenResponseReceivedContext = await RunTokenResponseReceivedEventAsync(authorizationResponse, tokenEndpointResponse, properties, ticket); - if (tokenResponseReceivedContext.CheckEventResult(out result)) + var tokenResponseReceivedContext = await RunTokenResponseReceivedEventAsync(authorizationResponse, tokenEndpointResponse, user, properties); + if (tokenResponseReceivedContext.Result != null) { - return result; + return tokenResponseReceivedContext.Result; } authorizationResponse = tokenResponseReceivedContext.ProtocolMessage; tokenEndpointResponse = tokenResponseReceivedContext.TokenEndpointResponse; + user = tokenResponseReceivedContext.Principal; + properties = tokenResponseReceivedContext.Properties; // no need to validate signature when token is received using "code flow" as per spec // [http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation]. @@ -605,11 +618,10 @@ protected override async Task HandleRemoteAuthenticateAsync( // At least a cursory validation is required on the new IdToken, even if we've already validated the one from the authorization response. // And we'll want to validate the new JWT in ValidateTokenResponse. - JwtSecurityToken tokenEndpointJwt; - var tokenEndpointTicket = ValidateToken(tokenEndpointResponse.IdToken, properties, validationParameters, out tokenEndpointJwt); + var tokenEndpointUser = ValidateToken(tokenEndpointResponse.IdToken, properties, validationParameters, out var tokenEndpointJwt); // Avoid reading & deleting the nonce cookie, running the event, etc, if it was already done as part of the authorization response validation. - if (ticket == null) + if (user == null) { nonce = tokenEndpointJwt.Payload.Nonce; if (!string.IsNullOrEmpty(nonce)) @@ -617,15 +629,15 @@ protected override async Task HandleRemoteAuthenticateAsync( nonce = ReadNonceCookie(nonce); } - var tokenValidatedContext = await RunTokenValidatedEventAsync(authorizationResponse, tokenEndpointResponse, properties, tokenEndpointTicket, tokenEndpointJwt, nonce); - if (tokenValidatedContext.CheckEventResult(out result)) + var tokenValidatedContext = await RunTokenValidatedEventAsync(authorizationResponse, tokenEndpointResponse, tokenEndpointUser, properties, tokenEndpointJwt, nonce); + if (tokenValidatedContext.Result != null) { - return result; + return tokenValidatedContext.Result; } authorizationResponse = tokenValidatedContext.ProtocolMessage; tokenEndpointResponse = tokenValidatedContext.TokenEndpointResponse; + user = tokenValidatedContext.Principal; properties = tokenValidatedContext.Properties; - ticket = tokenValidatedContext.Ticket; jwt = tokenValidatedContext.SecurityToken; nonce = tokenValidatedContext.Nonce; } @@ -654,15 +666,23 @@ protected override async Task HandleRemoteAuthenticateAsync( if (Options.SaveTokens) { - SaveTokens(ticket.Properties, tokenEndpointResponse ?? authorizationResponse); + SaveTokens(properties, tokenEndpointResponse ?? authorizationResponse); } if (Options.GetClaimsFromUserInfoEndpoint) { - return await GetUserInformationAsync(tokenEndpointResponse ?? authorizationResponse, jwt, ticket); + return await GetUserInformationAsync(tokenEndpointResponse ?? authorizationResponse, jwt, user, properties); + } + else + { + var identity = (ClaimsIdentity)user.Identity; + foreach (var action in Options.ClaimActions) + { + action.Run(null, identity, ClaimsIssuer); + } } - return AuthenticateResult.Success(ticket); + return HandleRequestResult.Success(new AuthenticationTicket(user, properties, Scheme.Name)); } catch (Exception exception) { @@ -679,13 +699,30 @@ protected override async Task HandleRemoteAuthenticateAsync( } var authenticationFailedContext = await RunAuthenticationFailedEventAsync(authorizationResponse, exception); - if (authenticationFailedContext.CheckEventResult(out result)) + if (authenticationFailedContext.Result != null) { - return result; + return authenticationFailedContext.Result; } - return AuthenticateResult.Fail(exception); + return HandleRequestResult.Fail(exception, properties); + } + } + + private AuthenticationProperties ReadPropertiesAndClearState(OpenIdConnectMessage message) + { + AuthenticationProperties properties = null; + if (!string.IsNullOrEmpty(message.State)) + { + properties = Options.StateDataFormat.Unprotect(message.State); + + if (properties != null) + { + // If properties can be decoded from state, clear the message state. + properties.Items.TryGetValue(OpenIdConnectDefaults.UserstatePropertiesKey, out var userstate); + message.State = userstate; + } } + return properties; } private void PopulateSessionProperties(OpenIdConnectMessage message, AuthenticationProperties properties) @@ -727,7 +764,7 @@ protected virtual async Task RedeemAuthorizationCodeAsync( // Error handling: // 1. If the response body can't be parsed as json, throws. - // 2. If the response's status code is not in 2XX range, throw OpenIdConnectProtocolException. If the body is correct parsed, + // 2. If the response's status code is not in 2XX range, throw OpenIdConnectProtocolException. If the body is correct parsed, // pass the error information from body to the exception. OpenIdConnectMessage message; try @@ -753,21 +790,24 @@ protected virtual async Task RedeemAuthorizationCodeAsync( /// /// message that is being processed /// The . - /// authentication ticket with claims principal and identities - /// Authentication ticket with identity with additional claims, if any. - protected virtual async Task GetUserInformationAsync(OpenIdConnectMessage message, JwtSecurityToken jwt, AuthenticationTicket ticket) + /// The claims principal and identities. + /// The authentication properties. + /// which is used to determine if the remote authentication was successful. + protected virtual async Task GetUserInformationAsync( + OpenIdConnectMessage message, JwtSecurityToken jwt, + ClaimsPrincipal principal, AuthenticationProperties properties) { var userInfoEndpoint = _configuration?.UserInfoEndpoint; if (string.IsNullOrEmpty(userInfoEndpoint)) { Logger.UserInfoEndpointNotSet(); - return AuthenticateResult.Success(ticket); + return HandleRequestResult.Success(new AuthenticationTicket(principal, properties, Scheme.Name)); } if (string.IsNullOrEmpty(message.AccessToken)) { Logger.AccessTokenNotAvailable(); - return AuthenticateResult.Success(ticket); + return HandleRequestResult.Success(new AuthenticationTicket(principal, properties, Scheme.Name)); } Logger.RetrievingClaims(); var requestMessage = new HttpRequestMessage(HttpMethod.Get, userInfoEndpoint); @@ -789,16 +829,16 @@ protected virtual async Task GetUserInformationAsync(OpenIdC } else { - return AuthenticateResult.Fail("Unknown response type: " + contentType.MediaType); + return HandleRequestResult.Fail("Unknown response type: " + contentType.MediaType, properties); } - var userInformationReceivedContext = await RunUserInformationReceivedEventAsync(ticket, message, user); - AuthenticateResult result; - if (userInformationReceivedContext.CheckEventResult(out result)) + var userInformationReceivedContext = await RunUserInformationReceivedEventAsync(principal, properties, message, user); + if (userInformationReceivedContext.Result != null) { - return result; + return userInformationReceivedContext.Result; } - ticket = userInformationReceivedContext.Ticket; + principal = userInformationReceivedContext.Principal; + properties = userInformationReceivedContext.Properties; user = userInformationReceivedContext.User; Options.ProtocolValidator.ValidateUserInfoResponse(new OpenIdConnectProtocolValidationContext() @@ -807,32 +847,14 @@ protected virtual async Task GetUserInformationAsync(OpenIdC ValidatedIdToken = jwt, }); - var identity = (ClaimsIdentity)ticket.Principal.Identity; + var identity = (ClaimsIdentity)principal.Identity; - foreach (var claim in identity.Claims) + foreach (var action in Options.ClaimActions) { - // If this claimType is mapped by the JwtSeurityTokenHandler, then this property will be set - var shortClaimTypeName = claim.Properties.ContainsKey(JwtSecurityTokenHandler.ShortClaimTypeProperty) ? - claim.Properties[JwtSecurityTokenHandler.ShortClaimTypeProperty] : string.Empty; - - // checking if claim in the identity (generated from id_token) has the same type as a claim retrieved from userinfo endpoint - JToken value; - var isClaimIncluded = user.TryGetValue(claim.Type, out value) || user.TryGetValue(shortClaimTypeName, out value); - - // if a same claim exists (matching both type and value) both in id_token identity and userinfo response, remove the json entry from the userinfo response - if (isClaimIncluded && claim.Value.Equals(value.ToString(), StringComparison.Ordinal)) - { - if (!user.Remove(claim.Type)) - { - user.Remove(shortClaimTypeName); - } - } + action.Run(user, identity, ClaimsIssuer); } - // adding remaining unique claims from userinfo endpoint to the identity - ClaimsHelper.AddClaimsToIdentity(user, identity, jwt.Issuer); - - return AuthenticateResult.Success(ticket); + return HandleRequestResult.Success(new AuthenticationTicket(principal, properties, Scheme.Name)); } /// @@ -866,10 +888,9 @@ private void SaveTokens(AuthenticationProperties properties, OpenIdConnectMessag if (!string.IsNullOrEmpty(message.ExpiresIn)) { - int value; - if (int.TryParse(message.ExpiresIn, NumberStyles.Integer, CultureInfo.InvariantCulture, out value)) + if (int.TryParse(message.ExpiresIn, NumberStyles.Integer, CultureInfo.InvariantCulture, out int value)) { - var expiresAt = Options.SystemClock.UtcNow + TimeSpan.FromSeconds(value); + var expiresAt = Clock.UtcNow + TimeSpan.FromSeconds(value); // https://www.w3.org/TR/xmlschema-2/#dateTime // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx tokens.Add(new AuthenticationToken { Name = "expires_at", Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) }); @@ -892,15 +913,12 @@ private void WriteNonceCookie(string nonce) throw new ArgumentNullException(nameof(nonce)); } + var cookieOptions = Options.NonceCookie.Build(Context, Clock.UtcNow); + Response.Cookies.Append( - OpenIdConnectDefaults.CookieNoncePrefix + Options.StringDataFormat.Protect(nonce), + Options.NonceCookie.Name + Options.StringDataFormat.Protect(nonce), NonceProperty, - new CookieOptions - { - HttpOnly = true, - Secure = Request.IsHttps, - Expires = Options.SystemClock.UtcNow.Add(Options.ProtocolValidator.NonceLifetime) - }); + cookieOptions); } /// @@ -908,7 +926,7 @@ private void WriteNonceCookie(string nonce) /// /// the nonce that we are looking for. /// echos 'nonce' if a cookie is found that matches, null otherwise. - /// Examine of that start with the prefix: 'OpenIdConnectAuthenticationDefaults.Nonce'. + /// Examine of that start with the prefix: 'OpenIdConnectAuthenticationDefaults.Nonce'. /// of is used to obtain the actual 'nonce'. If the nonce is found, then of is called. private string ReadNonceCookie(string nonce) { @@ -919,19 +937,14 @@ private string ReadNonceCookie(string nonce) foreach (var nonceKey in Request.Cookies.Keys) { - if (nonceKey.StartsWith(OpenIdConnectDefaults.CookieNoncePrefix)) + if (nonceKey.StartsWith(Options.NonceCookie.Name)) { try { - var nonceDecodedValue = Options.StringDataFormat.Unprotect(nonceKey.Substring(OpenIdConnectDefaults.CookieNoncePrefix.Length, nonceKey.Length - OpenIdConnectDefaults.CookieNoncePrefix.Length)); + var nonceDecodedValue = Options.StringDataFormat.Unprotect(nonceKey.Substring(Options.NonceCookie.Name.Length, nonceKey.Length - Options.NonceCookie.Name.Length)); if (nonceDecodedValue == nonce) { - var cookieOptions = new CookieOptions - { - HttpOnly = true, - Secure = Request.IsHttps - }; - + var cookieOptions = Options.NonceCookie.Build(Context, Clock.UtcNow); Response.Cookies.Delete(nonceKey, cookieOptions); return nonce; } @@ -979,51 +992,54 @@ private AuthenticationProperties GetPropertiesFromState(string state) private async Task RunMessageReceivedEventAsync(OpenIdConnectMessage message, AuthenticationProperties properties) { Logger.MessageReceived(message.BuildRedirectUrl()); - var messageReceivedContext = new MessageReceivedContext(Context, Options) + var context = new MessageReceivedContext(Context, Scheme, Options, properties) { ProtocolMessage = message, - Properties = properties, }; - await Options.Events.MessageReceived(messageReceivedContext); - if (messageReceivedContext.HandledResponse) + await Events.MessageReceived(context); + if (context.Result != null) { - Logger.MessageReceivedContextHandledResponse(); - } - else if (messageReceivedContext.Skipped) - { - Logger.MessageReceivedContextSkipped(); + if (context.Result.Handled) + { + Logger.MessageReceivedContextHandledResponse(); + } + else if (context.Result.Skipped) + { + Logger.MessageReceivedContextSkipped(); + } } - return messageReceivedContext; + return context; } - private async Task RunTokenValidatedEventAsync(OpenIdConnectMessage authorizationResponse, OpenIdConnectMessage tokenEndpointResponse, AuthenticationProperties properties, AuthenticationTicket ticket, JwtSecurityToken jwt, string nonce) + private async Task RunTokenValidatedEventAsync(OpenIdConnectMessage authorizationResponse, OpenIdConnectMessage tokenEndpointResponse, ClaimsPrincipal user, AuthenticationProperties properties, JwtSecurityToken jwt, string nonce) { - var tokenValidatedContext = new TokenValidatedContext(Context, Options) + var context = new TokenValidatedContext(Context, Scheme, Options, user, properties) { ProtocolMessage = authorizationResponse, TokenEndpointResponse = tokenEndpointResponse, - Properties = properties, - Ticket = ticket, SecurityToken = jwt, Nonce = nonce, }; - await Options.Events.TokenValidated(tokenValidatedContext); - if (tokenValidatedContext.HandledResponse) + await Events.TokenValidated(context); + if (context.Result != null) { - Logger.TokenValidatedHandledResponse(); - } - else if (tokenValidatedContext.Skipped) - { - Logger.TokenValidatedSkipped(); + if (context.Result.Handled) + { + Logger.TokenValidatedHandledResponse(); + } + else if (context.Result.Skipped) + { + Logger.TokenValidatedSkipped(); + } } - return tokenValidatedContext; + return context; } - private async Task RunAuthorizationCodeReceivedEventAsync(OpenIdConnectMessage authorizationResponse, AuthenticationProperties properties, AuthenticationTicket ticket, JwtSecurityToken jwt) + private async Task RunAuthorizationCodeReceivedEventAsync(OpenIdConnectMessage authorizationResponse, ClaimsPrincipal user, AuthenticationProperties properties, JwtSecurityToken jwt) { Logger.AuthorizationCodeReceived(); @@ -1033,105 +1049,116 @@ private async Task RunAuthorizationCodeReceive ClientSecret = Options.ClientSecret, Code = authorizationResponse.Code, GrantType = OpenIdConnectGrantTypes.AuthorizationCode, + EnableTelemetryParameters = !Options.DisableTelemetry, RedirectUri = properties.Items[OpenIdConnectDefaults.RedirectUriForCodePropertiesKey] }; - var authorizationCodeReceivedContext = new AuthorizationCodeReceivedContext(Context, Options) + var context = new AuthorizationCodeReceivedContext(Context, Scheme, Options, properties) { ProtocolMessage = authorizationResponse, - Properties = properties, TokenEndpointRequest = tokenEndpointRequest, - Ticket = ticket, + Principal = user, JwtSecurityToken = jwt, - Backchannel = Backchannel, + Backchannel = Backchannel }; - await Options.Events.AuthorizationCodeReceived(authorizationCodeReceivedContext); - if (authorizationCodeReceivedContext.HandledResponse) - { - Logger.AuthorizationCodeReceivedContextHandledResponse(); - } - else if (authorizationCodeReceivedContext.Skipped) + await Events.AuthorizationCodeReceived(context); + if (context.Result != null) { - Logger.AuthorizationCodeReceivedContextSkipped(); + if (context.Result.Handled) + { + Logger.AuthorizationCodeReceivedContextHandledResponse(); + } + else if (context.Result.Skipped) + { + Logger.AuthorizationCodeReceivedContextSkipped(); + } } - return authorizationCodeReceivedContext; + return context; } private async Task RunTokenResponseReceivedEventAsync( OpenIdConnectMessage message, OpenIdConnectMessage tokenEndpointResponse, - AuthenticationProperties properties, - AuthenticationTicket ticket) + ClaimsPrincipal user, + AuthenticationProperties properties) { Logger.TokenResponseReceived(); - var eventContext = new TokenResponseReceivedContext(Context, Options, properties) + var context = new TokenResponseReceivedContext(Context, Scheme, Options, user, properties) { ProtocolMessage = message, TokenEndpointResponse = tokenEndpointResponse, - Ticket = ticket }; - await Options.Events.TokenResponseReceived(eventContext); - if (eventContext.HandledResponse) + await Events.TokenResponseReceived(context); + if (context.Result != null) { - Logger.TokenResponseReceivedHandledResponse(); - } - else if (eventContext.Skipped) - { - Logger.TokenResponseReceivedSkipped(); + if (context.Result.Handled) + { + Logger.TokenResponseReceivedHandledResponse(); + } + else if (context.Result.Skipped) + { + Logger.TokenResponseReceivedSkipped(); + } } - return eventContext; + return context; } - private async Task RunUserInformationReceivedEventAsync(AuthenticationTicket ticket, OpenIdConnectMessage message, JObject user) + private async Task RunUserInformationReceivedEventAsync(ClaimsPrincipal principal, AuthenticationProperties properties, OpenIdConnectMessage message, JObject user) { Logger.UserInformationReceived(user.ToString()); - var userInformationReceivedContext = new UserInformationReceivedContext(Context, Options) + var context = new UserInformationReceivedContext(Context, Scheme, Options, principal, properties) { - Ticket = ticket, ProtocolMessage = message, User = user, }; - await Options.Events.UserInformationReceived(userInformationReceivedContext); - if (userInformationReceivedContext.HandledResponse) - { - Logger.UserInformationReceivedHandledResponse(); - } - else if (userInformationReceivedContext.Skipped) + await Events.UserInformationReceived(context); + if (context.Result != null) { - Logger.UserInformationReceivedSkipped(); + if (context.Result.Handled) + { + Logger.UserInformationReceivedHandledResponse(); + } + else if (context.Result.Skipped) + { + Logger.UserInformationReceivedSkipped(); + } } - return userInformationReceivedContext; + return context; } private async Task RunAuthenticationFailedEventAsync(OpenIdConnectMessage message, Exception exception) { - var authenticationFailedContext = new AuthenticationFailedContext(Context, Options) + var context = new AuthenticationFailedContext(Context, Scheme, Options) { ProtocolMessage = message, Exception = exception }; - await Options.Events.AuthenticationFailed(authenticationFailedContext); - if (authenticationFailedContext.HandledResponse) - { - Logger.AuthenticationFailedContextHandledResponse(); - } - else if (authenticationFailedContext.Skipped) + await Events.AuthenticationFailed(context); + if (context.Result != null) { - Logger.AuthenticationFailedContextSkipped(); + if (context.Result.Handled) + { + Logger.AuthenticationFailedContextHandledResponse(); + } + else if (context.Result.Skipped) + { + Logger.AuthenticationFailedContextSkipped(); + } } - return authenticationFailedContext; + return context; } - private AuthenticationTicket ValidateToken(string idToken, AuthenticationProperties properties, TokenValidationParameters validationParameters, out JwtSecurityToken jwt) + // Note this modifies properties if Options.UseTokenLifetime + private ClaimsPrincipal ValidateToken(string idToken, AuthenticationProperties properties, TokenValidationParameters validationParameters, out JwtSecurityToken jwt) { if (!Options.SecurityTokenValidator.CanReadToken(idToken)) { @@ -1141,20 +1168,14 @@ private AuthenticationTicket ValidateToken(string idToken, AuthenticationPropert if (_configuration != null) { - if (string.IsNullOrEmpty(validationParameters.ValidIssuer)) - { - validationParameters.ValidIssuer = _configuration.Issuer; - } - else if (!string.IsNullOrEmpty(_configuration.Issuer)) - { - validationParameters.ValidIssuers = validationParameters.ValidIssuers?.Concat(new[] { _configuration.Issuer }) ?? new[] { _configuration.Issuer }; - } + var issuer = new[] { _configuration.Issuer }; + validationParameters.ValidIssuers = validationParameters.ValidIssuers?.Concat(issuer) ?? issuer; - validationParameters.IssuerSigningKeys = validationParameters.IssuerSigningKeys?.Concat(_configuration.SigningKeys) ?? _configuration.SigningKeys; + validationParameters.IssuerSigningKeys = validationParameters.IssuerSigningKeys?.Concat(_configuration.SigningKeys) + ?? _configuration.SigningKeys; } - SecurityToken validatedToken = null; - var principal = Options.SecurityTokenValidator.ValidateToken(idToken, validationParameters, out validatedToken); + var principal = Options.SecurityTokenValidator.ValidateToken(idToken, validationParameters, out SecurityToken validatedToken); jwt = validatedToken as JwtSecurityToken; if (jwt == null) { @@ -1168,24 +1189,22 @@ private AuthenticationTicket ValidateToken(string idToken, AuthenticationPropert throw new SecurityTokenException(string.Format(CultureInfo.InvariantCulture, Resources.UnableToValidateToken, idToken)); } - var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme); - if (Options.UseTokenLifetime) { var issued = validatedToken.ValidFrom; if (issued != DateTime.MinValue) { - ticket.Properties.IssuedUtc = issued; + properties.IssuedUtc = issued; } var expires = validatedToken.ValidTo; if (expires != DateTime.MinValue) { - ticket.Properties.ExpiresUtc = expires; + properties.ExpiresUtc = expires; } } - return ticket; + return principal; } /// diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectMiddleware.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectMiddleware.cs deleted file mode 100644 index 8d880d0d9..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectMiddleware.cs +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Net.Http; -using System.Text; -using System.Text.Encodings.Web; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.DataProtection; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Microsoft.IdentityModel.Protocols; -using Microsoft.IdentityModel.Protocols.OpenIdConnect; - -namespace Microsoft.AspNetCore.Authentication.OpenIdConnect -{ - /// - /// ASP.NET Core middleware for obtaining identities using OpenIdConnect protocol. - /// - public class OpenIdConnectMiddleware : AuthenticationMiddleware - { - /// - /// Initializes a - /// - /// The next middleware in the middleware pipeline to invoke. - /// provider for creating a data protector. - /// factory for creating a . - /// - /// - /// - /// - /// The . - public OpenIdConnectMiddleware( - RequestDelegate next, - IDataProtectionProvider dataProtectionProvider, - ILoggerFactory loggerFactory, - UrlEncoder encoder, - IServiceProvider services, - IOptions sharedOptions, - IOptions options, - HtmlEncoder htmlEncoder) - : base(next, options, loggerFactory, encoder) - { - if (next == null) - { - throw new ArgumentNullException(nameof(next)); - } - - if (dataProtectionProvider == null) - { - throw new ArgumentNullException(nameof(dataProtectionProvider)); - } - - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - if (encoder == null) - { - throw new ArgumentNullException(nameof(encoder)); - } - - if (services == null) - { - throw new ArgumentNullException(nameof(services)); - } - - if (sharedOptions == null) - { - throw new ArgumentNullException(nameof(sharedOptions)); - } - - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - if (htmlEncoder == null) - { - throw new ArgumentNullException(nameof(htmlEncoder)); - } - - if (string.IsNullOrEmpty(Options.ClientId)) - { - throw new ArgumentException("Options.ClientId must be provided", nameof(Options.ClientId)); - } - - if (!Options.CallbackPath.HasValue) - { - throw new ArgumentException("Options.CallbackPath must be provided."); - } - - if (string.IsNullOrEmpty(Options.SignInScheme)) - { - Options.SignInScheme = sharedOptions.Value.SignInScheme; - } - if (string.IsNullOrEmpty(Options.SignInScheme)) - { - throw new ArgumentException("Options.SignInScheme is required."); - } - if (string.IsNullOrEmpty(Options.SignOutScheme)) - { - Options.SignOutScheme = Options.SignInScheme; - } - - HtmlEncoder = htmlEncoder; - - if (Options.StateDataFormat == null) - { - var dataProtector = dataProtectionProvider.CreateProtector( - typeof(OpenIdConnectMiddleware).FullName, - typeof(string).FullName, - Options.AuthenticationScheme, - "v1"); - - Options.StateDataFormat = new PropertiesDataFormat(dataProtector); - } - - if (Options.StringDataFormat == null) - { - var dataProtector = dataProtectionProvider.CreateProtector( - typeof(OpenIdConnectMiddleware).FullName, - typeof(string).FullName, - Options.AuthenticationScheme, - "v1"); - - Options.StringDataFormat = new SecureDataFormat(new StringSerializer(), dataProtector); - } - - if (Options.Events == null) - { - Options.Events = new OpenIdConnectEvents(); - } - - if (string.IsNullOrEmpty(Options.TokenValidationParameters.ValidAudience) && !string.IsNullOrEmpty(Options.ClientId)) - { - Options.TokenValidationParameters.ValidAudience = Options.ClientId; - } - - Backchannel = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler()); - Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OpenIdConnect middleware"); - Backchannel.Timeout = Options.BackchannelTimeout; - Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB - - if (Options.ConfigurationManager == null) - { - if (Options.Configuration != null) - { - Options.ConfigurationManager = new StaticConfigurationManager(Options.Configuration); - } - else if (!(string.IsNullOrEmpty(Options.MetadataAddress) && string.IsNullOrEmpty(Options.Authority))) - { - if (string.IsNullOrEmpty(Options.MetadataAddress) && !string.IsNullOrEmpty(Options.Authority)) - { - Options.MetadataAddress = Options.Authority; - if (!Options.MetadataAddress.EndsWith("/", StringComparison.Ordinal)) - { - Options.MetadataAddress += "/"; - } - - Options.MetadataAddress += ".well-known/openid-configuration"; - } - - if (Options.RequireHttpsMetadata && !Options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidOperationException("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false."); - } - - Options.ConfigurationManager = new ConfigurationManager(Options.MetadataAddress, new OpenIdConnectConfigurationRetriever(), - new HttpDocumentRetriever(Backchannel) { RequireHttps = Options.RequireHttpsMetadata }); - } - } - - if (Options.ConfigurationManager == null) - { - throw new InvalidOperationException($"Provide {nameof(Options.Authority)}, {nameof(Options.MetadataAddress)}, " - + $"{nameof(Options.Configuration)}, or {nameof(Options.ConfigurationManager)} to {nameof(OpenIdConnectOptions)}"); - } - } - - protected HttpClient Backchannel { get; private set; } - - protected HtmlEncoder HtmlEncoder { get; private set; } - - /// - /// Provides the object for processing authentication-related requests. - /// - /// An configured with the supplied to the constructor. - protected override AuthenticationHandler CreateHandler() - { - return new OpenIdConnectHandler(Backchannel, HtmlEncoder); - } - - private class StringSerializer : IDataSerializer - { - public string Deserialize(byte[] data) - { - return Encoding.UTF8.GetString(data); - } - - public byte[] Serialize(string model) - { - return Encoding.UTF8.GetBytes(model); - } - } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectOptions.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectOptions.cs index f0b26f75b..cbf6e8eab 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectOptions.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectOptions.cs @@ -4,28 +4,21 @@ using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.AspNetCore.Authentication.Internal; +using Microsoft.AspNetCore.Authentication.OAuth.Claims; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; using Microsoft.IdentityModel.Protocols; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Tokens; -namespace Microsoft.AspNetCore.Builder +namespace Microsoft.AspNetCore.Authentication.OpenIdConnect { /// - /// Configuration options for + /// Configuration options for /// public class OpenIdConnectOptions : RemoteAuthenticationOptions { - /// - /// Initializes a new - /// - public OpenIdConnectOptions() - : this(OpenIdConnectDefaults.AuthenticationScheme) - { - } + private CookieBuilder _nonceCookieBuilder; /// /// Initializes a new @@ -34,7 +27,6 @@ public OpenIdConnectOptions() /// Defaults: /// AddNonceToRequest: true. /// BackchannelTimeout: 1 minute. - /// Caption: . /// ProtocolValidator: new . /// RefreshOnIssuerKeyNotFound: true /// ResponseType: @@ -42,12 +34,8 @@ public OpenIdConnectOptions() /// TokenValidationParameters: new with AuthenticationScheme = authenticationScheme. /// UseTokenLifetime: false. /// - /// will be used to when creating the for the AuthenticationScheme property. - public OpenIdConnectOptions(string authenticationScheme) + public OpenIdConnectOptions() { - AuthenticationScheme = authenticationScheme; - AutomaticChallenge = true; - DisplayName = OpenIdConnectDefaults.Caption; CallbackPath = new PathString("/signin-oidc"); SignedOutCallbackPath = new PathString("/signout-callback-oidc"); RemoteSignOutPath = new PathString("/signout-oidc"); @@ -55,6 +43,68 @@ public OpenIdConnectOptions(string authenticationScheme) Events = new OpenIdConnectEvents(); Scope.Add("openid"); Scope.Add("profile"); + + ClaimActions.DeleteClaim("nonce"); + ClaimActions.DeleteClaim("aud"); + ClaimActions.DeleteClaim("azp"); + ClaimActions.DeleteClaim("acr"); + ClaimActions.DeleteClaim("amr"); + ClaimActions.DeleteClaim("iss"); + ClaimActions.DeleteClaim("iat"); + ClaimActions.DeleteClaim("nbf"); + ClaimActions.DeleteClaim("exp"); + ClaimActions.DeleteClaim("at_hash"); + ClaimActions.DeleteClaim("c_hash"); + ClaimActions.DeleteClaim("auth_time"); + ClaimActions.DeleteClaim("ipaddr"); + ClaimActions.DeleteClaim("platf"); + ClaimActions.DeleteClaim("ver"); + + // http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims + ClaimActions.MapUniqueJsonKey("sub", "sub"); + ClaimActions.MapUniqueJsonKey("name", "name"); + ClaimActions.MapUniqueJsonKey("given_name", "given_name"); + ClaimActions.MapUniqueJsonKey("family_name", "family_name"); + ClaimActions.MapUniqueJsonKey("profile", "profile"); + ClaimActions.MapUniqueJsonKey("email", "email"); + + _nonceCookieBuilder = new OpenIdConnectNonceCookieBuilder(this) + { + Name = OpenIdConnectDefaults.CookieNoncePrefix, + HttpOnly = true, + SameSite = SameSiteMode.None, + SecurePolicy = CookieSecurePolicy.SameAsRequest, + IsEssential = true, + }; + } + + /// + /// Check that the options are valid. Should throw an exception if things are not ok. + /// + public override void Validate() + { + base.Validate(); + + if (MaxAge.HasValue && MaxAge.Value < TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException(nameof(MaxAge), MaxAge.Value, "The value must not be a negative TimeSpan."); + } + + if (string.IsNullOrEmpty(ClientId)) + { + throw new ArgumentException("Options.ClientId must be provided", nameof(ClientId)); + } + + if (!CallbackPath.HasValue) + { + throw new ArgumentException("Options.CallbackPath must be provided.", nameof(CallbackPath)); + } + + if (ConfigurationManager == null) + { + throw new InvalidOperationException($"Provide {nameof(Authority)}, {nameof(MetadataAddress)}, " + + $"{nameof(Configuration)}, or {nameof(ConfigurationManager)} to {nameof(OpenIdConnectOptions)}"); + } } /// @@ -85,11 +135,16 @@ public OpenIdConnectOptions(string authenticationScheme) public IConfigurationManager ConfigurationManager { get; set; } /// - /// Boolean to set whether the middleware should go to user info endpoint to retrieve additional claims or not after creating an identity from id_token received from token endpoint. + /// Boolean to set whether the handler should go to user info endpoint to retrieve additional claims or not after creating an identity from id_token received from token endpoint. /// The default is 'false'. /// public bool GetClaimsFromUserInfoEndpoint { get; set; } + /// + /// A collection of claim actions used to select values from the json user data and create Claims. + /// + public ClaimActionCollection ClaimActions { get; } = new ClaimActionCollection(); + /// /// Gets or sets if HTTPS is required for the metadata address or authority. /// The default is true. This should be disabled only in development environments. @@ -102,17 +157,24 @@ public OpenIdConnectOptions(string authenticationScheme) public string MetadataAddress { get; set; } /// - /// Gets or sets the to notify when processing OpenIdConnect messages. + /// Gets or sets the to notify when processing OpenIdConnect messages. /// - public new IOpenIdConnectEvents Events + public new OpenIdConnectEvents Events { - get { return (IOpenIdConnectEvents)base.Events; } - set { base.Events = value; } + get => (OpenIdConnectEvents)base.Events; + set => base.Events = value; } + /// + /// Gets or sets the 'max_age'. If set the 'max_age' parameter will be sent with the authentication request. If the identity + /// provider has not actively authenticated the user within the length of time specified, the user will be prompted to + /// re-authenticate. By default no max_age is specified. + /// + public TimeSpan? MaxAge { get; set; } + /// /// Gets or sets the that is used to ensure that the 'id_token' received - /// is valid per: http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation + /// is valid per: http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation /// /// if 'value' is null. public OpenIdConnectProtocolValidator ProtocolValidator { get; set; } = new OpenIdConnectProtocolValidator() @@ -123,15 +185,16 @@ public OpenIdConnectOptions(string authenticationScheme) /// /// The request path within the application's base path where the user agent will be returned after sign out from the identity provider. + /// See post_logout_redirect_uri from http://openid.net/specs/openid-connect-session-1_0.html#RedirectionAfterLogout. /// public PathString SignedOutCallbackPath { get; set; } /// - /// The uri where the user agent will be returned to after application is signed out from the identity provider. + /// The uri where the user agent will be redirected to after application is signed out from the identity provider. /// The redirect will happen after the SignedOutCallbackPath is invoked. /// /// This URI can be out of the application's domain. By default it points to the root. - public string PostLogoutRedirectUri { get; set; } = "/"; + public string SignedOutRedirectUri { get; set; } = "/"; /// /// Gets or sets if a metadata refresh should be attempted after a SecurityTokenSignatureKeyNotFoundException. This allows for automatic @@ -159,13 +222,18 @@ public OpenIdConnectOptions(string authenticationScheme) /// public string ResponseType { get; set; } = OpenIdConnectResponseType.IdToken; + /// + /// Gets or sets the 'prompt'. + /// + public string Prompt { get; set; } + /// /// Gets the list of permissions to request. /// public ICollection Scope { get; } = new HashSet(); /// - /// Requests received on this path will cause the middleware to invoke SignOut using the SignInScheme. + /// Requests received on this path will cause the handler to invoke SignOut using the SignInScheme. /// public PathString RemoteSignOutPath { get; set; } @@ -176,12 +244,12 @@ public OpenIdConnectOptions(string authenticationScheme) public string SignOutScheme { get; set; } /// - /// Gets or sets the type used to secure data handled by the middleware. + /// Gets or sets the type used to secure data handled by the handler. /// public ISecureDataFormat StateDataFormat { get; set; } /// - /// Gets or sets the type used to secure strings used by the middleware. + /// Gets or sets the type used to secure strings used by the handler. /// public ISecureDataFormat StringDataFormat { get; set; } @@ -204,11 +272,55 @@ public OpenIdConnectOptions(string authenticationScheme) public bool UseTokenLifetime { get; set; } /// - /// Indicates if requests to the CallbackPath may also be for other components. If enabled the middleware will pass + /// Indicates if requests to the CallbackPath may also be for other components. If enabled the handler will pass /// requests through that do not contain OpenIdConnect authentication responses. Disabling this and setting the /// CallbackPath to a dedicated endpoint may provide better error handling. /// This is disabled by default. /// public bool SkipUnrecognizedRequests { get; set; } = false; + + /// + /// Indicates whether telemetry should be disabled. When this feature is enabled, + /// the assembly version of the Microsoft IdentityModel packages is sent to the + /// remote OpenID Connect provider as an authorization/logout request parameter. + /// + public bool DisableTelemetry { get; set; } + + /// + /// Determines the settings used to create the nonce cookie before the + /// cookie gets added to the response. + /// + /// + /// The value of is treated as the prefix to the cookie name, and defaults to . + /// + public CookieBuilder NonceCookie + { + get => _nonceCookieBuilder; + set => _nonceCookieBuilder = value ?? throw new ArgumentNullException(nameof(value)); + } + + private class OpenIdConnectNonceCookieBuilder : RequestPathBaseCookieBuilder + { + private readonly OpenIdConnectOptions _options; + + public OpenIdConnectNonceCookieBuilder(OpenIdConnectOptions oidcOptions) + { + _options = oidcOptions; + } + + protected override string AdditionalPath => _options.CallbackPath; + + public override CookieOptions Build(HttpContext context, DateTimeOffset expiresFrom) + { + var cookieOptions = base.Build(context, expiresFrom); + + if (!Expiration.HasValue || !cookieOptions.Expires.HasValue) + { + cookieOptions.Expires = expiresFrom.Add(_options.ProtocolValidator.NonceLifetime); + } + + return cookieOptions; + } + } } } diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectPostConfigureOptions.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectPostConfigureOptions.cs new file mode 100644 index 000000000..b79f1d1ed --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/OpenIdConnectPostConfigureOptions.cs @@ -0,0 +1,114 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Net.Http; +using System.Text; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Protocols; +using Microsoft.IdentityModel.Protocols.OpenIdConnect; + +namespace Microsoft.AspNetCore.Authentication.OpenIdConnect +{ + /// + /// Used to setup defaults for all . + /// + public class OpenIdConnectPostConfigureOptions : IPostConfigureOptions + { + private readonly IDataProtectionProvider _dp; + + public OpenIdConnectPostConfigureOptions(IDataProtectionProvider dataProtection) + { + _dp = dataProtection; + } + + /// + /// Invoked to post configure a TOptions instance. + /// + /// The name of the options instance being configured. + /// The options instance to configure. + public void PostConfigure(string name, OpenIdConnectOptions options) + { + options.DataProtectionProvider = options.DataProtectionProvider ?? _dp; + + if (string.IsNullOrEmpty(options.SignOutScheme)) + { + options.SignOutScheme = options.SignInScheme; + } + + if (options.StateDataFormat == null) + { + var dataProtector = options.DataProtectionProvider.CreateProtector( + typeof(OpenIdConnectHandler).FullName, name, "v1"); + options.StateDataFormat = new PropertiesDataFormat(dataProtector); + } + + if (options.StringDataFormat == null) + { + var dataProtector = options.DataProtectionProvider.CreateProtector( + typeof(OpenIdConnectHandler).FullName, + typeof(string).FullName, + name, + "v1"); + + options.StringDataFormat = new SecureDataFormat(new StringSerializer(), dataProtector); + } + + if (string.IsNullOrEmpty(options.TokenValidationParameters.ValidAudience) && !string.IsNullOrEmpty(options.ClientId)) + { + options.TokenValidationParameters.ValidAudience = options.ClientId; + } + + if (options.Backchannel == null) + { + options.Backchannel = new HttpClient(options.BackchannelHttpHandler ?? new HttpClientHandler()); + options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OpenIdConnect handler"); + options.Backchannel.Timeout = options.BackchannelTimeout; + options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB + } + + if (options.ConfigurationManager == null) + { + if (options.Configuration != null) + { + options.ConfigurationManager = new StaticConfigurationManager(options.Configuration); + } + else if (!(string.IsNullOrEmpty(options.MetadataAddress) && string.IsNullOrEmpty(options.Authority))) + { + if (string.IsNullOrEmpty(options.MetadataAddress) && !string.IsNullOrEmpty(options.Authority)) + { + options.MetadataAddress = options.Authority; + if (!options.MetadataAddress.EndsWith("/", StringComparison.Ordinal)) + { + options.MetadataAddress += "/"; + } + + options.MetadataAddress += ".well-known/openid-configuration"; + } + + if (options.RequireHttpsMetadata && !options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false."); + } + + options.ConfigurationManager = new ConfigurationManager(options.MetadataAddress, new OpenIdConnectConfigurationRetriever(), + new HttpDocumentRetriever(options.Backchannel) { RequireHttps = options.RequireHttpsMetadata }); + } + } + } + + private class StringSerializer : IDataSerializer + { + public string Deserialize(byte[] data) + { + return Encoding.UTF8.GetString(data); + } + + public byte[] Serialize(string model) + { + return Encoding.UTF8.GetBytes(model); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Properties/Resources.Designer.cs index 65a9273a0..753373ece 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Properties/Resources.Designer.cs @@ -15,96 +15,84 @@ private static readonly ResourceManager _resourceManager /// internal static string MessageStateIsNullOrEmpty { - get { return GetString("MessageStateIsNullOrEmpty"); } + get => GetString("MessageStateIsNullOrEmpty"); } /// /// OpenIdConnectAuthenticationHandler: message.State is null or empty. /// internal static string FormatMessageStateIsNullOrEmpty() - { - return GetString("MessageStateIsNullOrEmpty"); - } + => GetString("MessageStateIsNullOrEmpty"); /// /// Unable to unprotect the message.State. /// internal static string MessageStateIsInvalid { - get { return GetString("MessageStateIsInvalid"); } + get => GetString("MessageStateIsInvalid"); } /// /// Unable to unprotect the message.State. /// internal static string FormatMessageStateIsInvalid() - { - return GetString("MessageStateIsInvalid"); - } + => GetString("MessageStateIsInvalid"); /// /// Message contains error: '{0}', error_description: '{1}', error_uri: '{2}'. /// internal static string MessageContainsError { - get { return GetString("MessageContainsError"); } + get => GetString("MessageContainsError"); } /// /// Message contains error: '{0}', error_description: '{1}', error_uri: '{2}'. /// internal static string FormatMessageContainsError(object p0, object p1, object p2) - { - return string.Format(CultureInfo.CurrentCulture, GetString("MessageContainsError"), p0, p1, p2); - } + => string.Format(CultureInfo.CurrentCulture, GetString("MessageContainsError"), p0, p1, p2); /// /// The Validated Security Token must be of type JwtSecurityToken, but instead its type is: '{0}'. /// internal static string ValidatedSecurityTokenNotJwt { - get { return GetString("ValidatedSecurityTokenNotJwt"); } + get => GetString("ValidatedSecurityTokenNotJwt"); } /// /// The Validated Security Token must be of type JwtSecurityToken, but instead its type is: '{0}'. /// internal static string FormatValidatedSecurityTokenNotJwt(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("ValidatedSecurityTokenNotJwt"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("ValidatedSecurityTokenNotJwt"), p0); /// /// Unable to validate the 'id_token', no suitable ISecurityTokenValidator was found for: '{0}'." /// internal static string UnableToValidateToken { - get { return GetString("UnableToValidateToken"); } + get => GetString("UnableToValidateToken"); } /// /// Unable to validate the 'id_token', no suitable ISecurityTokenValidator was found for: '{0}'." /// internal static string FormatUnableToValidateToken(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("UnableToValidateToken"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("UnableToValidateToken"), p0); /// /// Cannot process the message. Both id_token and code are missing. /// internal static string IdTokenCodeMissing { - get { return GetString("IdTokenCodeMissing"); } + get => GetString("IdTokenCodeMissing"); } /// /// Cannot process the message. Both id_token and code are missing. /// internal static string FormatIdTokenCodeMissing() - { - return GetString("IdTokenCodeMissing"); - } + => GetString("IdTokenCodeMissing"); private static string GetString(string name, params string[] formatterNames) { diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Utility/ClaimsHelper.cs b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Utility/ClaimsHelper.cs deleted file mode 100644 index 78eea68bf..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/Utility/ClaimsHelper.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; -using Newtonsoft.Json.Linq; - -namespace Microsoft.AspNetCore.Authentication.OpenIdConnect -{ - internal static class ClaimsHelper - { - public static void AddClaimsToIdentity( - JObject userInformationPayload, - ClaimsIdentity identity, - string issuer) - { - foreach (var pair in userInformationPayload) - { - var array = pair.Value as JArray; - if (array != null) - { - foreach (var item in array) - { - AddClaimsToIdentity(item, identity, pair.Key, issuer); - } - } - else - { - AddClaimsToIdentity(pair.Value, identity, pair.Key, issuer); - } - } - } - - private static void AddClaimsToIdentity(JToken item, ClaimsIdentity identity, string key, string issuer) - => identity.AddClaim(new Claim(key, item?.ToString() ?? string.Empty, GetClaimValueType(item), issuer)); - - private static string GetClaimValueType(JToken token) - { - if (token == null) - { - return JsonClaimValueTypes.JsonNull; - } - - switch (token.Type) - { - case JTokenType.Array: - return JsonClaimValueTypes.JsonArray; - - case JTokenType.Boolean: - return ClaimValueTypes.Boolean; - - case JTokenType.Date: - return ClaimValueTypes.DateTime; - - case JTokenType.Float: - return ClaimValueTypes.Double; - - case JTokenType.Integer: - { - var value = (long) token; - if (value >= int.MinValue && value <= int.MaxValue) - { - return ClaimValueTypes.Integer; - } - - return ClaimValueTypes.Integer64; - } - - case JTokenType.Object: - return JsonClaimValueTypes.Json; - - case JTokenType.String: - return ClaimValueTypes.String; - } - - // Fall back to ClaimValueTypes.String when no appropriate - // claim value type can be inferred from the claim value. - return ClaimValueTypes.String; - } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/baseline.net45.json b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/baseline.net45.json deleted file mode 100644 index 64cb79487..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/baseline.net45.json +++ /dev/null @@ -1,2005 +0,0 @@ -{ - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.OpenIdConnect, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", - "Types": [ - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectDefaults", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "AuthenticationPropertiesKey", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "ReadOnly": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Field", - "Name": "Caption", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "ReadOnly": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Field", - "Name": "CookieNoncePrefix", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "ReadOnly": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Field", - "Name": "RedirectUriForCodePropertiesKey", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "ReadOnly": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Field", - "Name": "UserstatePropertiesKey", - "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": "\"OpenIdConnect\"" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Backchannel", - "Parameters": [], - "ReturnType": "System.Net.Http.HttpClient", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_HtmlEncoder", - "Parameters": [], - "ReturnType": "System.Text.Encodings.Web.HtmlEncoder", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleRequestAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleRemoteSignOutAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleSignOutAsync", - "Parameters": [ - { - "Name": "signout", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignOutContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleUnauthorizedAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleRemoteAuthenticateAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedeemAuthorizationCodeAsync", - "Parameters": [ - { - "Name": "tokenEndpointRequest", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetUserInformationAsync", - "Parameters": [ - { - "Name": "message", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" - }, - { - "Name": "jwt", - "Type": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken" - }, - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "backchannel", - "Type": "System.Net.Http.HttpClient" - }, - { - "Name": "htmlEncoder", - "Type": "System.Text.Encodings.Web.HtmlEncoder" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectMiddleware", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Backchannel", - "Parameters": [], - "ReturnType": "System.Net.Http.HttpClient", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_HtmlEncoder", - "Parameters": [], - "ReturnType": "System.Text.Encodings.Web.HtmlEncoder", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "CreateHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" - }, - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" - }, - { - "Name": "services", - "Type": "System.IServiceProvider" - }, - { - "Name": "sharedOptions", - "Type": "Microsoft.Extensions.Options.IOptions" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" - }, - { - "Name": "htmlEncoder", - "Type": "System.Text.Encodings.Web.HtmlEncoder" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectRedirectBehavior", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "RedirectGet", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "FormPost", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.AuthenticationFailedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Exception", - "Parameters": [], - "ReturnType": "System.Exception", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Exception", - "Parameters": [ - { - "Name": "value", - "Type": "System.Exception" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.AuthorizationCodeReceivedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Properties", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_JwtSecurityToken", - "Parameters": [], - "ReturnType": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_JwtSecurityToken", - "Parameters": [ - { - "Name": "value", - "Type": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_TokenEndpointRequest", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_TokenEndpointRequest", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Backchannel", - "Parameters": [], - "ReturnType": "System.Net.Http.HttpClient", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_TokenEndpointResponse", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_TokenEndpointResponse", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_HandledCodeRedemption", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleCodeRedemption", - "Parameters": [], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleCodeRedemption", - "Parameters": [ - { - "Name": "accessToken", - "Type": "System.String" - }, - { - "Name": "idToken", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleCodeRedemption", - "Parameters": [ - { - "Name": "tokenEndpointResponse", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseControlContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ProtocolMessage", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ProtocolMessage", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents" - ], - "Members": [ - { - "Kind": "Method", - "Name": "AuthenticationFailed", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.AuthenticationFailedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AuthorizationCodeReceived", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.AuthorizationCodeReceivedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "MessageReceived", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.MessageReceivedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToIdentityProvider", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RedirectContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToIdentityProviderForSignOut", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RedirectContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RemoteSignOut", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RemoteSignOutContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "TokenResponseReceived", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenResponseReceivedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "TokenValidated", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenValidatedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "UserInformationReceived", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.UserInformationReceivedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.MessageReceivedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Token", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Token", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Properties", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectEvents", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_OnAuthenticationFailed", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnAuthenticationFailed", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnAuthorizationCodeReceived", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnAuthorizationCodeReceived", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnMessageReceived", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnMessageReceived", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnRedirectToIdentityProvider", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnRedirectToIdentityProvider", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnRedirectToIdentityProviderForSignOut", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnRedirectToIdentityProviderForSignOut", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnRemoteSignOut", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnRemoteSignOut", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnTokenResponseReceived", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnTokenResponseReceived", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnTokenValidated", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnTokenValidated", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnUserInformationReceived", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnUserInformationReceived", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AuthenticationFailed", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.AuthenticationFailedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AuthorizationCodeReceived", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.AuthorizationCodeReceivedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "MessageReceived", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.MessageReceivedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToIdentityProvider", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RedirectContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToIdentityProviderForSignOut", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RedirectContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RemoteSignOut", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RemoteSignOutContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "TokenResponseReceived", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenResponseReceivedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "TokenValidated", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenValidatedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "UserInformationReceived", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.UserInformationReceivedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RedirectContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RemoteSignOutContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - }, - { - "Name": "message", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenResponseReceivedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_TokenEndpointResponse", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_TokenEndpointResponse", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenValidatedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Properties", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SecurityToken", - "Parameters": [], - "ReturnType": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SecurityToken", - "Parameters": [ - { - "Name": "value", - "Type": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_TokenEndpointResponse", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_TokenEndpointResponse", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Nonce", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Nonce", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.UserInformationReceivedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_User", - "Parameters": [], - "ReturnType": "Newtonsoft.Json.Linq.JObject", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_User", - "Parameters": [ - { - "Name": "value", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.OpenIdConnectAppBuilderExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "UseOpenIdConnectAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "UseOpenIdConnectAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Authority", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Authority", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ClientId", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ClientId", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ClientSecret", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ClientSecret", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Configuration", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfiguration", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Configuration", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfiguration" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ConfigurationManager", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.IConfigurationManager", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ConfigurationManager", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.IConfigurationManager" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_GetClaimsFromUserInfoEndpoint", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_GetClaimsFromUserInfoEndpoint", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_RequireHttpsMetadata", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_RequireHttpsMetadata", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_MetadataAddress", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_MetadataAddress", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Events", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Events", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ProtocolValidator", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolValidator", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ProtocolValidator", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolValidator" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_PostLogoutRedirectUri", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_PostLogoutRedirectUri", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_RefreshOnIssuerKeyNotFound", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_RefreshOnIssuerKeyNotFound", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AuthenticationMethod", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectRedirectBehavior", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_AuthenticationMethod", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectRedirectBehavior" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Resource", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Resource", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ResponseMode", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ResponseMode", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ResponseType", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ResponseType", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Scope", - "Parameters": [], - "ReturnType": "System.Collections.Generic.ICollection", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_RemoteSignOutPath", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_RemoteSignOutPath", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.PathString" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SignOutScheme", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SignOutScheme", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_StateDataFormat", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_StateDataFormat", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISecureDataFormat" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_StringDataFormat", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_StringDataFormat", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISecureDataFormat" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SecurityTokenValidator", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Tokens.ISecurityTokenValidator", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SecurityTokenValidator", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Tokens.ISecurityTokenValidator" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_TokenValidationParameters", - "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Tokens.TokenValidationParameters", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_TokenValidationParameters", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Tokens.TokenValidationParameters" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_UseTokenLifetime", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_UseTokenLifetime", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SkipUnrecognizedRequests", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SkipUnrecognizedRequests", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SystemClock", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISystemClock", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SystemClock", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "authenticationScheme", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - } - ], - "SourceFilters": [] -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/baseline.netcore.json b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/baseline.netcore.json index 64cb79487..d5c10d18d 100644 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/baseline.netcore.json @@ -1,8 +1,8 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.OpenIdConnect, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.OpenIdConnect, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectDefaults", + "Name": "Microsoft.Extensions.DependencyInjection.OpenIdConnectExtensions", "Visibility": "Public", "Kind": "Class", "Abstract": true, @@ -11,274 +11,436 @@ "ImplementedInterfaces": [], "Members": [ { - "Kind": "Field", - "Name": "AuthenticationPropertiesKey", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "AddOpenIdConnect", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, - "ReadOnly": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "Caption", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "AddOpenIdConnect", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, - "ReadOnly": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "CookieNoncePrefix", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "AddOpenIdConnect", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, - "ReadOnly": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "RedirectUriForCodePropertiesKey", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "AddOpenIdConnect", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, - "ReadOnly": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.OpenIdConnectAppBuilderExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ { - "Kind": "Field", - "Name": "UserstatePropertiesKey", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "UseOpenIdConnectAuthentication", + "Parameters": [ + { + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", "Static": true, - "ReadOnly": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "UseOpenIdConnectAuthentication", + "Parameters": [ + { + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", "Static": true, + "Extension": true, "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"OpenIdConnect\"" + "GenericParameter": [] } ], "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler", + "Name": "Microsoft.AspNetCore.Authentication.ClaimActionCollectionUniqueExtensions", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler", + "Abstract": true, + "Static": true, + "Sealed": true, "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_Backchannel", - "Parameters": [], - "ReturnType": "System.Net.Http.HttpClient", - "Visibility": "Protected", + "Name": "MapUniqueJsonKey", + "Parameters": [ + { + "Name": "collection", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection" + }, + { + "Name": "claimType", + "Type": "System.String" + }, + { + "Name": "jsonKey", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Static": true, + "Extension": true, + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_HtmlEncoder", + "Name": "MapUniqueJsonKey", + "Parameters": [ + { + "Name": "collection", + "Type": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection" + }, + { + "Name": "claimType", + "Type": "System.String" + }, + { + "Name": "jsonKey", + "Type": "System.String" + }, + { + "Name": "valueType", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.AuthenticationFailedContext", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_ProtocolMessage", "Parameters": [], - "ReturnType": "System.Text.Encodings.Web.HtmlEncoder", - "Visibility": "Protected", + "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "HandleRequestAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, + "Name": "set_ProtocolMessage", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" + } + ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "HandleRemoteSignOutAsync", + "Name": "get_Exception", "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", + "ReturnType": "System.Exception", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "HandleSignOutAsync", + "Name": "set_Exception", "Parameters": [ { - "Name": "signout", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignOutContext" + "Name": "value", + "Type": "System.Exception" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "HandleUnauthorizedAsync", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", + "Visibility": "Public", "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.AuthorizationCodeReceivedContext", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "HandleRemoteAuthenticateAsync", + "Name": "get_ProtocolMessage", "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", + "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RedeemAuthorizationCodeAsync", + "Name": "set_ProtocolMessage", "Parameters": [ { - "Name": "tokenEndpointRequest", + "Name": "value", "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetUserInformationAsync", + "Name": "get_JwtSecurityToken", + "Parameters": [], + "ReturnType": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_JwtSecurityToken", "Parameters": [ { - "Name": "message", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" - }, - { - "Name": "jwt", + "Name": "value", "Type": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken" - }, - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "get_TokenEndpointRequest", + "Parameters": [], + "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_TokenEndpointRequest", "Parameters": [ { - "Name": "backchannel", - "Type": "System.Net.Http.HttpClient" - }, - { - "Name": "htmlEncoder", - "Type": "System.Text.Encodings.Web.HtmlEncoder" + "Name": "value", + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" } ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectMiddleware", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Method", "Name": "get_Backchannel", "Parameters": [], "ReturnType": "System.Net.Http.HttpClient", - "Visibility": "Protected", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_HtmlEncoder", + "Name": "get_TokenEndpointResponse", "Parameters": [], - "ReturnType": "System.Text.Encodings.Web.HtmlEncoder", - "Visibility": "Protected", + "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "CreateHandler", + "Name": "set_TokenEndpointResponse", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_HandledCodeRedemption", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "Virtual": true, - "Override": true, - "Visibility": "Protected", + "ReturnType": "System.Boolean", + "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "HandleCodeRedemption", + "Parameters": [], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleCodeRedemption", "Parameters": [ { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" + "Name": "accessToken", + "Type": "System.String" }, { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, + "Name": "idToken", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleCodeRedemption", + "Parameters": [ { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" - }, + "Name": "tokenEndpointResponse", + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ { - "Name": "services", - "Type": "System.IServiceProvider" + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" }, { - "Name": "sharedOptions", - "Type": "Microsoft.Extensions.Options.IOptions" + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" }, { "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" + "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions" }, { - "Name": "htmlEncoder", - "Type": "System.Text.Encodings.Web.HtmlEncoder" + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], "Visibility": "Public", @@ -288,51 +450,48 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectRedirectBehavior", + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.MessageReceivedContext", "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", "ImplementedInterfaces": [], "Members": [ { - "Kind": "Field", - "Name": "RedirectGet", + "Kind": "Method", + "Name": "get_ProtocolMessage", "Parameters": [], - "GenericParameter": [], - "Literal": "0" + "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", + "Visibility": "Public", + "GenericParameter": [] }, { - "Kind": "Field", - "Name": "FormPost", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.AuthenticationFailedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "ImplementedInterfaces": [], - "Members": [ + "Kind": "Method", + "Name": "set_ProtocolMessage", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Method", - "Name": "get_Exception", + "Name": "get_Token", "Parameters": [], - "ReturnType": "System.Exception", + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Exception", + "Name": "set_Token", "Parameters": [ { "Name": "value", - "Type": "System.Exception" + "Type": "System.String" } ], "ReturnType": "System.Void", @@ -347,9 +506,17 @@ "Name": "context", "Type": "Microsoft.AspNetCore.Http.HttpContext" }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" + "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], "Visibility": "Public", @@ -359,27 +526,27 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.AuthorizationCodeReceivedContext", + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectEvents", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_Properties", + "Name": "get_OnAuthenticationFailed", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Properties", + "Name": "set_OnAuthenticationFailed", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Type": "System.Func" } ], "ReturnType": "System.Void", @@ -388,19 +555,19 @@ }, { "Kind": "Method", - "Name": "get_JwtSecurityToken", + "Name": "get_OnAuthorizationCodeReceived", "Parameters": [], - "ReturnType": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_JwtSecurityToken", + "Name": "set_OnAuthorizationCodeReceived", "Parameters": [ { "Name": "value", - "Type": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken" + "Type": "System.Func" } ], "ReturnType": "System.Void", @@ -409,19 +576,19 @@ }, { "Kind": "Method", - "Name": "get_TokenEndpointRequest", + "Name": "get_OnMessageReceived", "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_TokenEndpointRequest", + "Name": "set_OnMessageReceived", "Parameters": [ { "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" + "Type": "System.Func" } ], "ReturnType": "System.Void", @@ -430,27 +597,40 @@ }, { "Kind": "Method", - "Name": "get_Backchannel", + "Name": "get_OnRedirectToIdentityProvider", "Parameters": [], - "ReturnType": "System.Net.Http.HttpClient", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_TokenEndpointResponse", + "Name": "set_OnRedirectToIdentityProvider", + "Parameters": [ + { + "Name": "value", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_OnRedirectToIdentityProviderForSignOut", "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_TokenEndpointResponse", + "Name": "set_OnRedirectToIdentityProviderForSignOut", "Parameters": [ { "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" + "Type": "System.Func" } ], "ReturnType": "System.Void", @@ -459,44 +639,40 @@ }, { "Kind": "Method", - "Name": "get_HandledCodeRedemption", + "Name": "get_OnSignedOutCallbackRedirect", "Parameters": [], - "ReturnType": "System.Boolean", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "HandleCodeRedemption", - "Parameters": [], + "Name": "set_OnSignedOutCallbackRedirect", + "Parameters": [ + { + "Name": "value", + "Type": "System.Func" + } + ], "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "HandleCodeRedemption", - "Parameters": [ - { - "Name": "accessToken", - "Type": "System.String" - }, - { - "Name": "idToken", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", + "Name": "get_OnRemoteSignOut", + "Parameters": [], + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "HandleCodeRedemption", + "Name": "set_OnRemoteSignOut", "Parameters": [ { - "Name": "tokenEndpointResponse", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" + "Name": "value", + "Type": "System.Func" } ], "ReturnType": "System.Void", @@ -504,54 +680,41 @@ "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - } - ], + "Kind": "Method", + "Name": "get_OnTokenResponseReceived", + "Parameters": [], + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseControlContext", - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions", + "Name": "set_OnTokenResponseReceived", + "Parameters": [ + { + "Name": "value", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_ProtocolMessage", + "Name": "get_OnTokenValidated", "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_ProtocolMessage", + "Name": "set_OnTokenValidated", "Parameters": [ { "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" + "Type": "System.Func" } ], "ReturnType": "System.Void", @@ -559,33 +722,26 @@ "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "get_OnUserInformationReceived", + "Parameters": [], + "ReturnType": "System.Func", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_OnUserInformationReceived", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" + "Name": "value", + "Type": "System.Func" } ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents" - ], - "Members": [ + }, { "Kind": "Method", "Name": "AuthenticationFailed", @@ -596,6 +752,8 @@ } ], "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", "GenericParameter": [] }, { @@ -608,6 +766,8 @@ } ], "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", "GenericParameter": [] }, { @@ -620,6 +780,8 @@ } ], "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", "GenericParameter": [] }, { @@ -632,6 +794,8 @@ } ], "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", "GenericParameter": [] }, { @@ -644,6 +808,22 @@ } ], "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "SignedOutCallbackRedirect", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RemoteSignOutContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", "GenericParameter": [] }, { @@ -656,6 +836,8 @@ } ], "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", "GenericParameter": [] }, { @@ -668,6 +850,8 @@ } ], "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", "GenericParameter": [] }, { @@ -680,6 +864,8 @@ } ], "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", "GenericParameter": [] }, { @@ -692,33 +878,42 @@ } ], "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", "GenericParameter": [] } ], "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.MessageReceivedContext", + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RedirectContext", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", + "BaseType": "Microsoft.AspNetCore.Authentication.PropertiesContext", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_Token", + "Name": "get_ProtocolMessage", "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Token", + "Name": "set_ProtocolMessage", "Parameters": [ { "Name": "value", - "Type": "System.String" + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" } ], "ReturnType": "System.Void", @@ -727,19 +922,69 @@ }, { "Kind": "Method", - "Name": "get_Properties", + "Name": "get_Handled", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleResponse", + "Parameters": [], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RemoteSignOutContext", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_ProtocolMessage", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", + "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Properties", + "Name": "set_ProtocolMessage", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" } ], "ReturnType": "System.Void", @@ -754,9 +999,17 @@ "Name": "context", "Type": "Microsoft.AspNetCore.Http.HttpContext" }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" + "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions" + }, + { + "Name": "message", + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" } ], "Visibility": "Public", @@ -766,29 +1019,27 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectEvents", + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenResponseReceivedContext", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents" - ], + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_OnAuthenticationFailed", + "Name": "get_ProtocolMessage", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_OnAuthenticationFailed", + "Name": "set_ProtocolMessage", "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" } ], "ReturnType": "System.Void", @@ -797,19 +1048,19 @@ }, { "Kind": "Method", - "Name": "get_OnAuthorizationCodeReceived", + "Name": "get_TokenEndpointResponse", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_OnAuthorizationCodeReceived", + "Name": "set_TokenEndpointResponse", "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" } ], "ReturnType": "System.Void", @@ -817,41 +1068,58 @@ "GenericParameter": [] }, { - "Kind": "Method", - "Name": "get_OnMessageReceived", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnMessageReceived", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { - "Name": "value", - "Type": "System.Func" + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions" + }, + { + "Name": "user", + "Type": "System.Security.Claims.ClaimsPrincipal" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenValidatedContext", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "get_OnRedirectToIdentityProvider", + "Name": "get_ProtocolMessage", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_OnRedirectToIdentityProvider", + "Name": "set_ProtocolMessage", "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" } ], "ReturnType": "System.Void", @@ -860,19 +1128,19 @@ }, { "Kind": "Method", - "Name": "get_OnRedirectToIdentityProviderForSignOut", + "Name": "get_SecurityToken", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_OnRedirectToIdentityProviderForSignOut", + "Name": "set_SecurityToken", "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken" } ], "ReturnType": "System.Void", @@ -881,19 +1149,19 @@ }, { "Kind": "Method", - "Name": "get_OnRemoteSignOut", + "Name": "get_TokenEndpointResponse", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_OnRemoteSignOut", + "Name": "set_TokenEndpointResponse", "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" } ], "ReturnType": "System.Void", @@ -902,19 +1170,19 @@ }, { "Kind": "Method", - "Name": "get_OnTokenResponseReceived", + "Name": "get_Nonce", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_OnTokenResponseReceived", + "Name": "set_Nonce", "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "System.String" } ], "ReturnType": "System.Void", @@ -922,41 +1190,58 @@ "GenericParameter": [] }, { - "Kind": "Method", - "Name": "get_OnTokenValidated", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnTokenValidated", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { - "Name": "value", - "Type": "System.Func" + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions" + }, + { + "Name": "principal", + "Type": "System.Security.Claims.ClaimsPrincipal" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.UserInformationReceivedContext", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "get_OnUserInformationReceived", + "Name": "get_ProtocolMessage", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_OnUserInformationReceived", + "Name": "set_ProtocolMessage", "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" } ], "ReturnType": "System.Void", @@ -965,136 +1250,102 @@ }, { "Kind": "Method", - "Name": "AuthenticationFailed", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.AuthenticationFailedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", + "Name": "get_User", + "Parameters": [], + "ReturnType": "Newtonsoft.Json.Linq.JObject", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "AuthorizationCodeReceived", + "Name": "set_User", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.AuthorizationCodeReceivedContext" + "Name": "value", + "Type": "Newtonsoft.Json.Linq.JObject" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "MessageReceived", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.MessageReceivedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToIdentityProvider", - "Parameters": [ + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RedirectContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToIdentityProviderForSignOut", - "Parameters": [ + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RedirectContext" + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions" + }, + { + "Name": "principal", + "Type": "System.Security.Claims.ClaimsPrincipal" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", "Visibility": "Public", "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectChallengeProperties", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthChallengeProperties", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "RemoteSignOut", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RemoteSignOutContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", + "Name": "get_MaxAge", + "Parameters": [], + "ReturnType": "System.Nullable", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "TokenResponseReceived", + "Name": "set_MaxAge", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenResponseReceivedContext" + "Name": "value", + "Type": "System.Nullable" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "TokenValidated", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenValidatedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", + "Name": "get_Prompt", + "Parameters": [], + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "UserInformationReceived", + "Name": "set_Prompt", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.UserInformationReceivedContext" + "Name": "value", + "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, @@ -1104,273 +1355,294 @@ "Parameters": [], "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RedirectContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] }, { "Kind": "Constructor", "Name": ".ctor", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Name": "items", + "Type": "System.Collections.Generic.IDictionary" } ], "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.RemoteSignOutContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Constructor", "Name": ".ctor", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" + "Name": "items", + "Type": "System.Collections.Generic.IDictionary" }, { - "Name": "message", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" + "Name": "parameters", + "Type": "System.Collections.Generic.IDictionary" } ], "Visibility": "Public", "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "MaxAgeKey", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "PromptKey", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] } ], "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenResponseReceivedContext", + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectDefaults", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", + "Abstract": true, + "Static": true, + "Sealed": true, "ImplementedInterfaces": [], "Members": [ { - "Kind": "Method", - "Name": "get_Properties", + "Kind": "Field", + "Name": "AuthenticationPropertiesKey", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", + "ReturnType": "System.String", + "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "get_TokenEndpointResponse", + "Kind": "Field", + "Name": "DisplayName", "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", + "ReturnType": "System.String", + "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "set_TokenEndpointResponse", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" - } - ], - "ReturnType": "System.Void", + "Kind": "Field", + "Name": "CookieNoncePrefix", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "ReadOnly": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], + "Kind": "Field", + "Name": "RedirectUriForCodePropertiesKey", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "ReadOnly": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Field", + "Name": "UserstatePropertiesKey", + "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": "\"OpenIdConnect\"" } ], "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenValidatedContext", + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "ImplementedInterfaces": [], + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authentication.IAuthenticationSignOutHandler" + ], "Members": [ { "Kind": "Method", - "Name": "get_Properties", + "Name": "HandleRequestAsync", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IAuthenticationRequestHandler", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Properties", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", + "Name": "get_Backchannel", + "Parameters": [], + "ReturnType": "System.Net.Http.HttpClient", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_SecurityToken", + "Name": "get_HtmlEncoder", "Parameters": [], - "ReturnType": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken", - "Visibility": "Public", + "ReturnType": "System.Text.Encodings.Web.HtmlEncoder", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_SecurityToken", + "Name": "get_Events", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectEvents", + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Events", "Parameters": [ { "Name": "value", - "Type": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken" + "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectEvents" } ], "ReturnType": "System.Void", - "Visibility": "Public", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_TokenEndpointResponse", + "Name": "CreateEventsAsync", "Parameters": [], - "ReturnType": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_TokenEndpointResponse", + "Name": "HandleRemoteSignOutAsync", + "Parameters": [], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "SignOutAsync", "Parameters": [ { - "Name": "value", - "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Void", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IAuthenticationSignOutHandler", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Nonce", + "Name": "HandleSignOutCallbackAsync", "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Nonce", + "Name": "HandleChallengeAsync", "Parameters": [ { - "Name": "value", - "Type": "System.String" + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Void", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - } - ], - "Visibility": "Public", + "Kind": "Method", + "Name": "HandleRemoteAuthenticateAsync", + "Parameters": [], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.UserInformationReceivedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.BaseOpenIdConnectContext", - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Method", - "Name": "get_User", - "Parameters": [], - "ReturnType": "Newtonsoft.Json.Linq.JObject", - "Visibility": "Public", + "Name": "RedeemAuthorizationCodeAsync", + "Parameters": [ + { + "Name": "tokenEndpointRequest", + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_User", + "Name": "GetUserInformationAsync", "Parameters": [ { - "Name": "value", - "Type": "Newtonsoft.Json.Linq.JObject" + "Name": "message", + "Type": "Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage" + }, + { + "Name": "jwt", + "Type": "System.IdentityModel.Tokens.Jwt.JwtSecurityToken" + }, + { + "Name": "principal", + "Type": "System.Security.Claims.ClaimsPrincipal" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Void", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { @@ -1378,12 +1650,24 @@ "Name": ".ctor", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" }, { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" + "Name": "logger", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "htmlEncoder", + "Type": "System.Text.Encodings.Web.HtmlEncoder" + }, + { + "Name": "encoder", + "Type": "System.Text.Encodings.Web.UrlEncoder" + }, + { + "Name": "clock", + "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" } ], "Visibility": "Public", @@ -1393,58 +1677,22 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Builder.OpenIdConnectAppBuilderExtensions", + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions", "Visibility": "Public", "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "UseOpenIdConnectAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, + "Name": "Validate", + "Parameters": [], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, "Visibility": "Public", "GenericParameter": [] }, - { - "Kind": "Method", - "Name": "UseOpenIdConnectAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.OpenIdConnectOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions", - "ImplementedInterfaces": [], - "Members": [ { "Kind": "Method", "Name": "get_Authority", @@ -1571,6 +1819,14 @@ "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Method", + "Name": "get_ClaimActions", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Method", "Name": "get_RequireHttpsMetadata", @@ -1617,7 +1873,7 @@ "Kind": "Method", "Name": "get_Events", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents", + "ReturnType": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -1627,7 +1883,28 @@ "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.IOpenIdConnectEvents" + "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectEvents" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_MaxAge", + "Parameters": [], + "ReturnType": "System.Nullable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_MaxAge", + "Parameters": [ + { + "Name": "value", + "Type": "System.Nullable" } ], "ReturnType": "System.Void", @@ -1657,7 +1934,28 @@ }, { "Kind": "Method", - "Name": "get_PostLogoutRedirectUri", + "Name": "get_SignedOutCallbackPath", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Http.PathString", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_SignedOutCallbackPath", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Http.PathString" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_SignedOutRedirectUri", "Parameters": [], "ReturnType": "System.String", "Visibility": "Public", @@ -1665,7 +1963,7 @@ }, { "Kind": "Method", - "Name": "set_PostLogoutRedirectUri", + "Name": "set_SignedOutRedirectUri", "Parameters": [ { "Name": "value", @@ -1781,6 +2079,27 @@ "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": "Method", "Name": "get_Scope", @@ -1835,7 +2154,7 @@ "Kind": "Method", "Name": "get_StateDataFormat", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", + "ReturnType": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", "Visibility": "Public", "GenericParameter": [] }, @@ -1845,7 +2164,7 @@ "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISecureDataFormat" + "Type": "Microsoft.AspNetCore.Authentication.ISecureDataFormat" } ], "ReturnType": "System.Void", @@ -1959,19 +2278,40 @@ }, { "Kind": "Method", - "Name": "get_SystemClock", + "Name": "get_DisableTelemetry", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISystemClock", + "ReturnType": "System.Boolean", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_SystemClock", + "Name": "set_DisableTelemetry", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_NonceCookie", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Http.CookieBuilder", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_NonceCookie", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Http.CookieBuilder" } ], "ReturnType": "System.Void", @@ -1984,13 +2324,121 @@ "Parameters": [], "Visibility": "Public", "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectPostConfigureOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Options.IPostConfigureOptions" + ], + "Members": [ + { + "Kind": "Method", + "Name": "PostConfigure", + "Parameters": [ + { + "Name": "name", + "Type": "System.String" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Options.IPostConfigureOptions", + "Visibility": "Public", + "GenericParameter": [] }, { "Kind": "Constructor", "Name": ".ctor", "Parameters": [ { - "Name": "authenticationScheme", + "Name": "dataProtection", + "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectRedirectBehavior", + "Visibility": "Public", + "Kind": "Enumeration", + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Field", + "Name": "RedirectGet", + "Parameters": [], + "GenericParameter": [], + "Literal": "0" + }, + { + "Kind": "Field", + "Name": "FormPost", + "Parameters": [], + "GenericParameter": [], + "Literal": "1" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.OpenIdConnect.Claims.UniqueJsonKeyClaimAction", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.Claims.JsonKeyClaimAction", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Run", + "Parameters": [ + { + "Name": "userData", + "Type": "Newtonsoft.Json.Linq.JObject" + }, + { + "Name": "identity", + "Type": "System.Security.Claims.ClaimsIdentity" + }, + { + "Name": "issuer", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "claimType", + "Type": "System.String" + }, + { + "Name": "valueType", + "Type": "System.String" + }, + { + "Name": "jsonKey", "Type": "System.String" } ], @@ -2000,6 +2448,5 @@ ], "GenericParameters": [] } - ], - "SourceFilters": [] + ] } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/project.json b/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/project.json deleted file mode 100644 index 1b513d926..000000000 --- a/src/Microsoft.AspNetCore.Authentication.OpenIdConnect/project.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core middleware that enables an application to support the OpenID Connect authentication workflow.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/security" - }, - "tags": [ - "aspnetcore", - "authentication", - "security" - ] - }, - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "dependencies": { - "Microsoft.AspNetCore.Authentication": { - "target": "project" - }, - "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.2.0-*", - "type": "build" - }, - "Microsoft.IdentityModel.Protocols.OpenIdConnect": "2.1.0", - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": {}, - "netstandard1.4": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/Events/BaseTwitterContext.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/Events/BaseTwitterContext.cs deleted file mode 100644 index 5f00cb18b..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/Events/BaseTwitterContext.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Authentication.Twitter -{ - /// - /// Base class for other Twitter contexts. - /// - public class BaseTwitterContext : BaseContext - { - /// - /// Initializes a - /// - /// The HTTP environment - /// The options for Twitter - public BaseTwitterContext(HttpContext context, TwitterOptions options) - : base(context) - { - Options = options; - } - - public TwitterOptions Options { get; } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/Events/ITwitterEvents.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/Events/ITwitterEvents.cs deleted file mode 100644 index 006fafc73..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/Events/ITwitterEvents.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Authentication.Twitter -{ - /// - /// Specifies callback methods which the invokes to enable developer control over the authentication process. /> - /// - public interface ITwitterEvents : IRemoteAuthenticationEvents - { - /// - /// Invoked whenever Twitter succesfully authenticates a user - /// - /// Contains information about the login session as well as the user . - /// A representing the completed operation. - Task CreatingTicket(TwitterCreatingTicketContext context); - - /// - /// Called when a Challenge causes a redirect to authorize endpoint in the Twitter middleware - /// - /// Contains redirect URI and of the challenge - Task RedirectToAuthorizationEndpoint(TwitterRedirectToAuthorizationEndpointContext context); - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/Events/TwitterCreatingTicketContext.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/Events/TwitterCreatingTicketContext.cs index 435196a1e..67f28d529 100644 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/Events/TwitterCreatingTicketContext.cs +++ b/src/Microsoft.AspNetCore.Authentication.Twitter/Events/TwitterCreatingTicketContext.cs @@ -1,10 +1,9 @@ // 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.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; using Newtonsoft.Json.Linq; namespace Microsoft.AspNetCore.Authentication.Twitter @@ -12,13 +11,16 @@ namespace Microsoft.AspNetCore.Authentication.Twitter /// /// Contains information about the login session as well as the user . /// - public class TwitterCreatingTicketContext : BaseTwitterContext + public class TwitterCreatingTicketContext : ResultContext { /// /// Initializes a /// /// The HTTP environment + /// The scheme data /// The options for Twitter + /// The . + /// The . /// Twitter user ID /// Twitter screen name /// Twitter access token @@ -26,19 +28,24 @@ public class TwitterCreatingTicketContext : BaseTwitterContext /// User details public TwitterCreatingTicketContext( HttpContext context, + AuthenticationScheme scheme, TwitterOptions options, + ClaimsPrincipal principal, + AuthenticationProperties properties, string userId, string screenName, string accessToken, string accessTokenSecret, JObject user) - : base(context, options) + : base(context, scheme, options) { UserId = userId; ScreenName = screenName; AccessToken = accessToken; AccessTokenSecret = accessTokenSecret; User = user ?? new JObject(); + Principal = principal; + Properties = properties; } /// @@ -66,15 +73,5 @@ public TwitterCreatingTicketContext( /// if it is not available. /// public JObject User { get; } - - /// - /// Gets the representing the user - /// - public ClaimsPrincipal Principal { get; set; } - - /// - /// Gets or sets a property bag for common authentication properties - /// - public AuthenticationProperties Properties { get; set; } } } diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/Events/TwitterEvents.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/Events/TwitterEvents.cs index 033227542..744c48c5f 100644 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/Events/TwitterEvents.cs +++ b/src/Microsoft.AspNetCore.Authentication.Twitter/Events/TwitterEvents.cs @@ -3,27 +3,26 @@ using System; using System.Threading.Tasks; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Authentication.Twitter { /// - /// Default implementation. + /// Default implementation. /// - public class TwitterEvents : RemoteAuthenticationEvents, ITwitterEvents + public class TwitterEvents : RemoteAuthenticationEvents { /// /// Gets or sets the function that is invoked when the Authenticated method is invoked. /// - public Func OnCreatingTicket { get; set; } = context => TaskCache.CompletedTask; + public Func OnCreatingTicket { get; set; } = context => Task.CompletedTask; /// /// Gets or sets the delegate that is invoked when the ApplyRedirect method is invoked. /// - public Func OnRedirectToAuthorizationEndpoint { get; set; } = context => + public Func, Task> OnRedirectToAuthorizationEndpoint { get; set; } = context => { context.Response.Redirect(context.RedirectUri); - return TaskCache.CompletedTask; + return Task.CompletedTask; }; /// @@ -34,9 +33,9 @@ public class TwitterEvents : RemoteAuthenticationEvents, ITwitterEvents public virtual Task CreatingTicket(TwitterCreatingTicketContext context) => OnCreatingTicket(context); /// - /// Called when a Challenge causes a redirect to authorize endpoint in the Twitter middleware + /// Called when a Challenge causes a redirect to authorize endpoint in the Twitter handler /// /// Contains redirect URI and of the challenge - public virtual Task RedirectToAuthorizationEndpoint(TwitterRedirectToAuthorizationEndpointContext context) => OnRedirectToAuthorizationEndpoint(context); + public virtual Task RedirectToAuthorizationEndpoint(RedirectContext context) => OnRedirectToAuthorizationEndpoint(context); } } diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/Events/TwitterRedirectToAuthorizationEndpointContext.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/Events/TwitterRedirectToAuthorizationEndpointContext.cs deleted file mode 100644 index aa1da43ed..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/Events/TwitterRedirectToAuthorizationEndpointContext.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; - -namespace Microsoft.AspNetCore.Authentication.Twitter -{ - /// - /// The Context passed when a Challenge causes a redirect to authorize endpoint in the Twitter middleware. - /// - public class TwitterRedirectToAuthorizationEndpointContext : BaseTwitterContext - { - /// - /// Creates a new context object. - /// - /// The HTTP request context. - /// The Twitter middleware options. - /// The authentication properties of the challenge. - /// The initial redirect URI. - public TwitterRedirectToAuthorizationEndpointContext(HttpContext context, TwitterOptions options, - AuthenticationProperties properties, string redirectUri) - : base(context, options) - { - RedirectUri = redirectUri; - Properties = properties; - } - - /// - /// Gets the URI used for the redirect operation. - /// - public string RedirectUri { get; private set; } - - /// - /// Gets the authentication properties of the challenge. - /// - public AuthenticationProperties Properties { get; private set; } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/Microsoft.AspNetCore.Authentication.Twitter.csproj b/src/Microsoft.AspNetCore.Authentication.Twitter/Microsoft.AspNetCore.Authentication.Twitter.csproj new file mode 100644 index 000000000..4f2aae616 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.Twitter/Microsoft.AspNetCore.Authentication.Twitter.csproj @@ -0,0 +1,15 @@ + + + + ASP.NET Core middleware that enables an application to support Twitter's OAuth 1.0 authentication workflow. + netcoreapp3.0 + $(NoWarn);CS1591 + true + aspnetcore;authentication;security + + + + + + + diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/Microsoft.AspNetCore.Authentication.Twitter.xproj b/src/Microsoft.AspNetCore.Authentication.Twitter/Microsoft.AspNetCore.Authentication.Twitter.xproj deleted file mode 100644 index b72a631fa..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/Microsoft.AspNetCore.Authentication.Twitter.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 0330fff6-b4b5-42dd-8c99-26a789569000 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/Properties/Resources.Designer.cs index d60c2fc73..2eabfff29 100644 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Authentication.Twitter/Properties/Resources.Designer.cs @@ -15,32 +15,28 @@ private static readonly ResourceManager _resourceManager /// internal static string Exception_OptionMustBeProvided { - get { return GetString("Exception_OptionMustBeProvided"); } + get => GetString("Exception_OptionMustBeProvided"); } /// /// The '{0}' option must be provided. /// internal static string FormatException_OptionMustBeProvided(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); /// /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler. /// internal static string Exception_ValidatorHandlerMismatch { - get { return GetString("Exception_ValidatorHandlerMismatch"); } + get => GetString("Exception_ValidatorHandlerMismatch"); } /// /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler. /// internal static string FormatException_ValidatorHandlerMismatch() - { - return GetString("Exception_ValidatorHandlerMismatch"); - } + => GetString("Exception_ValidatorHandlerMismatch"); private static string GetString(string name, params string[] formatterNames) { diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterAppBuilderExtensions.cs index df6ca1d02..36e1111da 100644 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterAppBuilderExtensions.cs @@ -1,9 +1,8 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.AspNetCore.Authentication.Twitter; -using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Builder { @@ -13,38 +12,26 @@ namespace Microsoft.AspNetCore.Builder public static class TwitterAppBuilderExtensions { /// - /// Adds the middleware to the specified , which enables Twitter authentication capabilities. + /// UseTwitterAuthentication is obsolete. Configure Twitter authentication with AddAuthentication().AddTwitter in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. + /// The to add the handler to. /// A reference to this instance after the operation has completed. + [Obsolete("UseTwitterAuthentication is obsolete. Configure Twitter authentication with AddAuthentication().AddTwitter in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)] public static IApplicationBuilder UseTwitterAuthentication(this IApplicationBuilder app) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - - return app.UseMiddleware(); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } /// - /// Adds the middleware to the specified , which enables Twitter authentication capabilities. + /// UseTwitterAuthentication is obsolete. Configure Twitter authentication with AddAuthentication().AddTwitter in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details. /// - /// The to add the middleware to. + /// The to add the handler to. /// An action delegate to configure the provided . /// A reference to this instance after the operation has completed. + [Obsolete("UseTwitterAuthentication is obsolete. Configure Twitter authentication with AddAuthentication().AddTwitter in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)] public static IApplicationBuilder UseTwitterAuthentication(this IApplicationBuilder app, TwitterOptions options) { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - return app.UseMiddleware(Options.Create(options)); + throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470"); } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterDefaults.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterDefaults.cs index 0610ccfc9..bdab80e59 100644 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterDefaults.cs +++ b/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterDefaults.cs @@ -6,5 +6,16 @@ namespace Microsoft.AspNetCore.Authentication.Twitter public static class TwitterDefaults { public const string AuthenticationScheme = "Twitter"; + + public static readonly string DisplayName = "Twitter"; + + // https://developer.twitter.com/en/docs/basics/authentication/api-reference/request_token + internal const string RequestTokenEndpoint = "https://api.twitter.com/oauth/request_token"; + + // https://developer.twitter.com/en/docs/basics/authentication/api-reference/authenticate + internal const string AuthenticationEndpoint = "https://api.twitter.com/oauth/authenticate?oauth_token="; + + // https://developer.twitter.com/en/docs/basics/authentication/api-reference/access_token + internal const string AccessTokenEndpoint = "https://api.twitter.com/oauth/access_token"; } } diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterExtensions.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterExtensions.cs new file mode 100644 index 000000000..724380569 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterExtensions.cs @@ -0,0 +1,29 @@ +// 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.Twitter; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class TwitterExtensions + { + public static AuthenticationBuilder AddTwitter(this AuthenticationBuilder builder) + => builder.AddTwitter(TwitterDefaults.AuthenticationScheme, _ => { }); + + public static AuthenticationBuilder AddTwitter(this AuthenticationBuilder builder, Action configureOptions) + => builder.AddTwitter(TwitterDefaults.AuthenticationScheme, configureOptions); + + public static AuthenticationBuilder AddTwitter(this AuthenticationBuilder builder, string authenticationScheme, Action configureOptions) + => builder.AddTwitter(authenticationScheme, TwitterDefaults.DisplayName, configureOptions); + + public static AuthenticationBuilder AddTwitter(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions) + { + builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton, TwitterPostConfigureOptions>()); + return builder.AddRemoteScheme(authenticationScheme, displayName, configureOptions); + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterHandler.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterHandler.cs index 20d06beaf..cc8591ed3 100644 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterHandler.cs +++ b/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterHandler.cs @@ -8,85 +8,94 @@ using System.Security.Claims; using System.Security.Cryptography; using System.Text; +using System.Text.Encodings.Web; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; using Newtonsoft.Json.Linq; namespace Microsoft.AspNetCore.Authentication.Twitter { - internal class TwitterHandler : RemoteAuthenticationHandler + public class TwitterHandler : RemoteAuthenticationHandler { private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - private const string StateCookie = "__TwitterState"; - private const string RequestTokenEndpoint = "https://api.twitter.com/oauth/request_token"; - private const string AuthenticationEndpoint = "https://api.twitter.com/oauth/authenticate?oauth_token="; - private const string AccessTokenEndpoint = "https://api.twitter.com/oauth/access_token"; - private readonly HttpClient _httpClient; + private HttpClient Backchannel => Options.Backchannel; - public TwitterHandler(HttpClient httpClient) + /// + /// 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. + /// + protected new TwitterEvents Events { - _httpClient = httpClient; + get { return (TwitterEvents)base.Events; } + set { base.Events = value; } } - protected override async Task HandleRemoteAuthenticateAsync() + public TwitterHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) + : base(options, logger, encoder, clock) + { } + + protected override Task CreateEventsAsync() => Task.FromResult(new TwitterEvents()); + + protected override async Task HandleRemoteAuthenticateAsync() { - AuthenticationProperties properties = null; var query = Request.Query; - var protectedRequestToken = Request.Cookies[StateCookie]; + var protectedRequestToken = Request.Cookies[Options.StateCookie.Name]; var requestToken = Options.StateDataFormat.Unprotect(protectedRequestToken); if (requestToken == null) { - return AuthenticateResult.Fail("Invalid state cookie."); + return HandleRequestResult.Fail("Invalid state cookie."); } - properties = requestToken.Properties; + var properties = requestToken.Properties; - // REVIEW: see which of these are really errors + var denied = query["denied"]; + if (!StringValues.IsNullOrEmpty(denied)) + { + // Note: denied errors are special protocol errors indicating the user didn't + // approve the authorization demand requested by the remote authorization server. + // Since it's a frequent scenario (that is not caused by incorrect configuration), + // denied errors are handled differently using HandleAccessDeniedErrorAsync(). + return await HandleAccessDeniedErrorAsync(properties); + } var returnedToken = query["oauth_token"]; if (StringValues.IsNullOrEmpty(returnedToken)) { - return AuthenticateResult.Fail("Missing oauth_token"); + return HandleRequestResult.Fail("Missing oauth_token", properties); } if (!string.Equals(returnedToken, requestToken.Token, StringComparison.Ordinal)) { - return AuthenticateResult.Fail("Unmatched token"); + return HandleRequestResult.Fail("Unmatched token", properties); } var oauthVerifier = query["oauth_verifier"]; if (StringValues.IsNullOrEmpty(oauthVerifier)) { - return AuthenticateResult.Fail("Missing or blank oauth_verifier"); + return HandleRequestResult.Fail("Missing or blank oauth_verifier", properties); } - var cookieOptions = new CookieOptions - { - HttpOnly = true, - Secure = Request.IsHttps - }; + var cookieOptions = Options.StateCookie.Build(Context, Clock.UtcNow); - Response.Cookies.Delete(StateCookie, cookieOptions); + Response.Cookies.Delete(Options.StateCookie.Name, cookieOptions); var accessToken = await ObtainAccessTokenAsync(requestToken, oauthVerifier); var identity = new ClaimsIdentity(new[] { - new Claim(ClaimTypes.NameIdentifier, accessToken.UserId, ClaimValueTypes.String, Options.ClaimsIssuer), - new Claim(ClaimTypes.Name, accessToken.ScreenName, ClaimValueTypes.String, Options.ClaimsIssuer), - new Claim("urn:twitter:userid", accessToken.UserId, ClaimValueTypes.String, Options.ClaimsIssuer), - new Claim("urn:twitter:screenname", accessToken.ScreenName, ClaimValueTypes.String, Options.ClaimsIssuer) + new Claim(ClaimTypes.NameIdentifier, accessToken.UserId, ClaimValueTypes.String, ClaimsIssuer), + new Claim(ClaimTypes.Name, accessToken.ScreenName, ClaimValueTypes.String, ClaimsIssuer), + new Claim("urn:twitter:userid", accessToken.UserId, ClaimValueTypes.String, ClaimsIssuer), + new Claim("urn:twitter:screenname", accessToken.ScreenName, ClaimValueTypes.String, ClaimsIssuer) }, - Options.ClaimsIssuer); + ClaimsIssuer); JObject user = null; if (Options.RetrieveUserDetails) @@ -102,109 +111,128 @@ protected override async Task HandleRemoteAuthenticateAsync( }); } - return AuthenticateResult.Success(await CreateTicketAsync(identity, properties, accessToken, user)); + return HandleRequestResult.Success(await CreateTicketAsync(identity, properties, accessToken, user)); } protected virtual async Task CreateTicketAsync( ClaimsIdentity identity, AuthenticationProperties properties, AccessToken token, JObject user) { - var context = new TwitterCreatingTicketContext(Context, Options, token.UserId, token.ScreenName, token.Token, token.TokenSecret, user) + foreach (var action in Options.ClaimActions) { - Principal = new ClaimsPrincipal(identity), - Properties = properties - }; - - await Options.Events.CreatingTicket(context); - - if (context.Principal?.Identity == null) - { - return null; + action.Run(user, identity, ClaimsIssuer); } - return new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme); + var context = new TwitterCreatingTicketContext(Context, Scheme, Options, new ClaimsPrincipal(identity), properties, token.UserId, token.ScreenName, token.Token, token.TokenSecret, user); + await Events.CreatingTicket(context); + + return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name); } - protected override async Task HandleUnauthorizedAsync(ChallengeContext context) + protected override async Task HandleChallengeAsync(AuthenticationProperties properties) { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - var properties = new AuthenticationProperties(context.Properties); - if (string.IsNullOrEmpty(properties.RedirectUri)) { - properties.RedirectUri = CurrentUri; + properties.RedirectUri = OriginalPathBase + OriginalPath + Request.QueryString; } // If CallbackConfirmed is false, this will throw var requestToken = await ObtainRequestTokenAsync(BuildRedirectUri(Options.CallbackPath), properties); - var twitterAuthenticationEndpoint = AuthenticationEndpoint + requestToken.Token; + var twitterAuthenticationEndpoint = TwitterDefaults.AuthenticationEndpoint + requestToken.Token; - var cookieOptions = new CookieOptions - { - HttpOnly = true, - Secure = Request.IsHttps, - Expires = Options.SystemClock.UtcNow.Add(Options.RemoteAuthenticationTimeout), - }; + var cookieOptions = Options.StateCookie.Build(Context, Clock.UtcNow); - Response.Cookies.Append(StateCookie, Options.StateDataFormat.Protect(requestToken), cookieOptions); + Response.Cookies.Append(Options.StateCookie.Name, Options.StateDataFormat.Protect(requestToken), cookieOptions); - var redirectContext = new TwitterRedirectToAuthorizationEndpointContext( - Context, Options, - properties, twitterAuthenticationEndpoint); - await Options.Events.RedirectToAuthorizationEndpoint(redirectContext); - return true; + var redirectContext = new RedirectContext(Context, Scheme, Options, properties, twitterAuthenticationEndpoint); + await Events.RedirectToAuthorizationEndpoint(redirectContext); } - private async Task ObtainRequestTokenAsync(string callBackUri, AuthenticationProperties properties) + private async Task ExecuteRequestAsync(string url, HttpMethod httpMethod, RequestToken accessToken = null, Dictionary extraOAuthPairs = null, Dictionary queryParameters = null, Dictionary formData = null) { - Logger.ObtainRequestToken(); - - var nonce = Guid.NewGuid().ToString("N"); - - var authorizationParts = new SortedDictionary + var authorizationParts = new SortedDictionary(extraOAuthPairs ?? new Dictionary()) { - { "oauth_callback", callBackUri }, { "oauth_consumer_key", Options.ConsumerKey }, - { "oauth_nonce", nonce }, + { "oauth_nonce", Guid.NewGuid().ToString("N") }, { "oauth_signature_method", "HMAC-SHA1" }, { "oauth_timestamp", GenerateTimeStamp() }, { "oauth_version", "1.0" } }; + if (accessToken != null) + { + authorizationParts.Add("oauth_token", accessToken.Token); + } + + var signatureParts = new SortedDictionary(authorizationParts); + if (queryParameters != null) + { + foreach (var queryParameter in queryParameters) + { + signatureParts.Add(queryParameter.Key, queryParameter.Value); + } + } + if (formData != null) + { + foreach (var formItem in formData) + { + signatureParts.Add(formItem.Key, formItem.Value); + } + } + var parameterBuilder = new StringBuilder(); - foreach (var authorizationKey in authorizationParts) + foreach (var signaturePart in signatureParts) { - parameterBuilder.AppendFormat("{0}={1}&", UrlEncoder.Encode(authorizationKey.Key), UrlEncoder.Encode(authorizationKey.Value)); + parameterBuilder.AppendFormat("{0}={1}&", Uri.EscapeDataString(signaturePart.Key), Uri.EscapeDataString(signaturePart.Value)); } parameterBuilder.Length--; var parameterString = parameterBuilder.ToString(); var canonicalizedRequestBuilder = new StringBuilder(); - canonicalizedRequestBuilder.Append(HttpMethod.Post.Method); + canonicalizedRequestBuilder.Append(httpMethod.Method); canonicalizedRequestBuilder.Append("&"); - canonicalizedRequestBuilder.Append(UrlEncoder.Encode(RequestTokenEndpoint)); + canonicalizedRequestBuilder.Append(Uri.EscapeDataString(url)); canonicalizedRequestBuilder.Append("&"); - canonicalizedRequestBuilder.Append(UrlEncoder.Encode(parameterString)); + canonicalizedRequestBuilder.Append(Uri.EscapeDataString(parameterString)); - var signature = ComputeSignature(Options.ConsumerSecret, null, canonicalizedRequestBuilder.ToString()); + var signature = ComputeSignature(Options.ConsumerSecret, accessToken?.TokenSecret, canonicalizedRequestBuilder.ToString()); authorizationParts.Add("oauth_signature", signature); + var queryString = ""; + if (queryParameters != null) + { + var queryStringBuilder = new StringBuilder("?"); + foreach (var queryParam in queryParameters) + { + queryStringBuilder.AppendFormat("{0}={1}&", queryParam.Key, queryParam.Value); + } + queryStringBuilder.Length--; + queryString = queryStringBuilder.ToString(); + } + var authorizationHeaderBuilder = new StringBuilder(); authorizationHeaderBuilder.Append("OAuth "); foreach (var authorizationPart in authorizationParts) { - authorizationHeaderBuilder.AppendFormat( - "{0}=\"{1}\", ", authorizationPart.Key, UrlEncoder.Encode(authorizationPart.Value)); + authorizationHeaderBuilder.AppendFormat("{0}=\"{1}\",", authorizationPart.Key, Uri.EscapeDataString(authorizationPart.Value)); } - authorizationHeaderBuilder.Length = authorizationHeaderBuilder.Length - 2; + authorizationHeaderBuilder.Length--; - var request = new HttpRequestMessage(HttpMethod.Post, RequestTokenEndpoint); + var request = new HttpRequestMessage(httpMethod, url + queryString); request.Headers.Add("Authorization", authorizationHeaderBuilder.ToString()); - var response = await _httpClient.SendAsync(request, Context.RequestAborted); + if (formData != null) + { + request.Content = new FormUrlEncodedContent(formData); + } + + return await Backchannel.SendAsync(request, Context.RequestAborted); + } + + private async Task ObtainRequestTokenAsync(string callBackUri, AuthenticationProperties properties) + { + Logger.ObtainRequestToken(); + + var response = await ExecuteRequestAsync(TwitterDefaults.RequestTokenEndpoint, HttpMethod.Post, extraOAuthPairs: new Dictionary() { { "oauth_callback", callBackUri } }); response.EnsureSuccessStatusCode(); var responseText = await response.Content.ReadAsStringAsync(); @@ -223,58 +251,8 @@ private async Task ObtainAccessTokenAsync(RequestToken token, strin Logger.ObtainAccessToken(); - var nonce = Guid.NewGuid().ToString("N"); - - var authorizationParts = new SortedDictionary - { - { "oauth_consumer_key", Options.ConsumerKey }, - { "oauth_nonce", nonce }, - { "oauth_signature_method", "HMAC-SHA1" }, - { "oauth_token", token.Token }, - { "oauth_timestamp", GenerateTimeStamp() }, - { "oauth_verifier", verifier }, - { "oauth_version", "1.0" }, - }; - - var parameterBuilder = new StringBuilder(); - foreach (var authorizationKey in authorizationParts) - { - parameterBuilder.AppendFormat("{0}={1}&", UrlEncoder.Encode(authorizationKey.Key), UrlEncoder.Encode(authorizationKey.Value)); - } - parameterBuilder.Length--; - var parameterString = parameterBuilder.ToString(); - - var canonicalizedRequestBuilder = new StringBuilder(); - canonicalizedRequestBuilder.Append(HttpMethod.Post.Method); - canonicalizedRequestBuilder.Append("&"); - canonicalizedRequestBuilder.Append(UrlEncoder.Encode(AccessTokenEndpoint)); - canonicalizedRequestBuilder.Append("&"); - canonicalizedRequestBuilder.Append(UrlEncoder.Encode(parameterString)); - - var signature = ComputeSignature(Options.ConsumerSecret, token.TokenSecret, canonicalizedRequestBuilder.ToString()); - authorizationParts.Add("oauth_signature", signature); - authorizationParts.Remove("oauth_verifier"); - - var authorizationHeaderBuilder = new StringBuilder(); - authorizationHeaderBuilder.Append("OAuth "); - foreach (var authorizationPart in authorizationParts) - { - authorizationHeaderBuilder.AppendFormat( - "{0}=\"{1}\", ", authorizationPart.Key, UrlEncoder.Encode(authorizationPart.Value)); - } - authorizationHeaderBuilder.Length = authorizationHeaderBuilder.Length - 2; - - var request = new HttpRequestMessage(HttpMethod.Post, AccessTokenEndpoint); - request.Headers.Add("Authorization", authorizationHeaderBuilder.ToString()); - - var formPairs = new Dictionary() - { - { "oauth_verifier", verifier }, - }; - - request.Content = new FormUrlEncodedContent(formPairs); - - var response = await _httpClient.SendAsync(request, Context.RequestAborted); + var formPost = new Dictionary { { "oauth_verifier", verifier } }; + var response = await ExecuteRequestAsync(TwitterDefaults.AccessTokenEndpoint, HttpMethod.Post, token, formData: formPost); if (!response.IsSuccessStatusCode) { @@ -299,53 +277,8 @@ private async Task RetrieveUserDetailsAsync(AccessToken accessToken, Cl { Logger.RetrieveUserDetails(); - var nonce = Guid.NewGuid().ToString("N"); + var response = await ExecuteRequestAsync("https://api.twitter.com/1.1/account/verify_credentials.json", HttpMethod.Get, accessToken, queryParameters: new Dictionary() { { "include_email", "true" } }); - var authorizationParts = new SortedDictionary - { - { "oauth_consumer_key", Options.ConsumerKey }, - { "oauth_nonce", nonce }, - { "oauth_signature_method", "HMAC-SHA1" }, - { "oauth_timestamp", GenerateTimeStamp() }, - { "oauth_token", accessToken.Token }, - { "oauth_version", "1.0" } - }; - - var parameterBuilder = new StringBuilder(); - foreach (var authorizationKey in authorizationParts) - { - parameterBuilder.AppendFormat("{0}={1}&", UrlEncoder.Encode(authorizationKey.Key), UrlEncoder.Encode(authorizationKey.Value)); - } - parameterBuilder.Length--; - var parameterString = parameterBuilder.ToString(); - - var resource_url = "https://api.twitter.com/1.1/account/verify_credentials.json"; - var resource_query = "include_email=true"; - var canonicalizedRequestBuilder = new StringBuilder(); - canonicalizedRequestBuilder.Append(HttpMethod.Get.Method); - canonicalizedRequestBuilder.Append("&"); - canonicalizedRequestBuilder.Append(UrlEncoder.Encode(resource_url)); - canonicalizedRequestBuilder.Append("&"); - canonicalizedRequestBuilder.Append(UrlEncoder.Encode(resource_query)); - canonicalizedRequestBuilder.Append("%26"); - canonicalizedRequestBuilder.Append(UrlEncoder.Encode(parameterString)); - - var signature = ComputeSignature(Options.ConsumerSecret, accessToken.TokenSecret, canonicalizedRequestBuilder.ToString()); - authorizationParts.Add("oauth_signature", signature); - - var authorizationHeaderBuilder = new StringBuilder(); - authorizationHeaderBuilder.Append("OAuth "); - foreach (var authorizationPart in authorizationParts) - { - authorizationHeaderBuilder.AppendFormat( - "{0}=\"{1}\", ", authorizationPart.Key, UrlEncoder.Encode(authorizationPart.Value)); - } - authorizationHeaderBuilder.Length = authorizationHeaderBuilder.Length - 2; - - var request = new HttpRequestMessage(HttpMethod.Get, resource_url + "?include_email=true"); - request.Headers.Add("Authorization", authorizationHeaderBuilder.ToString()); - - var response = await _httpClient.SendAsync(request, Context.RequestAborted); if (!response.IsSuccessStatusCode) { Logger.LogError("Email request failed with a status code of " + response.StatusCode); @@ -355,12 +288,6 @@ private async Task RetrieveUserDetailsAsync(AccessToken accessToken, Cl var result = JObject.Parse(responseText); - var email = result.Value("email"); - if (!string.IsNullOrEmpty(email)) - { - identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.Email, Options.ClaimsIssuer)); - } - return result; } @@ -377,8 +304,8 @@ private string ComputeSignature(string consumerSecret, string tokenSecret, strin algorithm.Key = Encoding.ASCII.GetBytes( string.Format(CultureInfo.InvariantCulture, "{0}&{1}", - UrlEncoder.Encode(consumerSecret), - string.IsNullOrEmpty(tokenSecret) ? string.Empty : UrlEncoder.Encode(tokenSecret))); + Uri.EscapeDataString(consumerSecret), + string.IsNullOrEmpty(tokenSecret) ? string.Empty : Uri.EscapeDataString(tokenSecret))); var hash = algorithm.ComputeHash(Encoding.ASCII.GetBytes(signatureData)); return Convert.ToBase64String(hash); } diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterMiddleware.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterMiddleware.cs deleted file mode 100644 index 67fb903dd..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterMiddleware.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Globalization; -using System.Net.Http; -using System.Text.Encodings.Web; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.DataProtection; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace Microsoft.AspNetCore.Authentication.Twitter -{ - /// - /// ASP.NET Core middleware for authenticating users using Twitter. - /// - public class TwitterMiddleware : AuthenticationMiddleware - { - private readonly HttpClient _httpClient; - - /// - /// Initializes a - /// - /// The next middleware in the HTTP pipeline to invoke - /// - /// - /// - /// - /// Configuration options for the middleware - public TwitterMiddleware( - RequestDelegate next, - IDataProtectionProvider dataProtectionProvider, - ILoggerFactory loggerFactory, - UrlEncoder encoder, - IOptions sharedOptions, - IOptions options) - : base(next, options, loggerFactory, encoder) - { - if (next == null) - { - throw new ArgumentNullException(nameof(next)); - } - - if (dataProtectionProvider == null) - { - throw new ArgumentNullException(nameof(dataProtectionProvider)); - } - - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - if (encoder == null) - { - throw new ArgumentNullException(nameof(encoder)); - } - - if (sharedOptions == null) - { - throw new ArgumentNullException(nameof(sharedOptions)); - } - - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - if (string.IsNullOrEmpty(Options.ConsumerSecret)) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.ConsumerSecret))); - } - if (string.IsNullOrEmpty(Options.ConsumerKey)) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.ConsumerKey))); - } - if (!Options.CallbackPath.HasValue) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(Options.CallbackPath))); - } - - if (Options.Events == null) - { - Options.Events = new TwitterEvents(); - } - if (Options.StateDataFormat == null) - { - var dataProtector = dataProtectionProvider.CreateProtector( - typeof(TwitterMiddleware).FullName, Options.AuthenticationScheme, "v1"); - Options.StateDataFormat = new SecureDataFormat( - new RequestTokenSerializer(), - dataProtector); - } - - if (string.IsNullOrEmpty(Options.SignInScheme)) - { - Options.SignInScheme = sharedOptions.Value.SignInScheme; - } - if (string.IsNullOrEmpty(Options.SignInScheme)) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, "SignInScheme")); - } - - _httpClient = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler()); - _httpClient.Timeout = Options.BackchannelTimeout; - _httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB - _httpClient.DefaultRequestHeaders.Accept.ParseAdd("*/*"); - _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core Twitter middleware"); - _httpClient.DefaultRequestHeaders.ExpectContinue = false; - } - - /// - /// Provides the object for processing authentication-related requests. - /// - /// An configured with the supplied to the constructor. - protected override AuthenticationHandler CreateHandler() - { - return new TwitterHandler(_httpClient); - } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterOptions.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterOptions.cs index bf54b7fbb..269516ae1 100644 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterOptions.cs +++ b/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterOptions.cs @@ -2,28 +2,41 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.ComponentModel; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.Twitter; +using System.Globalization; +using System.Security.Claims; +using Microsoft.AspNetCore.Authentication.OAuth.Claims; using Microsoft.AspNetCore.Http; -namespace Microsoft.AspNetCore.Builder +namespace Microsoft.AspNetCore.Authentication.Twitter { /// - /// Options for the Twitter authentication middleware. + /// Options for the Twitter authentication handler. /// public class TwitterOptions : RemoteAuthenticationOptions { + private const string DefaultStateCookieName = "__TwitterState"; + + private CookieBuilder _stateCookieBuilder; + /// /// Initializes a new instance of the class. /// public TwitterOptions() { - AuthenticationScheme = TwitterDefaults.AuthenticationScheme; - DisplayName = AuthenticationScheme; CallbackPath = new PathString("/signin-twitter"); BackchannelTimeout = TimeSpan.FromSeconds(60); Events = new TwitterEvents(); + + ClaimActions.MapJsonKey(ClaimTypes.Email, "email", ClaimValueTypes.Email); + + _stateCookieBuilder = new TwitterCookieBuilder(this) + { + Name = DefaultStateCookieName, + SecurePolicy = CookieSecurePolicy.SameAsRequest, + HttpOnly = true, + SameSite = SameSiteMode.Lax, + IsEssential = true, + }; } /// @@ -47,17 +60,69 @@ public TwitterOptions() public bool RetrieveUserDetails { get; set; } /// - /// Gets or sets the type used to secure data handled by the middleware. + /// A collection of claim actions used to select values from the json user data and create Claims. + /// + public ClaimActionCollection ClaimActions { get; } = new ClaimActionCollection(); + + /// + /// Gets or sets the type used to secure data handled by the handler. /// public ISecureDataFormat StateDataFormat { get; set; } /// - /// Gets or sets the used to handle authentication events. + /// Gets or sets the used to handle authentication events. + /// + public new TwitterEvents Events + { + get => (TwitterEvents)base.Events; + set => base.Events = value; + } + + /// + /// Determines the settings used to create the state cookie before the + /// cookie gets added to the response. /// - public new ITwitterEvents Events + public CookieBuilder StateCookie { - get { return (ITwitterEvents)base.Events; } - set { base.Events = value; } + get => _stateCookieBuilder; + set => _stateCookieBuilder = value ?? throw new ArgumentNullException(nameof(value)); + } + + /// + /// Added the validate method to ensure that the customer key and customer secret values are not not empty for the twitter authentication middleware + /// + public override void Validate() + { + base.Validate(); + if (string.IsNullOrEmpty(ConsumerKey)) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(ConsumerKey)), nameof(ConsumerKey)); + } + + if (string.IsNullOrEmpty(ConsumerSecret)) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(ConsumerSecret)), nameof(ConsumerSecret)); + } + } + + private class TwitterCookieBuilder : CookieBuilder + { + private readonly TwitterOptions _twitterOptions; + + public TwitterCookieBuilder(TwitterOptions twitterOptions) + { + _twitterOptions = twitterOptions; + } + + public override CookieOptions Build(HttpContext context, DateTimeOffset expiresFrom) + { + var options = base.Build(context, expiresFrom); + if (!Expiration.HasValue) + { + options.Expires = expiresFrom.Add(_twitterOptions.RemoteAuthenticationTimeout); + } + return options; + } } } } diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterPostConfigureOptions.cs b/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterPostConfigureOptions.cs new file mode 100644 index 000000000..09db5699f --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.Twitter/TwitterPostConfigureOptions.cs @@ -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.Net.Http; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Authentication.Twitter +{ + /// + /// Used to setup defaults for all . + /// + public class TwitterPostConfigureOptions : IPostConfigureOptions + { + private readonly IDataProtectionProvider _dp; + + public TwitterPostConfigureOptions(IDataProtectionProvider dataProtection) + { + _dp = dataProtection; + } + + /// + /// Invoked to post configure a TOptions instance. + /// + /// The name of the options instance being configured. + /// The options instance to configure. + public void PostConfigure(string name, TwitterOptions options) + { + options.DataProtectionProvider = options.DataProtectionProvider ?? _dp; + + if (options.StateDataFormat == null) + { + var dataProtector = options.DataProtectionProvider.CreateProtector( + typeof(TwitterHandler).FullName, name, "v1"); + options.StateDataFormat = new SecureDataFormat( + new RequestTokenSerializer(), + dataProtector); + } + + if (options.Backchannel == null) + { + options.Backchannel = new HttpClient(options.BackchannelHttpHandler ?? new HttpClientHandler()); + options.Backchannel.Timeout = options.BackchannelTimeout; + options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB + options.Backchannel.DefaultRequestHeaders.Accept.ParseAdd("*/*"); + options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core Twitter handler"); + options.Backchannel.DefaultRequestHeaders.ExpectContinue = false; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/baseline.net45.json b/src/Microsoft.AspNetCore.Authentication.Twitter/baseline.net45.json deleted file mode 100644 index c35232a31..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/baseline.net45.json +++ /dev/null @@ -1,848 +0,0 @@ -{ - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Twitter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", - "Types": [ - { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.TwitterDefaults", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"Twitter\"" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.TwitterMiddleware", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "CreateHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" - }, - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" - }, - { - "Name": "sharedOptions", - "Type": "Microsoft.Extensions.Options.IOptions" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.BaseTwitterContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.TwitterOptions", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.TwitterOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.ITwitterEvents", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents" - ], - "Members": [ - { - "Kind": "Method", - "Name": "CreatingTicket", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Twitter.TwitterCreatingTicketContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToAuthorizationEndpoint", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Twitter.TwitterRedirectToAuthorizationEndpointContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.TwitterCreatingTicketContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Twitter.BaseTwitterContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_UserId", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ScreenName", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AccessToken", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AccessTokenSecret", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_User", - "Parameters": [], - "ReturnType": "Newtonsoft.Json.Linq.JObject", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Principal", - "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Principal", - "Parameters": [ - { - "Name": "value", - "Type": "System.Security.Claims.ClaimsPrincipal" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Properties", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.TwitterOptions" - }, - { - "Name": "userId", - "Type": "System.String" - }, - { - "Name": "screenName", - "Type": "System.String" - }, - { - "Name": "accessToken", - "Type": "System.String" - }, - { - "Name": "accessTokenSecret", - "Type": "System.String" - }, - { - "Name": "user", - "Type": "Newtonsoft.Json.Linq.JObject" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.TwitterEvents", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.Twitter.ITwitterEvents" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_OnCreatingTicket", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnCreatingTicket", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnRedirectToAuthorizationEndpoint", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnRedirectToAuthorizationEndpoint", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "CreatingTicket", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Twitter.TwitterCreatingTicketContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Twitter.ITwitterEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToAuthorizationEndpoint", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Twitter.TwitterRedirectToAuthorizationEndpointContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Twitter.ITwitterEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.TwitterRedirectToAuthorizationEndpointContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Twitter.BaseTwitterContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_RedirectUri", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.TwitterOptions" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - }, - { - "Name": "redirectUri", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.AccessToken", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Twitter.RequestToken", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_UserId", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_UserId", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ScreenName", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ScreenName", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.RequestToken", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Token", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Token", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_TokenSecret", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_TokenSecret", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_CallbackConfirmed", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_CallbackConfirmed", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Properties", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.RequestTokenSerializer", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IDataSerializer" - ], - "Members": [ - { - "Kind": "Method", - "Name": "Serialize", - "Parameters": [ - { - "Name": "model", - "Type": "Microsoft.AspNetCore.Authentication.Twitter.RequestToken" - } - ], - "ReturnType": "System.Byte[]", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Deserialize", - "Parameters": [ - { - "Name": "data", - "Type": "System.Byte[]" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authentication.Twitter.RequestToken", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Write", - "Parameters": [ - { - "Name": "writer", - "Type": "System.IO.BinaryWriter" - }, - { - "Name": "token", - "Type": "Microsoft.AspNetCore.Authentication.Twitter.RequestToken" - } - ], - "ReturnType": "System.Void", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Read", - "Parameters": [ - { - "Name": "reader", - "Type": "System.IO.BinaryReader" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authentication.Twitter.RequestToken", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.TwitterAppBuilderExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "UseTwitterAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "UseTwitterAuthentication", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.TwitterOptions" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.TwitterOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_ConsumerKey", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ConsumerKey", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ConsumerSecret", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ConsumerSecret", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_RetrieveUserDetails", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_RetrieveUserDetails", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_StateDataFormat", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_StateDataFormat", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISecureDataFormat" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Events", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.Twitter.ITwitterEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Events", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.Twitter.ITwitterEvents" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SystemClock", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISystemClock", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SystemClock", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - } - ], - "SourceFilters": [] -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/baseline.netcore.json b/src/Microsoft.AspNetCore.Authentication.Twitter/baseline.netcore.json index c35232a31..03ee64562 100644 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Authentication.Twitter/baseline.netcore.json @@ -1,8 +1,8 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Twitter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Twitter, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.TwitterDefaults", + "Name": "Microsoft.Extensions.DependencyInjection.TwitterExtensions", "Visibility": "Public", "Kind": "Class", "Abstract": true, @@ -11,99 +11,86 @@ "ImplementedInterfaces": [], "Members": [ { - "Kind": "Field", - "Name": "AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", + "Kind": "Method", + "Name": "AddTwitter", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, + "Extension": true, "Visibility": "Public", - "GenericParameter": [], - "Constant": true, - "Literal": "\"Twitter\"" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.TwitterMiddleware", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "CreateHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "Virtual": true, - "Override": true, - "Visibility": "Protected", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "AddTwitter", "Parameters": [ { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" }, { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddTwitter", + "Parameters": [ { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" }, { - "Name": "sharedOptions", - "Type": "Microsoft.Extensions.Options.IOptions" + "Name": "authenticationScheme", + "Type": "System.String" }, { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" + "Name": "configureOptions", + "Type": "System.Action" } ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.BaseTwitterContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.TwitterOptions", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "AddTwitter", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" }, { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.TwitterOptions" + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" } ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, "Visibility": "Public", "GenericParameter": [] } @@ -111,36 +98,46 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.ITwitterEvents", + "Name": "Microsoft.AspNetCore.Builder.TwitterAppBuilderExtensions", "Visibility": "Public", - "Kind": "Interface", + "Kind": "Class", "Abstract": true, - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents" - ], + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "CreatingTicket", + "Name": "UseTwitterAuthentication", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Twitter.TwitterCreatingTicketContext" + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RedirectToAuthorizationEndpoint", + "Name": "UseTwitterAuthentication", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Twitter.TwitterRedirectToAuthorizationEndpointContext" + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.Twitter.TwitterOptions" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", "GenericParameter": [] } ], @@ -150,7 +147,7 @@ "Name": "Microsoft.AspNetCore.Authentication.Twitter.TwitterCreatingTicketContext", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Twitter.BaseTwitterContext", + "BaseType": "Microsoft.AspNetCore.Authentication.ResultContext", "ImplementedInterfaces": [], "Members": [ { @@ -193,48 +190,6 @@ "Visibility": "Public", "GenericParameter": [] }, - { - "Kind": "Method", - "Name": "get_Principal", - "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Principal", - "Parameters": [ - { - "Name": "value", - "Type": "System.Security.Claims.ClaimsPrincipal" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Properties", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, { "Kind": "Constructor", "Name": ".ctor", @@ -243,9 +198,21 @@ "Name": "context", "Type": "Microsoft.AspNetCore.Http.HttpContext" }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.TwitterOptions" + "Type": "Microsoft.AspNetCore.Authentication.Twitter.TwitterOptions" + }, + { + "Name": "principal", + "Type": "System.Security.Claims.ClaimsPrincipal" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" }, { "Name": "userId", @@ -279,9 +246,7 @@ "Visibility": "Public", "Kind": "Class", "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.Twitter.ITwitterEvents" - ], + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", @@ -308,7 +273,7 @@ "Kind": "Method", "Name": "get_OnRedirectToAuthorizationEndpoint", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "System.Func, System.Threading.Tasks.Task>", "Visibility": "Public", "GenericParameter": [] }, @@ -318,7 +283,7 @@ "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "System.Func, System.Threading.Tasks.Task>" } ], "ReturnType": "System.Void", @@ -336,7 +301,6 @@ ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Twitter.ITwitterEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -346,12 +310,11 @@ "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Twitter.TwitterRedirectToAuthorizationEndpointContext" + "Type": "Microsoft.AspNetCore.Authentication.RedirectContext" } ], "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Twitter.ITwitterEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -365,56 +328,6 @@ ], "GenericParameters": [] }, - { - "Name": "Microsoft.AspNetCore.Authentication.Twitter.TwitterRedirectToAuthorizationEndpointContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Twitter.BaseTwitterContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_RedirectUri", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.TwitterOptions" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - }, - { - "Name": "redirectUri", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, { "Name": "Microsoft.AspNetCore.Authentication.Twitter.AccessToken", "Visibility": "Public", @@ -547,7 +460,7 @@ "Kind": "Method", "Name": "get_Properties", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationProperties", "Visibility": "Public", "GenericParameter": [] }, @@ -557,7 +470,7 @@ "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], "ReturnType": "System.Void", @@ -655,45 +568,148 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Builder.TwitterAppBuilderExtensions", + "Name": "Microsoft.AspNetCore.Authentication.Twitter.TwitterDefaults", "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": "AuthenticationScheme", + "Parameters": [], + "ReturnType": "System.String", + "Static": true, + "Visibility": "Public", + "GenericParameter": [], + "Constant": true, + "Literal": "\"Twitter\"" + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.Twitter.TwitterHandler", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler", + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "UseTwitterAuthentication", + "Name": "get_Events", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.Twitter.TwitterEvents", + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Events", "Parameters": [ { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + "Name": "value", + "Type": "Microsoft.AspNetCore.Authentication.Twitter.TwitterEvents" } ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", + "ReturnType": "System.Void", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "UseTwitterAuthentication", + "Name": "CreateEventsAsync", + "Parameters": [], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleRemoteAuthenticateAsync", + "Parameters": [], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "CreateTicketAsync", "Parameters": [ { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + "Name": "identity", + "Type": "System.Security.Claims.ClaimsIdentity" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + }, + { + "Name": "token", + "Type": "Microsoft.AspNetCore.Authentication.Twitter.AccessToken" }, + { + "Name": "user", + "Type": "Newtonsoft.Json.Linq.JObject" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleChallengeAsync", + "Parameters": [ + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.TwitterOptions" + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" + }, + { + "Name": "logger", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "encoder", + "Type": "System.Text.Encodings.Web.UrlEncoder" + }, + { + "Name": "clock", + "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" } ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, "Visibility": "Public", "GenericParameter": [] } @@ -701,10 +717,10 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Builder.TwitterOptions", + "Name": "Microsoft.AspNetCore.Authentication.Twitter.TwitterOptions", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions", "ImplementedInterfaces": [], "Members": [ { @@ -770,6 +786,14 @@ "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Method", + "Name": "get_ClaimActions", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimActionCollection", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Method", "Name": "get_StateDataFormat", @@ -795,7 +819,7 @@ "Kind": "Method", "Name": "get_Events", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.Twitter.ITwitterEvents", + "ReturnType": "Microsoft.AspNetCore.Authentication.Twitter.TwitterEvents", "Visibility": "Public", "GenericParameter": [] }, @@ -805,7 +829,7 @@ "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.Twitter.ITwitterEvents" + "Type": "Microsoft.AspNetCore.Authentication.Twitter.TwitterEvents" } ], "ReturnType": "System.Void", @@ -814,25 +838,35 @@ }, { "Kind": "Method", - "Name": "get_SystemClock", + "Name": "get_StateCookie", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISystemClock", + "ReturnType": "Microsoft.AspNetCore.Http.CookieBuilder", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_SystemClock", + "Name": "set_StateCookie", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" + "Type": "Microsoft.AspNetCore.Http.CookieBuilder" } ], "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Method", + "Name": "Validate", + "Parameters": [], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Constructor", "Name": ".ctor", @@ -842,7 +876,49 @@ } ], "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.Twitter.TwitterPostConfigureOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Options.IPostConfigureOptions" + ], + "Members": [ + { + "Kind": "Method", + "Name": "PostConfigure", + "Parameters": [ + { + "Name": "name", + "Type": "System.String" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.Twitter.TwitterOptions" + } + ], + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Options.IPostConfigureOptions", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "dataProtection", + "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] } - ], - "SourceFilters": [] + ] } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.Twitter/project.json b/src/Microsoft.AspNetCore.Authentication.Twitter/project.json deleted file mode 100644 index 2d31ec0b2..000000000 --- a/src/Microsoft.AspNetCore.Authentication.Twitter/project.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core middleware that enables an application to support Twitter's OAuth 1.0 authentication workflow.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/security" - }, - "tags": [ - "aspnetcore", - "authentication", - "security" - ] - }, - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "dependencies": { - "Microsoft.AspNetCore.Authentication": { - "target": "project" - }, - "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.2.0-*", - "type": "build" - }, - "NETStandard.Library": "1.6.2-*", - "Newtonsoft.Json": "9.0.1" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/AuthenticationFailedContext.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/AuthenticationFailedContext.cs new file mode 100644 index 000000000..f643fad97 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/AuthenticationFailedContext.cs @@ -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; +using Microsoft.AspNetCore.Http; +using Microsoft.IdentityModel.Protocols.WsFederation; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + /// + /// The context object used in for . + /// + public class AuthenticationFailedContext : RemoteAuthenticationContext + { + /// + /// Creates a new context object + /// + /// + /// + /// + public AuthenticationFailedContext(HttpContext context, AuthenticationScheme scheme, WsFederationOptions options) + : base(context, scheme, options, new AuthenticationProperties()) + { } + + /// + /// The from the request, if any. + /// + public WsFederationMessage ProtocolMessage { get; set; } + + /// + /// The that triggered this event. + /// + public Exception Exception { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/MessageReceivedContext.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/MessageReceivedContext.cs new file mode 100644 index 000000000..4028fa5e3 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/MessageReceivedContext.cs @@ -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 Microsoft.AspNetCore.Http; +using Microsoft.IdentityModel.Protocols.WsFederation; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + /// + /// The context object used for . + /// + public class MessageReceivedContext : RemoteAuthenticationContext + { + /// + /// Creates a new context object. + /// + /// + /// + /// + /// + public MessageReceivedContext( + HttpContext context, + AuthenticationScheme scheme, + WsFederationOptions options, + AuthenticationProperties properties) + : base(context, scheme, options, properties) { } + + /// + /// The received on this request. + /// + public WsFederationMessage ProtocolMessage { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/RedirectContext.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/RedirectContext.cs new file mode 100644 index 000000000..654037d0a --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/RedirectContext.cs @@ -0,0 +1,44 @@ +// 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; +using Microsoft.IdentityModel.Protocols.WsFederation; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + /// + /// When a user configures the to be notified prior to redirecting to an IdentityProvider + /// an instance of is passed to the 'RedirectToAuthenticationEndpoint' or 'RedirectToEndSessionEndpoint' events. + /// + public class RedirectContext : PropertiesContext + { + /// + /// Creates a new context object. + /// + /// + /// + /// + /// + public RedirectContext( + HttpContext context, + AuthenticationScheme scheme, + WsFederationOptions options, + AuthenticationProperties properties) + : base(context, scheme, options, properties) { } + + /// + /// The used to compose the redirect. + /// + public WsFederationMessage ProtocolMessage { get; set; } + + /// + /// If true, will skip any default logic for this redirect. + /// + public bool Handled { get; private set; } + + /// + /// Skips any default logic for this redirect. + /// + public void HandleResponse() => Handled = true; + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/RemoteSignoutContext.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/RemoteSignoutContext.cs new file mode 100644 index 000000000..8aec24a64 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/RemoteSignoutContext.cs @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Http; +using Microsoft.IdentityModel.Protocols.WsFederation; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + /// + /// An event context for RemoteSignOut. + /// + public class RemoteSignOutContext : RemoteAuthenticationContext + { + /// + /// + /// + /// + /// + /// + /// + public RemoteSignOutContext(HttpContext context, AuthenticationScheme scheme, WsFederationOptions options, WsFederationMessage message) + : base(context, scheme, options, new AuthenticationProperties()) + => ProtocolMessage = message; + + /// + /// The signout message. + /// + public WsFederationMessage ProtocolMessage { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/SecurityTokenReceivedContext.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/SecurityTokenReceivedContext.cs new file mode 100644 index 000000000..311f41515 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/SecurityTokenReceivedContext.cs @@ -0,0 +1,28 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Security.Claims; +using Microsoft.AspNetCore.Http; +using Microsoft.IdentityModel.Protocols.WsFederation; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + /// + /// This Context can be used to be informed when an 'AuthorizationCode' is redeemed for tokens at the token endpoint. + /// + public class SecurityTokenReceivedContext : RemoteAuthenticationContext + { + /// + /// Creates a + /// + public SecurityTokenReceivedContext(HttpContext context, AuthenticationScheme scheme, WsFederationOptions options, AuthenticationProperties properties) + : base(context, scheme, options, properties) + { + } + + /// + /// The received on this request. + /// + public WsFederationMessage ProtocolMessage { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/SecurityTokenValidatedContext.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/SecurityTokenValidatedContext.cs new file mode 100644 index 000000000..1f32014b6 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/SecurityTokenValidatedContext.cs @@ -0,0 +1,34 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using Microsoft.AspNetCore.Http; +using Microsoft.IdentityModel.Protocols.WsFederation; +using Microsoft.IdentityModel.Tokens; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + /// + /// The context object used for . + /// + public class SecurityTokenValidatedContext : RemoteAuthenticationContext + { + /// + /// Creates a + /// + public SecurityTokenValidatedContext(HttpContext context, AuthenticationScheme scheme, WsFederationOptions options, ClaimsPrincipal principal, AuthenticationProperties properties) + : base(context, scheme, options, properties) + => Principal = principal; + + /// + /// The received on this request. + /// + public WsFederationMessage ProtocolMessage { get; set; } + + /// + /// The that was validated. + /// + public SecurityToken SecurityToken { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/WsFederationEvents.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/WsFederationEvents.cs new file mode 100644 index 000000000..55c3936f9 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/Events/WsFederationEvents.cs @@ -0,0 +1,74 @@ +// 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; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + /// + /// Specifies events which the invokes to enable developer control over the authentication process. /> + /// + public class WsFederationEvents : RemoteAuthenticationEvents + { + /// + /// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed. + /// + public Func OnAuthenticationFailed { get; set; } = context => Task.CompletedTask; + + /// + /// Invoked when a protocol message is first received. + /// + public Func OnMessageReceived { get; set; } = context => Task.CompletedTask; + + /// + /// Invoked to manipulate redirects to the identity provider for SignIn, SignOut, or Challenge. + /// + public Func OnRedirectToIdentityProvider { get; set; } = context => Task.CompletedTask; + + /// + /// Invoked when a wsignoutcleanup request is received at the RemoteSignOutPath endpoint. + /// + public Func OnRemoteSignOut { get; set; } = context => Task.CompletedTask; + + /// + /// Invoked with the security token that has been extracted from the protocol message. + /// + public Func OnSecurityTokenReceived { get; set; } = context => Task.CompletedTask; + + /// + /// Invoked after the security token has passed validation and a ClaimsIdentity has been generated. + /// + public Func OnSecurityTokenValidated { get; set; } = context => Task.CompletedTask; + + /// + /// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed. + /// + public virtual Task AuthenticationFailed(AuthenticationFailedContext context) => OnAuthenticationFailed(context); + + /// + /// Invoked when a protocol message is first received. + /// + public virtual Task MessageReceived(MessageReceivedContext context) => OnMessageReceived(context); + + /// + /// Invoked to manipulate redirects to the identity provider for SignIn, SignOut, or Challenge. + /// + public virtual Task RedirectToIdentityProvider(RedirectContext context) => OnRedirectToIdentityProvider(context); + + /// + /// Invoked when a wsignoutcleanup request is received at the RemoteSignOutPath endpoint. + /// + public virtual Task RemoteSignOut(RemoteSignOutContext context) => OnRemoteSignOut(context); + + /// + /// Invoked with the security token that has been extracted from the protocol message. + /// + public virtual Task SecurityTokenReceived(SecurityTokenReceivedContext context) => OnSecurityTokenReceived(context); + + /// + /// Invoked after the security token has passed validation and a ClaimsIdentity has been generated. + /// + public virtual Task SecurityTokenValidated(SecurityTokenValidatedContext context) => OnSecurityTokenValidated(context); + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/LoggingExtensions.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/LoggingExtensions.cs new file mode 100644 index 000000000..e28b7e15b --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/LoggingExtensions.cs @@ -0,0 +1,85 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.Extensions.Logging +{ + internal static class LoggingExtensions + { + private static Action _signInWithoutWresult; + private static Action _signInWithoutToken; + private static Action _exceptionProcessingMessage; + private static Action _malformedRedirectUri; + private static Action _remoteSignOutHandledResponse; + private static Action _remoteSignOutSkipped; + private static Action _remoteSignOut; + + static LoggingExtensions() + { + _signInWithoutWresult = LoggerMessage.Define( + eventId: 1, + logLevel: LogLevel.Debug, + formatString: "Received a sign-in message without a WResult."); + _signInWithoutToken = LoggerMessage.Define( + eventId: 2, + logLevel: LogLevel.Debug, + formatString: "Received a sign-in message without a token."); + _exceptionProcessingMessage = LoggerMessage.Define( + eventId: 3, + logLevel: LogLevel.Error, + formatString: "Exception occurred while processing message."); + _malformedRedirectUri = LoggerMessage.Define( + eventId: 4, + logLevel: LogLevel.Warning, + formatString: "The sign-out redirect URI '{0}' is malformed."); + _remoteSignOutHandledResponse = LoggerMessage.Define( + eventId: 5, + logLevel: LogLevel.Debug, + formatString: "RemoteSignOutContext.HandledResponse"); + _remoteSignOutSkipped = LoggerMessage.Define( + eventId: 6, + logLevel: LogLevel.Debug, + formatString: "RemoteSignOutContext.Skipped"); + _remoteSignOut = LoggerMessage.Define( + eventId: 7, + logLevel: LogLevel.Information, + formatString: "Remote signout request processed."); + } + + public static void SignInWithoutWresult(this ILogger logger) + { + _signInWithoutWresult(logger, null); + } + + public static void SignInWithoutToken(this ILogger logger) + { + _signInWithoutToken(logger, null); + } + + public static void ExceptionProcessingMessage(this ILogger logger, Exception ex) + { + _exceptionProcessingMessage(logger, ex); + } + + public static void MalformedRedirectUri(this ILogger logger, string uri) + { + _malformedRedirectUri(logger, uri, null); + } + + public static void RemoteSignOutHandledResponse(this ILogger logger) + { + _remoteSignOutHandledResponse(logger, null); + } + + public static void RemoteSignOutSkipped(this ILogger logger) + { + _remoteSignOutSkipped(logger, null); + } + + public static void RemoteSignOut(this ILogger logger) + { + _remoteSignOut(logger, null); + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/Microsoft.AspNetCore.Authentication.WsFederation.csproj b/src/Microsoft.AspNetCore.Authentication.WsFederation/Microsoft.AspNetCore.Authentication.WsFederation.csproj new file mode 100644 index 000000000..ae4d52aff --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/Microsoft.AspNetCore.Authentication.WsFederation.csproj @@ -0,0 +1,17 @@ + + + + ASP.NET Core middleware that enables an application to support the WsFederation authentication workflow. + netcoreapp3.0 + true + aspnetcore;authentication;security + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/Properties/Resources.Designer.cs new file mode 100644 index 000000000..564e826a7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/Properties/Resources.Designer.cs @@ -0,0 +1,114 @@ +// +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + using System.Globalization; + using System.Reflection; + using System.Resources; + + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("Microsoft.AspNetCore.Authentication.WsFederation.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// The service descriptor is missing. + /// + internal static string Exception_MissingDescriptor + { + get => GetString("Exception_MissingDescriptor"); + } + + /// + /// The service descriptor is missing. + /// + internal static string FormatException_MissingDescriptor() + => GetString("Exception_MissingDescriptor"); + + /// + /// No token validator was found for the given token. + /// + internal static string Exception_NoTokenValidatorFound + { + get => GetString("Exception_NoTokenValidatorFound"); + } + + /// + /// No token validator was found for the given token. + /// + internal static string FormatException_NoTokenValidatorFound() + => GetString("Exception_NoTokenValidatorFound"); + + /// + /// The '{0}' option must be provided. + /// + internal static string Exception_OptionMustBeProvided + { + get => GetString("Exception_OptionMustBeProvided"); + } + + /// + /// The '{0}' option must be provided. + /// + internal static string FormatException_OptionMustBeProvided(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); + + /// + /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler. + /// + internal static string Exception_ValidatorHandlerMismatch + { + get => GetString("Exception_ValidatorHandlerMismatch"); + } + + /// + /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler. + /// + internal static string FormatException_ValidatorHandlerMismatch() + => GetString("Exception_ValidatorHandlerMismatch"); + + /// + /// The sign in message does not contain a required token. + /// + internal static string SignInMessageTokenIsMissing + { + get => GetString("SignInMessageTokenIsMissing"); + } + + /// + /// The sign in message does not contain a required token. + /// + internal static string FormatSignInMessageTokenIsMissing() + => GetString("SignInMessageTokenIsMissing"); + + /// + /// The sign in message does not contain a required wresult. + /// + internal static string SignInMessageWresultIsMissing + { + get => GetString("SignInMessageWresultIsMissing"); + } + + /// + /// The sign in message does not contain a required wresult. + /// + internal static string FormatSignInMessageWresultIsMissing() + => GetString("SignInMessageWresultIsMissing"); + + 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; + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/Resources.resx b/src/Microsoft.AspNetCore.Authentication.WsFederation/Resources.resx new file mode 100644 index 000000000..e2edafb67 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/Resources.resx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + The service descriptor is missing. + + + No token validator was found for the given token. + + + The '{0}' option must be provided. + + + An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler. + + + The sign in message does not contain a required token. + + + The sign in message does not contain a required wresult. + + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationDefaults.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationDefaults.cs new file mode 100644 index 000000000..3b97d995b --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationDefaults.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + /// + /// Default values related to WsFederation authentication handler + /// + public static class WsFederationDefaults + { + /// + /// The default authentication type used when registering the WsFederationHandler. + /// + public const string AuthenticationScheme = "WsFederation"; + + /// + /// The default display name used when registering the WsFederationHandler. + /// + public const string DisplayName = "WsFederation"; + + /// + /// Constant used to identify userstate inside AuthenticationProperties that have been serialized in the 'wctx' parameter. + /// + public static readonly string UserstatePropertiesKey = "WsFederation.Userstate"; + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationExtensions.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationExtensions.cs new file mode 100644 index 000000000..47091d58d --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationExtensions.cs @@ -0,0 +1,58 @@ +// 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.WsFederation; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// Extensions for registering the . + /// + public static class WsFederationExtensions + { + /// + /// Registers the using the default authentication scheme, display name, and options. + /// + /// + /// + public static AuthenticationBuilder AddWsFederation(this AuthenticationBuilder builder) + => builder.AddWsFederation(WsFederationDefaults.AuthenticationScheme, _ => { }); + + /// + /// Registers the using the default authentication scheme, display name, and the given options configuration. + /// + /// + /// A delegate that configures the . + /// + public static AuthenticationBuilder AddWsFederation(this AuthenticationBuilder builder, Action configureOptions) + => builder.AddWsFederation(WsFederationDefaults.AuthenticationScheme, configureOptions); + + /// + /// Registers the using the given authentication scheme, default display name, and the given options configuration. + /// + /// + /// + /// A delegate that configures the . + /// + public static AuthenticationBuilder AddWsFederation(this AuthenticationBuilder builder, string authenticationScheme, Action configureOptions) + => builder.AddWsFederation(authenticationScheme, WsFederationDefaults.DisplayName, configureOptions); + + /// + /// Registers the using the given authentication scheme, display name, and options configuration. + /// + /// + /// + /// + /// A delegate that configures the . + /// + public static AuthenticationBuilder AddWsFederation(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions) + { + builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton, WsFederationPostConfigureOptions>()); + return builder.AddRemoteScheme(authenticationScheme, displayName, configureOptions); + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationHandler.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationHandler.cs new file mode 100644 index 000000000..c4bb8fff7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationHandler.cs @@ -0,0 +1,425 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Protocols.WsFederation; +using Microsoft.IdentityModel.Tokens; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + /// + /// A per-request authentication handler for the WsFederation. + /// + public class WsFederationHandler : RemoteAuthenticationHandler, IAuthenticationSignOutHandler + { + private const string CorrelationProperty = ".xsrf"; + private WsFederationConfiguration _configuration; + + /// + /// Creates a new WsFederationAuthenticationHandler + /// + /// + /// + /// + /// + public WsFederationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) + : base(options, logger, encoder, clock) + { + } + + /// + /// 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. + /// + protected new WsFederationEvents Events + { + get { return (WsFederationEvents)base.Events; } + set { base.Events = value; } + } + + /// + /// Creates a new instance of the events instance. + /// + /// A new instance of the events instance. + protected override Task CreateEventsAsync() => Task.FromResult(new WsFederationEvents()); + + /// + /// Overridden to handle remote signout requests + /// + /// + public override Task HandleRequestAsync() + { + // RemoteSignOutPath and CallbackPath may be the same, fall through if the message doesn't match. + if (Options.RemoteSignOutPath.HasValue && Options.RemoteSignOutPath == Request.Path && HttpMethods.IsGet(Request.Method) + && string.Equals(Request.Query[WsFederationConstants.WsFederationParameterNames.Wa], + WsFederationConstants.WsFederationActions.SignOutCleanup, StringComparison.OrdinalIgnoreCase)) + { + // We've received a remote sign-out request + return HandleRemoteSignOutAsync(); + } + + return base.HandleRequestAsync(); + } + + /// + /// Handles Challenge + /// + /// + protected override async Task HandleChallengeAsync(AuthenticationProperties properties) + { + if (_configuration == null) + { + _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted); + } + + // Save the original challenge URI so we can redirect back to it when we're done. + if (string.IsNullOrEmpty(properties.RedirectUri)) + { + properties.RedirectUri = OriginalPathBase + OriginalPath + Request.QueryString; + } + + var wsFederationMessage = new WsFederationMessage() + { + IssuerAddress = _configuration.TokenEndpoint ?? string.Empty, + Wtrealm = Options.Wtrealm, + Wa = WsFederationConstants.WsFederationActions.SignIn, + }; + + if (!string.IsNullOrEmpty(Options.Wreply)) + { + wsFederationMessage.Wreply = Options.Wreply; + } + else + { + wsFederationMessage.Wreply = BuildRedirectUri(Options.CallbackPath); + } + + GenerateCorrelationId(properties); + + var redirectContext = new RedirectContext(Context, Scheme, Options, properties) + { + ProtocolMessage = wsFederationMessage + }; + await Events.RedirectToIdentityProvider(redirectContext); + + if (redirectContext.Handled) + { + return; + } + + wsFederationMessage = redirectContext.ProtocolMessage; + + if (!string.IsNullOrEmpty(wsFederationMessage.Wctx)) + { + properties.Items[WsFederationDefaults.UserstatePropertiesKey] = wsFederationMessage.Wctx; + } + + wsFederationMessage.Wctx = Uri.EscapeDataString(Options.StateDataFormat.Protect(properties)); + + var redirectUri = wsFederationMessage.CreateSignInUrl(); + if (!Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute)) + { + Logger.MalformedRedirectUri(redirectUri); + } + Response.Redirect(redirectUri); + } + + /// + /// Invoked to process incoming authentication messages. + /// + /// + protected override async Task HandleRemoteAuthenticateAsync() + { + WsFederationMessage wsFederationMessage = null; + AuthenticationProperties properties = null; + + // assumption: if the ContentType is "application/x-www-form-urlencoded" it should be safe to read as it is small. + if (HttpMethods.IsPost(Request.Method) + && !string.IsNullOrEmpty(Request.ContentType) + // May have media/type; charset=utf-8, allow partial match. + && Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase) + && Request.Body.CanRead) + { + var form = await Request.ReadFormAsync(); + + wsFederationMessage = new WsFederationMessage(form.Select(pair => new KeyValuePair(pair.Key, pair.Value))); + } + + if (wsFederationMessage == null || !wsFederationMessage.IsSignInMessage) + { + if (Options.SkipUnrecognizedRequests) + { + // Not for us? + return HandleRequestResult.SkipHandler(); + } + + return HandleRequestResult.Fail("No message."); + } + + try + { + // Retrieve our cached redirect uri + var state = wsFederationMessage.Wctx; + // WsFed allows for uninitiated logins, state may be missing. See AllowUnsolicitedLogins. + properties = Options.StateDataFormat.Unprotect(state); + + if (properties == null) + { + if (!Options.AllowUnsolicitedLogins) + { + return HandleRequestResult.Fail("Unsolicited logins are not allowed."); + } + } + else + { + // Extract the user state from properties and reset. + properties.Items.TryGetValue(WsFederationDefaults.UserstatePropertiesKey, out var userState); + wsFederationMessage.Wctx = userState; + } + + var messageReceivedContext = new MessageReceivedContext(Context, Scheme, Options, properties) + { + ProtocolMessage = wsFederationMessage + }; + await Events.MessageReceived(messageReceivedContext); + if (messageReceivedContext.Result != null) + { + return messageReceivedContext.Result; + } + wsFederationMessage = messageReceivedContext.ProtocolMessage; + properties = messageReceivedContext.Properties; // Provides a new instance if not set. + + // If state did flow from the challenge then validate it. See AllowUnsolicitedLogins above. + if (properties.Items.TryGetValue(CorrelationProperty, out string correlationId) + && !ValidateCorrelationId(properties)) + { + return HandleRequestResult.Fail("Correlation failed.", properties); + } + + if (wsFederationMessage.Wresult == null) + { + Logger.SignInWithoutWresult(); + return HandleRequestResult.Fail(Resources.SignInMessageWresultIsMissing, properties); + } + + var token = wsFederationMessage.GetToken(); + if (string.IsNullOrEmpty(token)) + { + Logger.SignInWithoutToken(); + return HandleRequestResult.Fail(Resources.SignInMessageTokenIsMissing, properties); + } + + var securityTokenReceivedContext = new SecurityTokenReceivedContext(Context, Scheme, Options, properties) + { + ProtocolMessage = wsFederationMessage + }; + await Events.SecurityTokenReceived(securityTokenReceivedContext); + if (securityTokenReceivedContext.Result != null) + { + return securityTokenReceivedContext.Result; + } + wsFederationMessage = securityTokenReceivedContext.ProtocolMessage; + properties = messageReceivedContext.Properties; + + if (_configuration == null) + { + _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted); + } + + // Copy and augment to avoid cross request race conditions for updated configurations. + var tvp = Options.TokenValidationParameters.Clone(); + var issuers = new[] { _configuration.Issuer }; + tvp.ValidIssuers = (tvp.ValidIssuers == null ? issuers : tvp.ValidIssuers.Concat(issuers)); + tvp.IssuerSigningKeys = (tvp.IssuerSigningKeys == null ? _configuration.SigningKeys : tvp.IssuerSigningKeys.Concat(_configuration.SigningKeys)); + + ClaimsPrincipal principal = null; + SecurityToken parsedToken = null; + foreach (var validator in Options.SecurityTokenHandlers) + { + if (validator.CanReadToken(token)) + { + principal = validator.ValidateToken(token, tvp, out parsedToken); + break; + } + } + + if (principal == null) + { + throw new SecurityTokenException(Resources.Exception_NoTokenValidatorFound); + } + + if (Options.UseTokenLifetime && parsedToken != null) + { + // Override any session persistence to match the token lifetime. + var issued = parsedToken.ValidFrom; + if (issued != DateTime.MinValue) + { + properties.IssuedUtc = issued.ToUniversalTime(); + } + var expires = parsedToken.ValidTo; + if (expires != DateTime.MinValue) + { + properties.ExpiresUtc = expires.ToUniversalTime(); + } + properties.AllowRefresh = false; + } + + var securityTokenValidatedContext = new SecurityTokenValidatedContext(Context, Scheme, Options, principal, properties) + { + ProtocolMessage = wsFederationMessage, + SecurityToken = parsedToken, + }; + + await Events.SecurityTokenValidated(securityTokenValidatedContext); + if (securityTokenValidatedContext.Result != null) + { + return securityTokenValidatedContext.Result; + } + + // Flow possible changes + principal = securityTokenValidatedContext.Principal; + properties = securityTokenValidatedContext.Properties; + + return HandleRequestResult.Success(new AuthenticationTicket(principal, properties, Scheme.Name)); + } + catch (Exception exception) + { + Logger.ExceptionProcessingMessage(exception); + + // Refresh the configuration for exceptions that may be caused by key rollovers. The user can also request a refresh in the notification. + if (Options.RefreshOnIssuerKeyNotFound && exception.GetType().Equals(typeof(SecurityTokenSignatureKeyNotFoundException))) + { + Options.ConfigurationManager.RequestRefresh(); + } + + var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options) + { + ProtocolMessage = wsFederationMessage, + Exception = exception + }; + await Events.AuthenticationFailed(authenticationFailedContext); + if (authenticationFailedContext.Result != null) + { + return authenticationFailedContext.Result; + } + + return HandleRequestResult.Fail(exception, properties); + } + } + + /// + /// Handles Signout + /// + /// + public async virtual Task SignOutAsync(AuthenticationProperties properties) + { + var target = ResolveTarget(Options.ForwardSignOut); + if (target != null) + { + await Context.SignOutAsync(target, properties); + return; + } + + if (_configuration == null) + { + _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted); + } + + var wsFederationMessage = new WsFederationMessage() + { + IssuerAddress = _configuration.TokenEndpoint ?? string.Empty, + Wtrealm = Options.Wtrealm, + Wa = WsFederationConstants.WsFederationActions.SignOut, + }; + + // Set Wreply in order: + // 1. properties.Redirect + // 2. Options.SignOutWreply + // 3. Options.Wreply + if (properties != null && !string.IsNullOrEmpty(properties.RedirectUri)) + { + wsFederationMessage.Wreply = BuildRedirectUriIfRelative(properties.RedirectUri); + } + else if (!string.IsNullOrEmpty(Options.SignOutWreply)) + { + wsFederationMessage.Wreply = BuildRedirectUriIfRelative(Options.SignOutWreply); + } + else if (!string.IsNullOrEmpty(Options.Wreply)) + { + wsFederationMessage.Wreply = BuildRedirectUriIfRelative(Options.Wreply); + } + + var redirectContext = new RedirectContext(Context, Scheme, Options, properties) + { + ProtocolMessage = wsFederationMessage + }; + await Events.RedirectToIdentityProvider(redirectContext); + + if (!redirectContext.Handled) + { + var redirectUri = redirectContext.ProtocolMessage.CreateSignOutUrl(); + if (!Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute)) + { + Logger.MalformedRedirectUri(redirectUri); + } + Response.Redirect(redirectUri); + } + } + + /// + /// Handles wsignoutcleanup1.0 messages sent to the RemoteSignOutPath + /// + /// + protected virtual async Task HandleRemoteSignOutAsync() + { + var message = new WsFederationMessage(Request.Query.Select(pair => new KeyValuePair(pair.Key, pair.Value))); + var remoteSignOutContext = new RemoteSignOutContext(Context, Scheme, Options, message); + await Events.RemoteSignOut(remoteSignOutContext); + + if (remoteSignOutContext.Result != null) + { + if (remoteSignOutContext.Result.Handled) + { + Logger.RemoteSignOutHandledResponse(); + return true; + } + if (remoteSignOutContext.Result.Skipped) + { + Logger.RemoteSignOutSkipped(); + return false; + } + } + + Logger.RemoteSignOut(); + + await Context.SignOutAsync(Options.SignOutScheme); + return true; + } + + /// + /// Build a redirect path if the given path is a relative path. + /// + private string BuildRedirectUriIfRelative(string uri) + { + if (string.IsNullOrEmpty(uri)) + { + return uri; + } + + if (!uri.StartsWith("/", StringComparison.Ordinal)) + { + return uri; + } + + return BuildRedirectUri(uri); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationOptions.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationOptions.cs new file mode 100644 index 000000000..4e0612677 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationOptions.cs @@ -0,0 +1,180 @@ +// 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.Collections.ObjectModel; +using System.IdentityModel.Tokens.Jwt; +using Microsoft.AspNetCore.Http; +using Microsoft.IdentityModel.Protocols; +using Microsoft.IdentityModel.Protocols.WsFederation; +using Microsoft.IdentityModel.Tokens; +using Microsoft.IdentityModel.Tokens.Saml; +using Microsoft.IdentityModel.Tokens.Saml2; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + /// + /// Configuration options for + /// + public class WsFederationOptions : RemoteAuthenticationOptions + { + private ICollection _securityTokenHandlers = new Collection() + { + new Saml2SecurityTokenHandler(), + new SamlSecurityTokenHandler(), + new JwtSecurityTokenHandler() + }; + private TokenValidationParameters _tokenValidationParameters = new TokenValidationParameters(); + + /// + /// Initializes a new + /// + public WsFederationOptions() + { + CallbackPath = "/signin-wsfed"; + // In ADFS the cleanup messages are sent to the same callback path as the initial login. + // In AAD it sends the cleanup message to a random Reply Url and there's no deterministic way to configure it. + // If you manage to get it configured, then you can set RemoteSignOutPath accordingly. + RemoteSignOutPath = "/signin-wsfed"; + Events = new WsFederationEvents(); + } + + /// + /// Check that the options are valid. Should throw an exception if things are not ok. + /// + public override void Validate() + { + base.Validate(); + + if (ConfigurationManager == null) + { + throw new InvalidOperationException($"Provide {nameof(MetadataAddress)}, " + + $"{nameof(Configuration)}, or {nameof(ConfigurationManager)} to {nameof(WsFederationOptions)}"); + } + } + + /// + /// Configuration provided directly by the developer. If provided, then MetadataAddress and the Backchannel properties + /// will not be used. This information should not be updated during request processing. + /// + public WsFederationConfiguration Configuration { get; set; } + + /// + /// Gets or sets the address to retrieve the wsFederation metadata + /// + public string MetadataAddress { get; set; } + + /// + /// Responsible for retrieving, caching, and refreshing the configuration from metadata. + /// If not provided, then one will be created using the MetadataAddress and Backchannel properties. + /// + public IConfigurationManager ConfigurationManager { get; set; } + + /// + /// Gets or sets if a metadata refresh should be attempted after a SecurityTokenSignatureKeyNotFoundException. This allows for automatic + /// recovery in the event of a signature key rollover. This is enabled by default. + /// + public bool RefreshOnIssuerKeyNotFound { get; set; } = true; + + /// + /// Indicates if requests to the CallbackPath may also be for other components. If enabled the handler will pass + /// requests through that do not contain WsFederation authentication responses. Disabling this and setting the + /// CallbackPath to a dedicated endpoint may provide better error handling. + /// This is disabled by default. + /// + public bool SkipUnrecognizedRequests { get; set; } + + /// + /// Gets or sets the to call when processing WsFederation messages. + /// + public new WsFederationEvents Events + { + get => (WsFederationEvents)base.Events; + set => base.Events = value; + } + + /// + /// Gets or sets the collection of used to read and validate the s. + /// + public ICollection SecurityTokenHandlers + { + get + { + return _securityTokenHandlers; + } + set + { + _securityTokenHandlers = value ?? throw new ArgumentNullException(nameof(SecurityTokenHandlers)); + } + } + + /// + /// Gets or sets the type used to secure data handled by the middleware. + /// + public ISecureDataFormat StateDataFormat { get; set; } + + /// + /// Gets or sets the + /// + /// if 'TokenValidationParameters' is null. + public TokenValidationParameters TokenValidationParameters + { + get + { + return _tokenValidationParameters; + } + set + { + _tokenValidationParameters = value ?? throw new ArgumentNullException(nameof(TokenValidationParameters)); + } + } + + /// + /// Gets or sets the 'wreply'. CallbackPath must be set to match or cleared so it can be generated dynamically. + /// This field is optional. If not set then it will be generated from the current request and the CallbackPath. + /// + public string Wreply { get; set; } + + /// + /// Gets or sets the 'wreply' value used during sign-out. + /// If none is specified then the value from the Wreply field is used. + /// + public string SignOutWreply { get; set; } + + /// + /// Gets or sets the 'wtrealm'. + /// + public string Wtrealm { get; set; } + + /// + /// Indicates that the authentication session lifetime (e.g. cookies) should match that of the authentication token. + /// If the token does not provide lifetime information then normal session lifetimes will be used. + /// This is enabled by default. + /// + public bool UseTokenLifetime { get; set; } = true; + + /// + /// Gets or sets if HTTPS is required for the metadata address or authority. + /// The default is true. This should be disabled only in development environments. + /// + public bool RequireHttpsMetadata { get; set; } = true; + + /// + /// The Ws-Federation protocol allows the user to initiate logins without contacting the application for a Challenge first. + /// However, that flow is susceptible to XSRF and other attacks so it is disabled here by default. + /// + public bool AllowUnsolicitedLogins { get; set; } + + /// + /// Requests received on this path will cause the handler to invoke SignOut using the SignOutScheme. + /// + public PathString RemoteSignOutPath { get; set; } + + /// + /// The Authentication Scheme to use with SignOutAsync from RemoteSignOutPath. SignInScheme will be used if this + /// is not set. + /// + public string SignOutScheme { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationPostConfigureOptions.cs b/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationPostConfigureOptions.cs new file mode 100644 index 000000000..62647d4fc --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/WsFederationPostConfigureOptions.cs @@ -0,0 +1,89 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Net.Http; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Protocols; +using Microsoft.IdentityModel.Protocols.WsFederation; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + /// + /// Used to setup defaults for all . + /// + public class WsFederationPostConfigureOptions : IPostConfigureOptions + { + private readonly IDataProtectionProvider _dp; + + /// + /// + /// + /// + public WsFederationPostConfigureOptions(IDataProtectionProvider dataProtection) + { + _dp = dataProtection; + } + + /// + /// Invoked to post configure a TOptions instance. + /// + /// The name of the options instance being configured. + /// The options instance to configure. + public void PostConfigure(string name, WsFederationOptions options) + { + options.DataProtectionProvider = options.DataProtectionProvider ?? _dp; + + if (string.IsNullOrEmpty(options.SignOutScheme)) + { + options.SignOutScheme = options.SignInScheme; + } + + if (options.StateDataFormat == null) + { + var dataProtector = options.DataProtectionProvider.CreateProtector( + typeof(WsFederationHandler).FullName, name, "v1"); + options.StateDataFormat = new PropertiesDataFormat(dataProtector); + } + + if (!options.CallbackPath.HasValue && !string.IsNullOrEmpty(options.Wreply) && Uri.TryCreate(options.Wreply, UriKind.Absolute, out var wreply)) + { + // Wreply must be a very specific, case sensitive value, so we can't generate it. Instead we generate CallbackPath from it. + options.CallbackPath = PathString.FromUriComponent(wreply); + } + + if (string.IsNullOrEmpty(options.TokenValidationParameters.ValidAudience)) + { + options.TokenValidationParameters.ValidAudience = options.Wtrealm; + } + + if (options.Backchannel == null) + { + options.Backchannel = new HttpClient(options.BackchannelHttpHandler ?? new HttpClientHandler()); + options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core WsFederation handler"); + options.Backchannel.Timeout = options.BackchannelTimeout; + options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB + } + + if (options.ConfigurationManager == null) + { + if (options.Configuration != null) + { + options.ConfigurationManager = new StaticConfigurationManager(options.Configuration); + } + else if (!string.IsNullOrEmpty(options.MetadataAddress)) + { + if (options.RequireHttpsMetadata && !options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("The MetadataAddress must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false."); + } + + options.ConfigurationManager = new ConfigurationManager(options.MetadataAddress, new WsFederationConfigurationRetriever(), + new HttpDocumentRetriever(options.Backchannel) { RequireHttps = options.RequireHttpsMetadata }); + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/baseline.net45.json b/src/Microsoft.AspNetCore.Authentication.WsFederation/baseline.netcore.json similarity index 52% rename from src/Microsoft.AspNetCore.Authentication.Cookies/baseline.net45.json rename to src/Microsoft.AspNetCore.Authentication.WsFederation/baseline.netcore.json index 56e48d3fe..41150cbc0 100644 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/baseline.net45.json +++ b/src/Microsoft.AspNetCore.Authentication.WsFederation/baseline.netcore.json @@ -1,8 +1,8 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Cookies, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.WsFederation, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { - "Name": "Microsoft.AspNetCore.Builder.CookieAppBuilderExtensions", + "Name": "Microsoft.Extensions.DependencyInjection.WsFederationExtensions", "Visibility": "Public", "Kind": "Class", "Abstract": true, @@ -12,14 +12,14 @@ "Members": [ { "Kind": "Method", - "Name": "UseCookieAuthentication", + "Name": "AddWsFederation", "Parameters": [ { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" } ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, "Extension": true, "Visibility": "Public", @@ -27,18 +27,68 @@ }, { "Kind": "Method", - "Name": "UseCookieAuthentication", + "Name": "AddWsFederation", "Parameters": [ { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" }, { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddWsFederation", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddWsFederation", + "Parameters": [ + { + "Name": "builder", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" } ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, "Extension": true, "Visibility": "Public", @@ -48,29 +98,27 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions", + "Name": "Microsoft.AspNetCore.Authentication.WsFederation.AuthenticationFailedContext", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.AuthenticationOptions", - "ImplementedInterfaces": [ - "Microsoft.Extensions.Options.IOptions" - ], + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_CookieName", + "Name": "get_ProtocolMessage", "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CookieName", + "Name": "set_ProtocolMessage", "Parameters": [ { "Name": "value", - "Type": "System.String" + "Type": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage" } ], "ReturnType": "System.Void", @@ -79,61 +127,125 @@ }, { "Kind": "Method", - "Name": "get_CookieDomain", + "Name": "get_Exception", "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "System.Exception", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CookieDomain", + "Name": "set_Exception", "Parameters": [ { "Name": "value", - "Type": "System.String" + "Type": "System.Exception" } ], "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationOptions" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.WsFederation.MessageReceivedContext", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "get_CookiePath", + "Name": "get_ProtocolMessage", "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CookiePath", + "Name": "set_ProtocolMessage", "Parameters": [ { "Name": "value", - "Type": "System.String" + "Type": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage" } ], "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationOptions" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.WsFederation.RedirectContext", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.PropertiesContext", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "get_CookieHttpOnly", + "Name": "get_ProtocolMessage", "Parameters": [], - "ReturnType": "System.Boolean", + "ReturnType": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CookieHttpOnly", + "Name": "set_ProtocolMessage", "Parameters": [ { "Name": "value", - "Type": "System.Boolean" + "Type": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage" } ], "ReturnType": "System.Void", @@ -142,82 +254,179 @@ }, { "Kind": "Method", - "Name": "get_CookieSecure", + "Name": "get_Handled", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.CookieSecurePolicy", + "ReturnType": "System.Boolean", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CookieSecure", + "Name": "HandleResponse", + "Parameters": [], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.CookieSecurePolicy" + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationOptions" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.WsFederation.RemoteSignOutContext", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "get_DataProtectionProvider", + "Name": "get_ProtocolMessage", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider", + "ReturnType": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_DataProtectionProvider", + "Name": "set_ProtocolMessage", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" + "Type": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage" } ], "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationOptions" + }, + { + "Name": "message", + "Type": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.WsFederation.SecurityTokenReceivedContext", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "get_ExpireTimeSpan", + "Name": "get_ProtocolMessage", "Parameters": [], - "ReturnType": "System.TimeSpan", + "ReturnType": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_ExpireTimeSpan", + "Name": "set_ProtocolMessage", "Parameters": [ { "Name": "value", - "Type": "System.TimeSpan" + "Type": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage" } ], "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationOptions" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.WsFederation.SecurityTokenValidatedContext", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "get_SlidingExpiration", + "Name": "get_ProtocolMessage", "Parameters": [], - "ReturnType": "System.Boolean", + "ReturnType": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_SlidingExpiration", + "Name": "set_ProtocolMessage", "Parameters": [ { "Name": "value", - "Type": "System.Boolean" + "Type": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage" } ], "ReturnType": "System.Void", @@ -226,40 +435,78 @@ }, { "Kind": "Method", - "Name": "get_LoginPath", + "Name": "get_SecurityToken", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", + "ReturnType": "Microsoft.IdentityModel.Tokens.SecurityToken", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_LoginPath", + "Name": "set_SecurityToken", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Http.PathString" + "Type": "Microsoft.IdentityModel.Tokens.SecurityToken" } ], "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationOptions" + }, + { + "Name": "principal", + "Type": "System.Security.Claims.ClaimsPrincipal" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationEvents", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "get_LogoutPath", + "Name": "get_OnAuthenticationFailed", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_LogoutPath", + "Name": "set_OnAuthenticationFailed", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Http.PathString" + "Type": "System.Func" } ], "ReturnType": "System.Void", @@ -268,19 +515,19 @@ }, { "Kind": "Method", - "Name": "get_AccessDeniedPath", + "Name": "get_OnMessageReceived", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_AccessDeniedPath", + "Name": "set_OnMessageReceived", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Http.PathString" + "Type": "System.Func" } ], "ReturnType": "System.Void", @@ -289,19 +536,19 @@ }, { "Kind": "Method", - "Name": "get_ReturnUrlParameter", + "Name": "get_OnRedirectToIdentityProvider", "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_ReturnUrlParameter", + "Name": "set_OnRedirectToIdentityProvider", "Parameters": [ { "Name": "value", - "Type": "System.String" + "Type": "System.Func" } ], "ReturnType": "System.Void", @@ -310,19 +557,19 @@ }, { "Kind": "Method", - "Name": "get_Events", + "Name": "get_OnRemoteSignOut", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Events", + "Name": "set_OnRemoteSignOut", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents" + "Type": "System.Func" } ], "ReturnType": "System.Void", @@ -331,19 +578,19 @@ }, { "Kind": "Method", - "Name": "get_TicketDataFormat", + "Name": "get_OnSecurityTokenReceived", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_TicketDataFormat", + "Name": "set_OnSecurityTokenReceived", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISecureDataFormat" + "Type": "System.Func" } ], "ReturnType": "System.Void", @@ -352,19 +599,19 @@ }, { "Kind": "Method", - "Name": "get_SystemClock", + "Name": "get_OnSecurityTokenValidated", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.ISystemClock", + "ReturnType": "System.Func", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_SystemClock", + "Name": "set_OnSecurityTokenValidated", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" + "Type": "System.Func" } ], "ReturnType": "System.Void", @@ -373,175 +620,85 @@ }, { "Kind": "Method", - "Name": "get_CookieManager", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", + "Name": "AuthenticationFailed", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.AuthenticationFailedContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CookieManager", + "Name": "MessageReceived", "Parameters": [ { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager" + "Name": "context", + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.MessageReceivedContext" } ], - "ReturnType": "System.Void", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_SessionStore", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.ITicketStore", + "Name": "RedirectToIdentityProvider", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.RedirectContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_SessionStore", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.ITicketStore" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.ChunkingCookieManager", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_ChunkSize", - "Parameters": [], - "ReturnType": "System.Nullable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ChunkSize", - "Parameters": [ - { - "Name": "value", - "Type": "System.Nullable" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ThrowForPartialCookies", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ThrowForPartialCookies", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetRequestCookie", + "Name": "RemoteSignOut", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "key", - "Type": "System.String" + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.RemoteSignOutContext" } ], - "ReturnType": "System.String", - "Sealed": true, + "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "AppendResponseCookie", + "Name": "SecurityTokenReceived", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "key", - "Type": "System.String" - }, - { - "Name": "value", - "Type": "System.String" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.SecurityTokenReceivedContext" } ], - "ReturnType": "System.Void", - "Sealed": true, + "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "DeleteCookie", + "Name": "SecurityTokenValidated", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "key", - "Type": "System.String" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.SecurityTokenValidatedContext" } ], - "ReturnType": "System.Void", - "Sealed": true, + "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", "Visibility": "Public", "GenericParameter": [] }, @@ -556,7 +713,7 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults", + "Name": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationDefaults", "Visibility": "Public", "Kind": "Class", "Abstract": true, @@ -566,7 +723,7 @@ "Members": [ { "Kind": "Field", - "Name": "CookiePrefix", + "Name": "UserstatePropertiesKey", "Parameters": [], "ReturnType": "System.String", "Static": true, @@ -576,695 +733,148 @@ }, { "Kind": "Field", - "Name": "LoginPath", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Static": true, - "ReadOnly": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Field", - "Name": "LogoutPath", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Static": true, - "ReadOnly": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Field", - "Name": "AccessDeniedPath", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Static": true, - "ReadOnly": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Field", - "Name": "ReturnUrlParameter", + "Name": "AuthenticationScheme", "Parameters": [], "ReturnType": "System.String", "Static": true, - "ReadOnly": true, "Visibility": "Public", - "GenericParameter": [] + "GenericParameter": [], + "Constant": true, + "Literal": "\"WsFederation\"" }, { "Kind": "Field", - "Name": "AuthenticationScheme", + "Name": "DisplayName", "Parameters": [], "ReturnType": "System.String", "Static": true, "Visibility": "Public", "GenericParameter": [], "Constant": true, - "Literal": "\"Cookies\"" + "Literal": "\"WsFederation\"" } ], "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", + "Name": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationHandler", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", - "ImplementedInterfaces": [], + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authentication.IAuthenticationSignOutHandler" + ], "Members": [ { "Kind": "Method", - "Name": "CreateHandler", + "Name": "HandleRequestAsync", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "ReturnType": "System.Threading.Tasks.Task", "Virtual": true, "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "dataProtectionProvider", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" - }, - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "urlEncoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" - } - ], + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IAuthenticationRequestHandler", "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Method", - "Name": "GetRequestCookie", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "key", - "Type": "System.String" - } - ], - "ReturnType": "System.String", + "Name": "get_Events", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationEvents", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "AppendResponseCookie", + "Name": "set_Events", "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "key", - "Type": "System.String" - }, { "Name": "value", - "Type": "System.String" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationEvents" } ], "ReturnType": "System.Void", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "DeleteCookie", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "key", - "Type": "System.String" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" - } - ], - "ReturnType": "System.Void", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.ITicketStore", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "StoreAsync", - "Parameters": [ - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - } - ], - "ReturnType": "System.Threading.Tasks.Task", + "Name": "CreateEventsAsync", + "Parameters": [], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RenewAsync", + "Name": "HandleChallengeAsync", "Parameters": [ { - "Name": "key", - "Type": "System.String" - }, - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RetrieveAsync", - "Parameters": [ - { - "Name": "key", - "Type": "System.String" - } - ], - "ReturnType": "System.Threading.Tasks.Task", + "Name": "HandleRemoteAuthenticateAsync", + "Parameters": [], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RemoveAsync", + "Name": "SignOutAsync", "Parameters": [ { - "Name": "key", - "Type": "System.String" + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.BaseCookieContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_OnValidatePrincipal", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnValidatePrincipal", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnSigningIn", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnSigningIn", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnSignedIn", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnSignedIn", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnSigningOut", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnSigningOut", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnRedirectToLogin", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnRedirectToLogin", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnRedirectToAccessDenied", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnRedirectToAccessDenied", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnRedirectToLogout", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnRedirectToLogout", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnRedirectToReturnUrl", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnRedirectToReturnUrl", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ValidatePrincipal", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieValidatePrincipalContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "SigningIn", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningInContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "SignedIn", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieSignedInContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "SigningOut", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningOutContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToLogout", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToLogin", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToReturnUrl", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RedirectToAccessDenied", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Cookies.BaseCookieContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_RedirectUri", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_RedirectUri", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" - }, - { - "Name": "redirectUri", - "Type": "System.String" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieSignedInContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Cookies.BaseCookieContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Principal", - "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IAuthenticationSignOutHandler", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Properties", + "Name": "HandleRemoteSignOutAsync", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Constructor", "Name": ".ctor", "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" }, { - "Name": "authenticationScheme", - "Type": "System.String" + "Name": "logger", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" }, { - "Name": "principal", - "Type": "System.Security.Claims.ClaimsPrincipal" + "Name": "encoder", + "Type": "System.Text.Encodings.Web.UrlEncoder" }, { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Name": "clock", + "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" } ], "Visibility": "Public", @@ -1274,35 +884,37 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningInContext", + "Name": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationOptions", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Cookies.BaseCookieContext", + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_AuthenticationScheme", + "Name": "Validate", "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Principal", + "Name": "get_Configuration", "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", + "ReturnType": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationConfiguration", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Principal", + "Name": "set_Configuration", "Parameters": [ { "Name": "value", - "Type": "System.Security.Claims.ClaimsPrincipal" + "Type": "Microsoft.IdentityModel.Protocols.WsFederation.WsFederationConfiguration" } ], "ReturnType": "System.Void", @@ -1311,19 +923,19 @@ }, { "Kind": "Method", - "Name": "get_Properties", + "Name": "get_MetadataAddress", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Properties", + "Name": "set_MetadataAddress", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Type": "System.String" } ], "ReturnType": "System.Void", @@ -1332,19 +944,19 @@ }, { "Kind": "Method", - "Name": "get_CookieOptions", + "Name": "get_ConfigurationManager", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.CookieOptions", + "ReturnType": "Microsoft.IdentityModel.Protocols.IConfigurationManager", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CookieOptions", + "Name": "set_ConfigurationManager", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" + "Type": "Microsoft.IdentityModel.Protocols.IConfigurationManager" } ], "ReturnType": "System.Void", @@ -1352,62 +964,41 @@ "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "get_RefreshOnIssuerKeyNotFound", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_RefreshOnIssuerKeyNotFound", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" - }, - { - "Name": "authenticationScheme", - "Type": "System.String" - }, - { - "Name": "principal", - "Type": "System.Security.Claims.ClaimsPrincipal" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - }, - { - "Name": "cookieOptions", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" + "Name": "value", + "Type": "System.Boolean" } ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningOutContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Cookies.BaseCookieContext", - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Method", - "Name": "get_CookieOptions", + "Name": "get_SkipUnrecognizedRequests", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.CookieOptions", + "ReturnType": "System.Boolean", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CookieOptions", + "Name": "set_SkipUnrecognizedRequests", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" + "Type": "System.Boolean" } ], "ReturnType": "System.Void", @@ -1416,19 +1007,19 @@ }, { "Kind": "Method", - "Name": "get_Properties", + "Name": "get_Events", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", + "ReturnType": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationEvents", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Properties", + "Name": "set_Events", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationEvents" } ], "ReturnType": "System.Void", @@ -1436,70 +1027,62 @@ "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "get_SecurityTokenHandlers", + "Parameters": [], + "ReturnType": "System.Collections.Generic.ICollection", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_SecurityTokenHandlers", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - }, - { - "Name": "cookieOptions", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" + "Name": "value", + "Type": "System.Collections.Generic.ICollection" } ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieValidatePrincipalContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.Cookies.BaseCookieContext", - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Method", - "Name": "get_Principal", + "Name": "get_StateDataFormat", "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", + "ReturnType": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", + "Name": "set_StateDataFormat", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Authentication.ISecureDataFormat" + } + ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_ShouldRenew", + "Name": "get_TokenValidationParameters", "Parameters": [], - "ReturnType": "System.Boolean", + "ReturnType": "Microsoft.IdentityModel.Tokens.TokenValidationParameters", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_ShouldRenew", + "Name": "set_TokenValidationParameters", "Parameters": [ { "Name": "value", - "Type": "System.Boolean" + "Type": "Microsoft.IdentityModel.Tokens.TokenValidationParameters" } ], "ReturnType": "System.Void", @@ -1508,11 +1091,19 @@ }, { "Kind": "Method", - "Name": "ReplacePrincipal", + "Name": "get_Wreply", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Wreply", "Parameters": [ { - "Name": "principal", - "Type": "System.Security.Claims.ClaimsPrincipal" + "Name": "value", + "Type": "System.String" } ], "ReturnType": "System.Void", @@ -1521,141 +1112,203 @@ }, { "Kind": "Method", - "Name": "RejectPrincipal", + "Name": "get_SignOutWreply", "Parameters": [], - "ReturnType": "System.Void", + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "set_SignOutWreply", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookieAuthenticationOptions" + "Name": "value", + "Type": "System.String" } ], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Cookies.ICookieAuthenticationEvents", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ + }, + { + "Kind": "Method", + "Name": "get_Wtrealm", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Method", - "Name": "ValidatePrincipal", + "Name": "set_Wtrealm", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieValidatePrincipalContext" + "Name": "value", + "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_UseTokenLifetime", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "SigningIn", + "Name": "set_UseTokenLifetime", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningInContext" + "Name": "value", + "Type": "System.Boolean" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_RequireHttpsMetadata", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "SignedIn", + "Name": "set_RequireHttpsMetadata", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieSignedInContext" + "Name": "value", + "Type": "System.Boolean" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RedirectToLogout", + "Name": "get_AllowUnsolicitedLogins", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_AllowUnsolicitedLogins", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" + "Name": "value", + "Type": "System.Boolean" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_RemoteSignOutPath", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Http.PathString", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RedirectToLogin", + "Name": "set_RemoteSignOutPath", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" + "Name": "value", + "Type": "Microsoft.AspNetCore.Http.PathString" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_SignOutScheme", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RedirectToReturnUrl", + "Name": "set_SignOutScheme", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" + "Name": "value", + "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationPostConfigureOptions", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.Extensions.Options.IPostConfigureOptions" + ], + "Members": [ { "Kind": "Method", - "Name": "RedirectToAccessDenied", + "Name": "PostConfigure", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieRedirectContext" + "Name": "name", + "Type": "System.String" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationOptions" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.Extensions.Options.IPostConfigureOptions", + "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "SigningOut", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningOutContext" + "Name": "dataProtection", + "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" } ], - "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Public", "GenericParameter": [] } ], "GenericParameters": [] } - ], - "SourceFilters": [] + ] } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/AuthAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Authentication/AuthAppBuilderExtensions.cs new file mode 100644 index 000000000..771601ed1 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/AuthAppBuilderExtensions.cs @@ -0,0 +1,29 @@ +// 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; + +namespace Microsoft.AspNetCore.Builder +{ + /// + /// Extension methods to add authentication capabilities to an HTTP application pipeline. + /// + public static class AuthAppBuilderExtensions + { + /// + /// Adds the to the specified , which enables authentication capabilities. + /// + /// The to add the middleware to. + /// A reference to this instance after the operation has completed. + public static IApplicationBuilder UseAuthentication(this IApplicationBuilder app) + { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + return app.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/AuthenticateResult.cs b/src/Microsoft.AspNetCore.Authentication/AuthenticateResult.cs deleted file mode 100644 index 28f116d3d..000000000 --- a/src/Microsoft.AspNetCore.Authentication/AuthenticateResult.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.AspNetCore.Authentication -{ - /// - /// Contains the result of an Authenticate call - /// - public class AuthenticateResult - { - private AuthenticateResult() { } - - /// - /// If a ticket was produced, authenticate was successful. - /// - public bool Succeeded - { - get - { - return Ticket != null; - } - } - - /// - /// The authentication ticket. - /// - public AuthenticationTicket Ticket { get; private set; } - - /// - /// Holds failure information from the authentication. - /// - public Exception Failure { get; private set; } - - /// - /// Indicates that stage of authentication was directly handled by user intervention and no - /// further processing should be attempted. - /// - public bool Handled { get; private set; } - - /// - /// Indicates that this stage of authentication was skipped by user intervention. - /// - public bool Skipped { get; private set; } - - public static AuthenticateResult Success(AuthenticationTicket ticket) - { - if (ticket == null) - { - throw new ArgumentNullException(nameof(ticket)); - } - return new AuthenticateResult() { Ticket = ticket }; - } - - public static AuthenticateResult Handle() - { - return new AuthenticateResult() { Handled = true }; - } - - public static AuthenticateResult Skip() - { - return new AuthenticateResult() { Skipped = true }; - } - - public static AuthenticateResult Fail(Exception failure) - { - return new AuthenticateResult() { Failure = failure }; - } - - public static AuthenticateResult Fail(string failureMessage) - { - return new AuthenticateResult() { Failure = new Exception(failureMessage) }; - } - - } -} diff --git a/src/Microsoft.AspNetCore.Authentication/AuthenticationBuilder.cs b/src/Microsoft.AspNetCore.Authentication/AuthenticationBuilder.cs new file mode 100644 index 000000000..401b1f488 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/AuthenticationBuilder.cs @@ -0,0 +1,120 @@ +// 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.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Authentication +{ + /// + /// Used to configure authentication + /// + public class AuthenticationBuilder + { + /// + /// Constructor. + /// + /// The services being configured. + public AuthenticationBuilder(IServiceCollection services) + => Services = services; + + /// + /// The services being configured. + /// + public virtual IServiceCollection Services { get; } + + + private AuthenticationBuilder AddSchemeHelper(string authenticationScheme, string displayName, Action configureOptions) + where TOptions : class, new() + where THandler : class, IAuthenticationHandler + { + Services.Configure(o => + { + o.AddScheme(authenticationScheme, scheme => { + scheme.HandlerType = typeof(THandler); + scheme.DisplayName = displayName; + }); + }); + if (configureOptions != null) + { + Services.Configure(authenticationScheme, configureOptions); + } + Services.AddTransient(); + return this; + } + + /// + /// Adds a which can be used by . + /// + /// The type to configure the handler."/>. + /// The used to handle this scheme. + /// The name of this scheme. + /// The display name of this scheme. + /// Used to configure the scheme options. + /// The builder. + public virtual AuthenticationBuilder AddScheme(string authenticationScheme, string displayName, Action configureOptions) + where TOptions : AuthenticationSchemeOptions, new() + where THandler : AuthenticationHandler + => AddSchemeHelper(authenticationScheme, displayName, configureOptions); + + /// + /// Adds a which can be used by . + /// + /// The type to configure the handler."/>. + /// The used to handle this scheme. + /// The name of this scheme. + /// Used to configure the scheme options. + /// The builder. + public virtual AuthenticationBuilder AddScheme(string authenticationScheme, Action configureOptions) + where TOptions : AuthenticationSchemeOptions, new() + where THandler : AuthenticationHandler + => AddScheme(authenticationScheme, displayName: null, configureOptions: configureOptions); + + /// + /// Adds a based that supports remote authentication + /// which can be used by . + /// + /// The type to configure the handler."/>. + /// The used to handle this scheme. + /// The name of this scheme. + /// The display name of this scheme. + /// Used to configure the scheme options. + /// The builder. + public virtual AuthenticationBuilder AddRemoteScheme(string authenticationScheme, string displayName, Action configureOptions) + where TOptions : RemoteAuthenticationOptions, new() + where THandler : RemoteAuthenticationHandler + { + Services.TryAddEnumerable(ServiceDescriptor.Singleton, EnsureSignInScheme>()); + return AddScheme(authenticationScheme, displayName, configureOptions: configureOptions); + } + + /// + /// Adds a based authentication handler which can be used to + /// redirect to other authentication schemes. + /// + /// The name of this scheme. + /// The display name of this scheme. + /// Used to configure the scheme options. + /// The builder. + public virtual AuthenticationBuilder AddPolicyScheme(string authenticationScheme, string displayName, Action configureOptions) + => AddSchemeHelper(authenticationScheme, displayName, configureOptions); + + // Used to ensure that there's always a default sign in scheme that's not itself + private class EnsureSignInScheme : IPostConfigureOptions where TOptions : RemoteAuthenticationOptions + { + private readonly AuthenticationOptions _authOptions; + + public EnsureSignInScheme(IOptions authOptions) + { + _authOptions = authOptions.Value; + } + + public void PostConfigure(string name, TOptions options) + { + options.SignInScheme = options.SignInScheme ?? _authOptions.DefaultSignInScheme ?? _authOptions.DefaultScheme; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Authentication/AuthenticationHandler.cs index 8e7e42765..5c9a6473f 100644 --- a/src/Microsoft.AspNetCore.Authentication/AuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Authentication/AuthenticationHandler.cs @@ -4,245 +4,156 @@ using System; using System.Text.Encodings.Web; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.Http.Features.Authentication; -using Microsoft.Extensions.Internal; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Authentication { - /// - /// Base class for the per-request work performed by most authentication middleware. - /// - /// Specifies which type for of AuthenticationOptions property - public abstract class AuthenticationHandler : IAuthenticationHandler where TOptions : AuthenticationOptions + public abstract class AuthenticationHandler : IAuthenticationHandler where TOptions : AuthenticationSchemeOptions, new() { private Task _authenticateTask; - private bool _finishCalled; - - protected bool SignInAccepted { get; set; } - protected bool SignOutAccepted { get; set; } - protected bool ChallengeCalled { get; set; } + public AuthenticationScheme Scheme { get; private set; } + public TOptions Options { get; private set; } protected HttpContext Context { get; private set; } protected HttpRequest Request { - get { return Context.Request; } + get => Context.Request; } protected HttpResponse Response { - get { return Context.Response; } + get => Context.Response; } - protected PathString OriginalPathBase { get; private set; } + protected PathString OriginalPath => Context.Features.Get()?.OriginalPath ?? Request.Path; + + protected PathString OriginalPathBase => Context.Features.Get()?.OriginalPathBase ?? Request.PathBase; - protected PathString OriginalPath { get; private set; } + protected ILogger Logger { get; } - protected ILogger Logger { get; private set; } + protected UrlEncoder UrlEncoder { get; } - protected UrlEncoder UrlEncoder { get; private set; } + protected ISystemClock Clock { get; } - public IAuthenticationHandler PriorHandler { get; set; } + protected IOptionsMonitor OptionsMonitor { get; } + + /// + /// 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. + /// + protected virtual object Events { get; set; } + + protected virtual string ClaimsIssuer => Options.ClaimsIssuer ?? Scheme.Name; protected string CurrentUri { - get - { - return Request.Scheme + "://" + Request.Host + Request.PathBase + Request.Path + Request.QueryString; - } + get => Request.Scheme + "://" + Request.Host + Request.PathBase + Request.Path + Request.QueryString; } - protected TOptions Options { get; private set; } - - protected AuthenticateResult InitializeResult { get; private set; } + protected AuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) + { + Logger = logger.CreateLogger(this.GetType().FullName); + UrlEncoder = encoder; + Clock = clock; + OptionsMonitor = options; + } /// - /// Initialize is called once per request to contextualize this instance with appropriate state. + /// Initialize the handler, resolve the options and validate them. /// - /// The original options passed by the application control behavior - /// The utility object to observe the current request and response - /// The logging factory used to create loggers - /// The . - /// async completion - public async Task InitializeAsync(TOptions options, HttpContext context, ILogger logger, UrlEncoder encoder) + /// + /// + /// + public async Task InitializeAsync(AuthenticationScheme scheme, HttpContext context) { - if (options == null) + if (scheme == null) { - throw new ArgumentNullException(nameof(options)); + throw new ArgumentNullException(nameof(scheme)); } - if (context == null) { throw new ArgumentNullException(nameof(context)); } - if (logger == null) - { - throw new ArgumentNullException(nameof(logger)); - } - - if (encoder == null) - { - throw new ArgumentNullException(nameof(encoder)); - } - - Options = options; + Scheme = scheme; Context = context; - OriginalPathBase = Request.PathBase; - OriginalPath = Request.Path; - Logger = logger; - UrlEncoder = encoder; - - RegisterAuthenticationHandler(); - - Response.OnStarting(OnStartingCallback, this); - - if (ShouldHandleScheme(AuthenticationManager.AutomaticScheme, Options.AutomaticAuthenticate)) - { - InitializeResult = await HandleAuthenticateOnceAsync(); - if (InitializeResult?.Skipped == true || InitializeResult?.Handled == true) - { - return; - } - - if (InitializeResult?.Failure != null) - { - Logger.AuthenticationSchemeNotAuthenticatedWithFailure(Options.AuthenticationScheme, InitializeResult.Failure.Message); - } - - var ticket = InitializeResult?.Ticket; - if (ticket?.Principal != null) - { - Context.User = SecurityHelper.MergeUserPrincipal(Context.User, ticket.Principal); - Logger.UserPrinicpalMerged(Options.AuthenticationScheme); - } - } - } - protected string BuildRedirectUri(string targetPath) - { - return Request.Scheme + "://" + Request.Host + OriginalPathBase + targetPath; - } + Options = OptionsMonitor.Get(Scheme.Name) ?? new TOptions(); + Options.Validate(Scheme.Name); - private static async Task OnStartingCallback(object state) - { - var handler = (AuthenticationHandler)state; - await handler.FinishResponseOnce(); - } - - private async Task FinishResponseOnce() - { - if (!_finishCalled) - { - _finishCalled = true; - await FinishResponseAsync(); - await HandleAutomaticChallengeIfNeeded(); - } + await InitializeEventsAsync(); + await InitializeHandlerAsync(); } /// - /// Hook that is called when the response about to be sent + /// Initializes the events object, called once per request by . /// - /// - protected virtual Task FinishResponseAsync() + protected virtual async Task InitializeEventsAsync() { - return TaskCache.CompletedTask; - } - - private async Task HandleAutomaticChallengeIfNeeded() - { - if (!ChallengeCalled && Options.AutomaticChallenge && Response.StatusCode == 401) + Events = Options.Events; + if (Options.EventsType != null) { - await HandleUnauthorizedAsync(new ChallengeContext(Options.AuthenticationScheme)); + Events = Context.RequestServices.GetRequiredService(Options.EventsType); } + Events = Events ?? await CreateEventsAsync(); } /// - /// Called once after Invoke by AuthenticationMiddleware. + /// Creates a new instance of the events instance. /// - /// async completion - internal async Task TeardownAsync() - { - try - { - await FinishResponseOnce(); - } - finally - { - UnregisterAuthenticationHandler(); - } - } + /// A new instance of the events instance. + protected virtual Task CreateEventsAsync() => Task.FromResult(new object()); /// - /// Called once by common code after initialization. If an authentication middleware responds directly to - /// specifically known paths it must override this virtual, compare the request path to it's known paths, - /// provide any response information as appropriate, and true to stop further processing. + /// Called after options/events have been initialized for the handler to finish initializing itself. /// - /// Returning false will cause the common code to call the next middleware in line. Returning true will - /// cause the common code to begin the async completion journey without calling the rest of the middleware - /// pipeline. - public virtual Task HandleRequestAsync() - { - if (InitializeResult?.Handled == true) - { - return Task.FromResult(true); - } - return Task.FromResult(false); - } + /// A task + protected virtual Task InitializeHandlerAsync() => Task.CompletedTask; - public void GetDescriptions(DescribeSchemesContext describeContext) - { - describeContext.Accept(Options.Description.Items); - - if (PriorHandler != null) - { - PriorHandler.GetDescriptions(describeContext); - } - } + protected string BuildRedirectUri(string targetPath) + => Request.Scheme + "://" + Request.Host + OriginalPathBase + targetPath; - public bool ShouldHandleScheme(string authenticationScheme, bool handleAutomatic) + protected virtual string ResolveTarget(string scheme) { - return string.Equals(Options.AuthenticationScheme, authenticationScheme, StringComparison.Ordinal) || - (handleAutomatic && string.Equals(authenticationScheme, AuthenticationManager.AutomaticScheme, StringComparison.Ordinal)); + var target = scheme ?? Options.ForwardDefaultSelector?.Invoke(Context) ?? Options.ForwardDefault; + + // Prevent self targetting + return string.Equals(target, Scheme.Name, StringComparison.Ordinal) + ? null + : target; } - public async Task AuthenticateAsync(AuthenticateContext context) + public async Task AuthenticateAsync() { - var handled = false; - if (ShouldHandleScheme(context.AuthenticationScheme, Options.AutomaticAuthenticate)) + var target = ResolveTarget(Options.ForwardAuthenticate); + if (target != null) { - // Calling Authenticate more than once should always return the original value. - var result = await HandleAuthenticateOnceAsync(); + return await Context.AuthenticateAsync(target); + } - if (result?.Failure != null) + // Calling Authenticate more than once should always return the original value. + var result = await HandleAuthenticateOnceAsync(); + if (result?.Failure == null) + { + var ticket = result?.Ticket; + if (ticket?.Principal != null) { - context.Failed(result.Failure); + Logger.AuthenticationSchemeAuthenticated(Scheme.Name); } else { - var ticket = result?.Ticket; - if (ticket?.Principal != null) - { - context.Authenticated(ticket.Principal, ticket.Properties.Items, Options.Description.Items); - Logger.AuthenticationSchemeAuthenticated(Options.AuthenticationScheme); - handled = true; - } - else - { - context.NotAuthenticated(); - Logger.AuthenticationSchemeNotAuthenticated(Options.AuthenticationScheme); - } + Logger.AuthenticationSchemeNotAuthenticated(Scheme.Name); } } - - if (PriorHandler != null && !handled) + else { - await PriorHandler.AuthenticateAsync(context); + Logger.AuthenticationSchemeNotAuthenticatedWithFailure(Scheme.Name, result.Failure.Message); } + return result; } /// @@ -278,59 +189,15 @@ protected async Task HandleAuthenticateOnceSafeAsync() protected abstract Task HandleAuthenticateAsync(); - public async Task SignInAsync(SignInContext context) - { - if (ShouldHandleScheme(context.AuthenticationScheme, handleAutomatic: false)) - { - SignInAccepted = true; - await HandleSignInAsync(context); - Logger.AuthenticationSchemeSignedIn(Options.AuthenticationScheme); - context.Accept(); - } - else if (PriorHandler != null) - { - await PriorHandler.SignInAsync(context); - } - } - - protected virtual Task HandleSignInAsync(SignInContext context) - { - return TaskCache.CompletedTask; - } - - public async Task SignOutAsync(SignOutContext context) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - if (ShouldHandleScheme(context.AuthenticationScheme, handleAutomatic: false)) - { - SignOutAccepted = true; - await HandleSignOutAsync(context); - Logger.AuthenticationSchemeSignedOut(Options.AuthenticationScheme); - context.Accept(); - } - else if (PriorHandler != null) - { - await PriorHandler.SignOutAsync(context); - } - } - - protected virtual Task HandleSignOutAsync(SignOutContext context) - { - return TaskCache.CompletedTask; - } - /// - /// Override this method to deal with a challenge that is forbidden. + /// Override this method to handle Forbid. /// - /// - protected virtual Task HandleForbiddenAsync(ChallengeContext context) + /// + /// A Task. + protected virtual Task HandleForbiddenAsync(AuthenticationProperties properties) { Response.StatusCode = 403; - return Task.FromResult(true); + return Task.CompletedTask; } /// @@ -338,59 +205,40 @@ protected virtual Task HandleForbiddenAsync(ChallengeContext context) /// deals an authentication interaction as part of it's request flow. (like adding a response header, or /// changing the 401 result to 302 of a login page or external sign-in location.) /// - /// - /// True if no other handlers should be called - protected virtual Task HandleUnauthorizedAsync(ChallengeContext context) + /// + /// A Task. + protected virtual Task HandleChallengeAsync(AuthenticationProperties properties) { Response.StatusCode = 401; - return Task.FromResult(false); + return Task.CompletedTask; } - public async Task ChallengeAsync(ChallengeContext context) + public async Task ChallengeAsync(AuthenticationProperties properties) { - ChallengeCalled = true; - var handled = false; - if (ShouldHandleScheme(context.AuthenticationScheme, Options.AutomaticChallenge)) + var target = ResolveTarget(Options.ForwardChallenge); + if (target != null) { - switch (context.Behavior) - { - case ChallengeBehavior.Automatic: - // If there is a principal already, invoke the forbidden code path - var result = await HandleAuthenticateOnceSafeAsync(); - if (result?.Ticket?.Principal != null) - { - goto case ChallengeBehavior.Forbidden; - } - goto case ChallengeBehavior.Unauthorized; - case ChallengeBehavior.Unauthorized: - handled = await HandleUnauthorizedAsync(context); - Logger.AuthenticationSchemeChallenged(Options.AuthenticationScheme); - break; - case ChallengeBehavior.Forbidden: - handled = await HandleForbiddenAsync(context); - Logger.AuthenticationSchemeForbidden(Options.AuthenticationScheme); - break; - } - context.Accept(); + await Context.ChallengeAsync(target, properties); + return; } - if (!handled && PriorHandler != null) - { - await PriorHandler.ChallengeAsync(context); - } + properties = properties ?? new AuthenticationProperties(); + await HandleChallengeAsync(properties); + Logger.AuthenticationSchemeChallenged(Scheme.Name); } - private void RegisterAuthenticationHandler() + public async Task ForbidAsync(AuthenticationProperties properties) { - var auth = Context.GetAuthentication(); - PriorHandler = auth.Handler; - auth.Handler = this; - } + var target = ResolveTarget(Options.ForwardForbid); + if (target != null) + { + await Context.ForbidAsync(target, properties); + return; + } - private void UnregisterAuthenticationHandler() - { - var auth = Context.GetAuthentication(); - auth.Handler = PriorHandler; + properties = properties ?? new AuthenticationProperties(); + await HandleForbiddenAsync(properties); + Logger.AuthenticationSchemeForbidden(Scheme.Name); } } } diff --git a/src/Microsoft.AspNetCore.Authentication/AuthenticationMiddleware.cs b/src/Microsoft.AspNetCore.Authentication/AuthenticationMiddleware.cs index a01490c3e..0c62cc3c3 100644 --- a/src/Microsoft.AspNetCore.Authentication/AuthenticationMiddleware.cs +++ b/src/Microsoft.AspNetCore.Authentication/AuthenticationMiddleware.cs @@ -2,90 +2,63 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Text.Encodings.Web; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; +using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Authentication { - public abstract class AuthenticationMiddleware where TOptions : AuthenticationOptions, new() + public class AuthenticationMiddleware { private readonly RequestDelegate _next; - protected AuthenticationMiddleware( - RequestDelegate next, - IOptions options, - ILoggerFactory loggerFactory, - UrlEncoder encoder) + public AuthenticationMiddleware(RequestDelegate next, IAuthenticationSchemeProvider schemes) { if (next == null) { throw new ArgumentNullException(nameof(next)); } - - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - if (encoder == null) - { - throw new ArgumentNullException(nameof(encoder)); - } - - Options = options.Value; - Logger = loggerFactory.CreateLogger(this.GetType().FullName); - UrlEncoder = encoder; - - if (string.IsNullOrEmpty(Options.ClaimsIssuer)) + if (schemes == null) { - // Default to something reasonable - Options.ClaimsIssuer = Options.AuthenticationScheme; + throw new ArgumentNullException(nameof(schemes)); } _next = next; + Schemes = schemes; } - public string AuthenticationScheme { get; set; } - - public TOptions Options { get; set; } - - public ILogger Logger { get; set; } - - public UrlEncoder UrlEncoder { get; set; } + public IAuthenticationSchemeProvider Schemes { get; set; } public async Task Invoke(HttpContext context) { - var handler = CreateHandler(); - await handler.InitializeAsync(Options, context, Logger, UrlEncoder); - try + context.Features.Set(new AuthenticationFeature + { + OriginalPath = context.Request.Path, + OriginalPathBase = context.Request.PathBase + }); + + // Give any IAuthenticationRequestHandler schemes a chance to handle the request + var handlers = context.RequestServices.GetRequiredService(); + foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync()) { - if (!await handler.HandleRequestAsync()) + var handler = await handlers.GetHandlerAsync(context, scheme.Name) as IAuthenticationRequestHandler; + if (handler != null && await handler.HandleRequestAsync()) { - await _next(context); + return; } } - finally + + var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync(); + if (defaultAuthenticate != null) { - try - { - await handler.TeardownAsync(); - } - catch (Exception) + var result = await context.AuthenticateAsync(defaultAuthenticate.Name); + if (result?.Principal != null) { - // Don't mask the original exception, if any + context.User = result.Principal; } } - } - protected abstract AuthenticationHandler CreateHandler(); + await _next(context); + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/AuthenticationOptions.cs b/src/Microsoft.AspNetCore.Authentication/AuthenticationOptions.cs deleted file mode 100644 index 34ec577f1..000000000 --- a/src/Microsoft.AspNetCore.Authentication/AuthenticationOptions.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Http.Authentication; -using System.ComponentModel; - -namespace Microsoft.AspNetCore.Builder -{ - /// - /// Base Options for all authentication middleware. - /// - public abstract class AuthenticationOptions - { - private string _authenticationScheme; - - /// - /// The AuthenticationScheme in the options corresponds to the logical name for a particular authentication scheme. A different - /// value may be assigned in order to use the same authentication middleware type more than once in a pipeline. - /// - public string AuthenticationScheme - { - get { return _authenticationScheme; } - set - { - _authenticationScheme = value; - Description.AuthenticationScheme = value; - } - } - - /// - /// If true the authentication middleware alter the request user coming in. If false the authentication middleware will only provide - /// identity when explicitly indicated by the AuthenticationScheme. - /// - public bool AutomaticAuthenticate { get; set; } - - /// - /// If true the authentication middleware should handle automatic challenge. - /// If false the authentication middleware will only alter responses when explicitly indicated by the AuthenticationScheme. - /// - public bool AutomaticChallenge { get; set; } - - /// - /// Gets or sets the issuer that should be used for any claims that are created - /// - public string ClaimsIssuer { get; set; } - - /// - /// Additional information about the authentication type which is made available to the application. - /// - public AuthenticationDescription Description { get; set; } = new AuthenticationDescription(); - - /// - /// For testing purposes only. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public ISystemClock SystemClock { get; set; } = new SystemClock(); - } -} diff --git a/src/Microsoft.AspNetCore.Authentication/AuthenticationSchemeOptions.cs b/src/Microsoft.AspNetCore.Authentication/AuthenticationSchemeOptions.cs new file mode 100644 index 000000000..a547d203b --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/AuthenticationSchemeOptions.cs @@ -0,0 +1,93 @@ +// 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.Http; + +namespace Microsoft.AspNetCore.Authentication +{ + /// + /// Contains the options used by the . + /// + public class AuthenticationSchemeOptions + { + /// + /// Check that the options are valid. Should throw an exception if things are not ok. + /// + public virtual void Validate() { } + + /// + /// Checks that the options are valid for a specific scheme + /// + /// The scheme being validated. + public virtual void Validate(string scheme) + => Validate(); + + /// + /// Gets or sets the issuer that should be used for any claims that are created + /// + public string ClaimsIssuer { get; set; } + + /// + /// Instance used for events + /// + public object Events { get; set; } + + /// + /// If set, will be used as the service type to get the Events instance instead of the property. + /// + public Type EventsType { get; set; } + + /// + /// If set, this specifies a default scheme that authentication handlers should forward all authentication operations to + /// by default. The default forwarding logic will check the most specific ForwardAuthenticate/Challenge/Forbid/SignIn/SignOut + /// setting first, followed by checking the ForwardDefaultSelector, followed by ForwardDefault. The first non null result + /// will be used as the target scheme to forward to. + /// + public string ForwardDefault { get; set; } + + /// + /// If set, this specifies the target scheme that this scheme should forward AuthenticateAsync calls to. + /// For example Context.AuthenticateAsync("ThisScheme") => Context.AuthenticateAsync("ForwardAuthenticateValue"); + /// Set the target to the current scheme to disable forwarding and allow normal processing. + /// + public string ForwardAuthenticate { get; set; } + + /// + /// If set, this specifies the target scheme that this scheme should forward ChallengeAsync calls to. + /// For example Context.ChallengeAsync("ThisScheme") => Context.ChallengeAsync("ForwardChallengeValue"); + /// Set the target to the current scheme to disable forwarding and allow normal processing. + /// + public string ForwardChallenge { get; set; } + + /// + /// If set, this specifies the target scheme that this scheme should forward ForbidAsync calls to. + /// For example Context.ForbidAsync("ThisScheme") => Context.ForbidAsync("ForwardForbidValue"); + /// Set the target to the current scheme to disable forwarding and allow normal processing. + /// + public string ForwardForbid { get; set; } + + /// + /// If set, this specifies the target scheme that this scheme should forward SignInAsync calls to. + /// For example Context.SignInAsync("ThisScheme") => Context.SignInAsync("ForwardSignInValue"); + /// Set the target to the current scheme to disable forwarding and allow normal processing. + /// + public string ForwardSignIn { get; set; } + + /// + /// If set, this specifies the target scheme that this scheme should forward SignOutAsync calls to. + /// For example Context.SignOutAsync("ThisScheme") => Context.SignInAsync("ForwardSignOutValue"); + /// Set the target to the current scheme to disable forwarding and allow normal processing. + /// + public string ForwardSignOut { get; set; } + + /// + /// Used to select a default scheme for the current request that authentication handlers should forward all authentication operations to + /// by default. The default forwarding logic will check the most specific ForwardAuthenticate/Challenge/Forbid/SignIn/SignOut + /// setting first, followed by checking the ForwardDefaultSelector, followed by ForwardDefault. The first non null result + /// will be used as the target scheme to forward to. + /// + public Func ForwardDefaultSelector { get; set; } + + } +} diff --git a/src/Microsoft.AspNetCore.Authentication/AuthenticationServiceCollectionExtensions.cs b/src/Microsoft.AspNetCore.Authentication/AuthenticationServiceCollectionExtensions.cs index 2aa320ae2..6c381b84a 100644 --- a/src/Microsoft.AspNetCore.Authentication/AuthenticationServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNetCore.Authentication/AuthenticationServiceCollectionExtensions.cs @@ -3,6 +3,8 @@ using System; using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; namespace Microsoft.Extensions.DependencyInjection { @@ -11,31 +13,24 @@ namespace Microsoft.Extensions.DependencyInjection /// public static class AuthenticationServiceCollectionExtensions { - /// - /// Adds authentication services to the specified . - /// - /// The to add services to. - /// The so that additional calls can be chained. - public static IServiceCollection AddAuthentication(this IServiceCollection services) + public static AuthenticationBuilder AddAuthentication(this IServiceCollection services) { if (services == null) { throw new ArgumentNullException(nameof(services)); } - services.AddWebEncoders(); + services.AddAuthenticationCore(); services.AddDataProtection(); - return services; + services.AddWebEncoders(); + services.TryAddSingleton(); + return new AuthenticationBuilder(services); } - /// - /// Adds authentication services to the specified . - /// - /// The to add services to. - /// An action delegate to configure the provided . - /// The so that additional calls can be chained. - public static IServiceCollection AddAuthentication(this IServiceCollection services, Action configureOptions) - { + public static AuthenticationBuilder AddAuthentication(this IServiceCollection services, string defaultScheme) + => services.AddAuthentication(o => o.DefaultScheme = defaultScheme); + + public static AuthenticationBuilder AddAuthentication(this IServiceCollection services, Action configureOptions) { if (services == null) { throw new ArgumentNullException(nameof(services)); @@ -46,8 +41,26 @@ public static IServiceCollection AddAuthentication(this IServiceCollection servi throw new ArgumentNullException(nameof(configureOptions)); } + var builder = services.AddAuthentication(); services.Configure(configureOptions); - return services.AddAuthentication(); + return builder; + } + + // Used to ensure that there's always a sign in scheme + private class EnsureSignInScheme : IPostConfigureOptions where TOptions : RemoteAuthenticationOptions + { + private readonly AuthenticationOptions _authOptions; + + public EnsureSignInScheme(IOptions authOptions) + { + _authOptions = authOptions.Value; + } + + public void PostConfigure(string name, TOptions options) + { + options.SignInScheme = options.SignInScheme ?? _authOptions.DefaultSignInScheme; + } } + } } diff --git a/src/Microsoft.AspNetCore.Authentication/AuthenticationTicket.cs b/src/Microsoft.AspNetCore.Authentication/AuthenticationTicket.cs deleted file mode 100644 index 1d56a8fb3..000000000 --- a/src/Microsoft.AspNetCore.Authentication/AuthenticationTicket.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Security.Claims; -using Microsoft.AspNetCore.Http.Authentication; - -namespace Microsoft.AspNetCore.Authentication -{ - /// - /// Contains user identity information as well as additional authentication state. - /// - public class AuthenticationTicket - { - /// - /// Initializes a new instance of the class - /// - /// the that represents the authenticated user. - /// additional properties that can be consumed by the user or runtime. - /// the authentication middleware that was responsible for this ticket. - public AuthenticationTicket(ClaimsPrincipal principal, AuthenticationProperties properties, string authenticationScheme) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - AuthenticationScheme = authenticationScheme; - Principal = principal; - Properties = properties ?? new AuthenticationProperties(); - } - - /// - /// Gets the authentication type. - /// - public string AuthenticationScheme { get; private set; } - - /// - /// Gets the claims-principal with authenticated user identities. - /// - public ClaimsPrincipal Principal{ get; private set; } - - /// - /// Additional state values for the authentication session. - /// - public AuthenticationProperties Properties { get; private set; } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationAppBuilderExtensions.cs deleted file mode 100644 index 1edb4a0f4..000000000 --- a/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationAppBuilderExtensions.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Security.Claims; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication; -using Microsoft.Extensions.Options; - -namespace Microsoft.AspNetCore.Builder -{ - /// - /// Extension methods to add claims transformation capabilities to an HTTP application pipeline. - /// - public static class ClaimsTransformationAppBuilderExtensions - { - /// - /// Adds the middleware to the specified , which enables claims transformation capabilities. - /// - /// The to add the middleware to. - /// A reference to this instance after the operation has completed. - public static IApplicationBuilder UseClaimsTransformation(this IApplicationBuilder app) - { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - - return app.UseMiddleware(); - } - - /// - /// Adds the middleware to the specified , which enables claims transformation capabilities. - /// - /// The to add the middleware to. - /// A function that asynchronously transforms one to another. - /// A reference to this instance after the operation has completed. - public static IApplicationBuilder UseClaimsTransformation(this IApplicationBuilder app, Func> transform) - { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - if (transform == null) - { - throw new ArgumentNullException(nameof(transform)); - } - - return app.UseClaimsTransformation(new ClaimsTransformationOptions - { - Transformer = new ClaimsTransformer { OnTransform = transform } - }); - } - - /// - /// Adds the middleware to the specified , which enables claims transformation capabilities. - /// - /// The to add the middleware to. - /// The to configure the middleware with. - /// A reference to this instance after the operation has completed. - public static IApplicationBuilder UseClaimsTransformation(this IApplicationBuilder app, ClaimsTransformationOptions options) - { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - return app.UseMiddleware(Options.Create(options)); - } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationContext.cs b/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationContext.cs deleted file mode 100644 index 3c363ca98..000000000 --- a/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationContext.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.AspNetCore.Http; -using System.Security.Claims; - -namespace Microsoft.AspNetCore.Authentication -{ - public class ClaimsTransformationContext - { - public ClaimsTransformationContext(HttpContext context) - { - Context = context; - } - public HttpContext Context { get; } - public ClaimsPrincipal Principal { get; set; } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationHandler.cs b/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationHandler.cs deleted file mode 100644 index 27965dbf4..000000000 --- a/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationHandler.cs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features.Authentication; -using Microsoft.Extensions.Internal; - -namespace Microsoft.AspNetCore.Authentication -{ - /// - /// Handler that applies ClaimsTransformation to authentication - /// - public class ClaimsTransformationHandler : IAuthenticationHandler - { - private readonly IClaimsTransformer _transform; - private readonly HttpContext _httpContext; - - public ClaimsTransformationHandler(IClaimsTransformer transform, HttpContext httpContext) - { - _transform = transform; - _httpContext = httpContext; - } - - public IAuthenticationHandler PriorHandler { get; set; } - - public async Task AuthenticateAsync(AuthenticateContext context) - { - if (PriorHandler != null) - { - await PriorHandler.AuthenticateAsync(context); - if (_transform != null && context?.Principal != null) - { - var transformationContext = new ClaimsTransformationContext(_httpContext) - { - Principal = context.Principal - }; - context.Authenticated( - await _transform.TransformAsync(transformationContext), - context.Properties, - context.Description); - } - } - } - - public Task ChallengeAsync(ChallengeContext context) - { - if (PriorHandler != null) - { - return PriorHandler.ChallengeAsync(context); - } - return TaskCache.CompletedTask; - } - - public void GetDescriptions(DescribeSchemesContext context) - { - if (PriorHandler != null) - { - PriorHandler.GetDescriptions(context); - } - } - - public Task SignInAsync(SignInContext context) - { - if (PriorHandler != null) - { - return PriorHandler.SignInAsync(context); - } - return TaskCache.CompletedTask; - } - - public Task SignOutAsync(SignOutContext context) - { - if (PriorHandler != null) - { - return PriorHandler.SignOutAsync(context); - } - return TaskCache.CompletedTask; - } - - public void RegisterAuthenticationHandler(IHttpAuthenticationFeature auth) - { - PriorHandler = auth.Handler; - auth.Handler = this; - } - - public void UnregisterAuthenticationHandler(IHttpAuthenticationFeature auth) - { - auth.Handler = PriorHandler; - } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationMiddleware.cs b/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationMiddleware.cs deleted file mode 100644 index 53f6a07a8..000000000 --- a/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationMiddleware.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Options; - -namespace Microsoft.AspNetCore.Authentication -{ - public class ClaimsTransformationMiddleware - { - private readonly RequestDelegate _next; - - public ClaimsTransformationMiddleware( - RequestDelegate next, - IOptions options) - { - if (next == null) - { - throw new ArgumentNullException(nameof(next)); - } - - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - Options = options.Value; - _next = next; - } - - public ClaimsTransformationOptions Options { get; set; } - - public async Task Invoke(HttpContext context) - { - var handler = new ClaimsTransformationHandler(Options.Transformer, context); - handler.RegisterAuthenticationHandler(context.GetAuthentication()); - try - { - if (Options.Transformer != null) - { - var transformationContext = new ClaimsTransformationContext(context) - { - Principal = context.User - }; - context.User = await Options.Transformer.TransformAsync(transformationContext); - } - await _next(context); - } - finally - { - handler.UnregisterAuthenticationHandler(context.GetAuthentication()); - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationOptions.cs b/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationOptions.cs deleted file mode 100644 index 70a76f27c..000000000 --- a/src/Microsoft.AspNetCore.Authentication/ClaimsTransformationOptions.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Authentication; - -namespace Microsoft.AspNetCore.Builder -{ - /// - /// Contains the options used by the . - /// - public class ClaimsTransformationOptions - { - /// - /// Responsible for transforming the claims principal. - /// - public IClaimsTransformer Transformer { get; set; } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication/ClaimsTransformer.cs b/src/Microsoft.AspNetCore.Authentication/ClaimsTransformer.cs deleted file mode 100644 index db05db0e5..000000000 --- a/src/Microsoft.AspNetCore.Authentication/ClaimsTransformer.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Security.Claims; -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Authentication -{ - public class ClaimsTransformer : IClaimsTransformer - { - public Func> OnTransform { get; set; } - - public virtual Task TransformAsync(ClaimsTransformationContext context) - { - return OnTransform?.Invoke(context) ?? Task.FromResult(context.Principal); - } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication/DataHandler/IDataSerializer.cs b/src/Microsoft.AspNetCore.Authentication/Data/IDataSerializer.cs similarity index 100% rename from src/Microsoft.AspNetCore.Authentication/DataHandler/IDataSerializer.cs rename to src/Microsoft.AspNetCore.Authentication/Data/IDataSerializer.cs diff --git a/src/Microsoft.AspNetCore.Authentication/DataHandler/ISecureDataFormat.cs b/src/Microsoft.AspNetCore.Authentication/Data/ISecureDataFormat.cs similarity index 100% rename from src/Microsoft.AspNetCore.Authentication/DataHandler/ISecureDataFormat.cs rename to src/Microsoft.AspNetCore.Authentication/Data/ISecureDataFormat.cs diff --git a/src/Microsoft.AspNetCore.Authentication/DataHandler/PropertiesDataFormat.cs b/src/Microsoft.AspNetCore.Authentication/Data/PropertiesDataFormat.cs similarity index 100% rename from src/Microsoft.AspNetCore.Authentication/DataHandler/PropertiesDataFormat.cs rename to src/Microsoft.AspNetCore.Authentication/Data/PropertiesDataFormat.cs diff --git a/src/Microsoft.AspNetCore.Authentication/DataHandler/PropertiesSerializer.cs b/src/Microsoft.AspNetCore.Authentication/Data/PropertiesSerializer.cs similarity index 100% rename from src/Microsoft.AspNetCore.Authentication/DataHandler/PropertiesSerializer.cs rename to src/Microsoft.AspNetCore.Authentication/Data/PropertiesSerializer.cs diff --git a/src/Microsoft.AspNetCore.Authentication/DataHandler/SecureDataFormat.cs b/src/Microsoft.AspNetCore.Authentication/Data/SecureDataFormat.cs similarity index 100% rename from src/Microsoft.AspNetCore.Authentication/DataHandler/SecureDataFormat.cs rename to src/Microsoft.AspNetCore.Authentication/Data/SecureDataFormat.cs diff --git a/src/Microsoft.AspNetCore.Authentication/DataHandler/TextEncoder.cs b/src/Microsoft.AspNetCore.Authentication/Data/TextEncoder.cs similarity index 89% rename from src/Microsoft.AspNetCore.Authentication/DataHandler/TextEncoder.cs rename to src/Microsoft.AspNetCore.Authentication/Data/TextEncoder.cs index c0663295c..1f7ecc718 100644 --- a/src/Microsoft.AspNetCore.Authentication/DataHandler/TextEncoder.cs +++ b/src/Microsoft.AspNetCore.Authentication/Data/TextEncoder.cs @@ -13,7 +13,7 @@ public static class Base64UrlTextEncoder /// Base64 encoded string modified with non-URL encodable characters public static string Encode(byte[] data) { - return WebUtilities.Base64UrlTextEncoder.Encode(data); + return WebUtilities.WebEncoders.Base64UrlEncode(data); } /// @@ -24,7 +24,7 @@ public static string Encode(byte[] data) /// The decoded data. public static byte[] Decode(string text) { - return WebUtilities.Base64UrlTextEncoder.Decode(text); + return WebUtilities.WebEncoders.Base64UrlDecode(text); } } } diff --git a/src/Microsoft.AspNetCore.Authentication/DataHandler/TicketDataFormat.cs b/src/Microsoft.AspNetCore.Authentication/Data/TicketDataFormat.cs similarity index 100% rename from src/Microsoft.AspNetCore.Authentication/DataHandler/TicketDataFormat.cs rename to src/Microsoft.AspNetCore.Authentication/Data/TicketDataFormat.cs diff --git a/src/Microsoft.AspNetCore.Authentication/DataHandler/TicketSerializer.cs b/src/Microsoft.AspNetCore.Authentication/Data/TicketSerializer.cs similarity index 100% rename from src/Microsoft.AspNetCore.Authentication/DataHandler/TicketSerializer.cs rename to src/Microsoft.AspNetCore.Authentication/Data/TicketSerializer.cs diff --git a/src/Microsoft.AspNetCore.Authentication/Events/AccessDeniedContext.cs b/src/Microsoft.AspNetCore.Authentication/Events/AccessDeniedContext.cs new file mode 100644 index 000000000..f01d69453 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/Events/AccessDeniedContext.cs @@ -0,0 +1,44 @@ +// 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 +{ + /// + /// Provides access denied failure context information to handler providers. + /// + public class AccessDeniedContext : HandleRequestContext + { + public AccessDeniedContext( + HttpContext context, + AuthenticationScheme scheme, + RemoteAuthenticationOptions options) + : base(context, scheme, options) + { + } + + /// + /// Gets or sets the endpoint path the user agent will be redirected to. + /// By default, this property is set to . + /// + public PathString AccessDeniedPath { get; set; } + + /// + /// Additional state values for the authentication session. + /// + public AuthenticationProperties Properties { get; set; } + + /// + /// Gets or sets the return URL that will be flowed up to the access denied page. + /// If is not set, this property is not used. + /// + public string ReturnUrl { get; set; } + + /// + /// Gets or sets the parameter name that will be used to flow the return URL. + /// By default, this property is set to . + /// + public string ReturnUrlParameter { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication/Events/BaseContext.cs b/src/Microsoft.AspNetCore.Authentication/Events/BaseContext.cs index 10b3325d4..915fc2377 100644 --- a/src/Microsoft.AspNetCore.Authentication/Events/BaseContext.cs +++ b/src/Microsoft.AspNetCore.Authentication/Events/BaseContext.cs @@ -1,27 +1,65 @@ // 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.Http; namespace Microsoft.AspNetCore.Authentication { - public abstract class BaseContext + /// + /// Base class used by other context classes. + /// + public abstract class BaseContext where TOptions : AuthenticationSchemeOptions { - protected BaseContext(HttpContext context) + /// + /// Constructor. + /// + /// The context. + /// The authentication scheme. + /// The authentication options associated with the scheme. + protected BaseContext(HttpContext context, AuthenticationScheme scheme, TOptions options) { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + if (scheme == null) + { + throw new ArgumentNullException(nameof(scheme)); + } + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + HttpContext = context; + Scheme = scheme; + Options = options; } - public HttpContext HttpContext { get; private set; } + /// + /// The authentication scheme. + /// + public AuthenticationScheme Scheme { get; } - public HttpRequest Request - { - get { return HttpContext.Request; } - } + /// + /// Gets the authentication options associated with the scheme. + /// + public TOptions Options { get; } - public HttpResponse Response - { - get { return HttpContext.Response; } - } + /// + /// The context. + /// + public HttpContext HttpContext { get; } + + /// + /// The request. + /// + public HttpRequest Request => HttpContext.Request; + + /// + /// The response. + /// + public HttpResponse Response => HttpContext.Response; } } diff --git a/src/Microsoft.AspNetCore.Authentication/Events/BaseControlContext.cs b/src/Microsoft.AspNetCore.Authentication/Events/BaseControlContext.cs deleted file mode 100644 index 4039a0560..000000000 --- a/src/Microsoft.AspNetCore.Authentication/Events/BaseControlContext.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Authentication -{ - public class BaseControlContext : BaseContext - { - protected BaseControlContext(HttpContext context) : base(context) - { - } - - public EventResultState State { get; set; } - - public bool HandledResponse - { - get { return State == EventResultState.HandledResponse; } - } - - public bool Skipped - { - get { return State == EventResultState.Skipped; } - } - - /// - /// Discontinue all processing for this request and return to the client. - /// The caller is responsible for generating the full response. - /// Set the to trigger SignIn. - /// - public void HandleResponse() - { - State = EventResultState.HandledResponse; - } - - /// - /// Discontinue processing the request in the current middleware and pass control to the next one. - /// SignIn will not be called. - /// - public void SkipToNextMiddleware() - { - State = EventResultState.Skipped; - } - - /// - /// Gets or set the to return if this event signals it handled the event. - /// - public AuthenticationTicket Ticket { get; set; } - - public bool CheckEventResult(out AuthenticateResult result) - { - if (HandledResponse) - { - if (Ticket == null) - { - result = AuthenticateResult.Handle(); - } - else - { - result = AuthenticateResult.Success(Ticket); - } - return true; - } - else if (Skipped) - { - result = AuthenticateResult.Skip(); - return true; - } - result = null; - return false; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/Events/EventResultState.cs b/src/Microsoft.AspNetCore.Authentication/Events/EventResultState.cs deleted file mode 100644 index b11dec93f..000000000 --- a/src/Microsoft.AspNetCore.Authentication/Events/EventResultState.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.Authentication -{ - public enum EventResultState - { - /// - /// Continue with normal processing. - /// - Continue, - - /// - /// Discontinue processing the request in the current middleware and pass control to the next one. - /// - Skipped, - - /// - /// Discontinue all processing for this request. - /// - HandledResponse - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/Events/FailureContext.cs b/src/Microsoft.AspNetCore.Authentication/Events/FailureContext.cs deleted file mode 100644 index 35af9cee3..000000000 --- a/src/Microsoft.AspNetCore.Authentication/Events/FailureContext.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Authentication -{ - /// - /// Provides failure context information to middleware providers. - /// - public class FailureContext : BaseControlContext - { - public FailureContext(HttpContext context, Exception failure) - : base(context) - { - Failure = failure; - } - - /// - /// User friendly error message for the error. - /// - public Exception Failure { get; set; } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication/Events/HandleRequestContext.cs b/src/Microsoft.AspNetCore.Authentication/Events/HandleRequestContext.cs new file mode 100644 index 000000000..52dd9ce12 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/Events/HandleRequestContext.cs @@ -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 Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Authentication +{ + public class HandleRequestContext : BaseContext where TOptions : AuthenticationSchemeOptions + { + protected HandleRequestContext( + HttpContext context, + AuthenticationScheme scheme, + TOptions options) + : base(context, scheme, options) { } + + /// + /// The which is used by the handler. + /// + public HandleRequestResult Result { get; protected set; } + + /// + /// Discontinue all processing for this request and return to the client. + /// The caller is responsible for generating the full response. + /// + public void HandleResponse() => Result = HandleRequestResult.Handle(); + + /// + /// Discontinue processing the request in the current handler. + /// + public void SkipHandler() => Result = HandleRequestResult.SkipHandler(); + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/Events/IRemoteAuthenticationEvents.cs b/src/Microsoft.AspNetCore.Authentication/Events/IRemoteAuthenticationEvents.cs deleted file mode 100644 index e2109a065..000000000 --- a/src/Microsoft.AspNetCore.Authentication/Events/IRemoteAuthenticationEvents.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Authentication -{ - public interface IRemoteAuthenticationEvents - { - /// - /// Invoked when the remote authentication process has an error. - /// - Task RemoteFailure(FailureContext context); - - /// - /// Invoked before sign in. - /// - Task TicketReceived(TicketReceivedContext context); - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/Events/PrincipalContext.cs b/src/Microsoft.AspNetCore.Authentication/Events/PrincipalContext.cs new file mode 100644 index 000000000..8bf40760a --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/Events/PrincipalContext.cs @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Security.Claims; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Authentication +{ + /// + /// Base context for authentication events which deal with a ClaimsPrincipal. + /// + public abstract class PrincipalContext : PropertiesContext where TOptions : AuthenticationSchemeOptions + { + /// + /// Constructor. + /// + /// The context. + /// The authentication scheme. + /// The authentication options associated with the scheme. + /// The authentication properties. + protected PrincipalContext(HttpContext context, AuthenticationScheme scheme, TOptions options, AuthenticationProperties properties) + : base(context, scheme, options, properties) { } + + /// + /// Gets the containing the user claims. + /// + public virtual ClaimsPrincipal Principal { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication/Events/PropertiesContext.cs b/src/Microsoft.AspNetCore.Authentication/Events/PropertiesContext.cs new file mode 100644 index 000000000..f1730d0d7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/Events/PropertiesContext.cs @@ -0,0 +1,31 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Authentication +{ + /// + /// Base context for authentication events which contain . + /// + public abstract class PropertiesContext : BaseContext where TOptions : AuthenticationSchemeOptions + { + /// + /// Constructor. + /// + /// The context. + /// The authentication scheme. + /// The authentication options associated with the scheme. + /// The authentication properties. + protected PropertiesContext(HttpContext context, AuthenticationScheme scheme, TOptions options, AuthenticationProperties properties) + : base(context, scheme, options) + { + Properties = properties ?? new AuthenticationProperties(); + } + + /// + /// Gets or sets the . + /// + public virtual AuthenticationProperties Properties { get; protected set; } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieRedirectContext.cs b/src/Microsoft.AspNetCore.Authentication/Events/RedirectContext.cs similarity index 56% rename from src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieRedirectContext.cs rename to src/Microsoft.AspNetCore.Authentication/Events/RedirectContext.cs index 2cbb5ff09..dac24cafa 100644 --- a/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieRedirectContext.cs +++ b/src/Microsoft.AspNetCore.Authentication/Events/RedirectContext.cs @@ -1,36 +1,38 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; -namespace Microsoft.AspNetCore.Authentication.Cookies +namespace Microsoft.AspNetCore.Authentication { /// - /// Context passed when a Challenge, SignIn, or SignOut causes a redirect in the cookie middleware + /// Context passed for redirect events. /// - public class CookieRedirectContext : BaseCookieContext + public class RedirectContext : PropertiesContext where TOptions : AuthenticationSchemeOptions { /// /// Creates a new context object. /// /// The HTTP request context - /// The cookie middleware options + /// The scheme data + /// The handler options /// The initial redirect URI /// The . - public CookieRedirectContext(HttpContext context, CookieAuthenticationOptions options, string redirectUri, AuthenticationProperties properties) - : base(context, options) + public RedirectContext( + HttpContext context, + AuthenticationScheme scheme, + TOptions options, + AuthenticationProperties properties, + string redirectUri) + : base(context, scheme, options, properties) { - RedirectUri = redirectUri; Properties = properties; + RedirectUri = redirectUri; } /// /// Gets or Sets the URI used for the redirect operation. /// public string RedirectUri { get; set; } - - public AuthenticationProperties Properties { get; } } } diff --git a/src/Microsoft.AspNetCore.Authentication/Events/RemoteAuthenticationContext.cs b/src/Microsoft.AspNetCore.Authentication/Events/RemoteAuthenticationContext.cs new file mode 100644 index 000000000..b7a016879 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/Events/RemoteAuthenticationContext.cs @@ -0,0 +1,49 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Security.Claims; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Authentication +{ + /// + /// Base context for remote authentication. + /// + public abstract class RemoteAuthenticationContext : HandleRequestContext where TOptions : AuthenticationSchemeOptions + { + /// + /// Constructor. + /// + /// The context. + /// The authentication scheme. + /// The authentication options associated with the scheme. + /// The authentication properties. + protected RemoteAuthenticationContext( + HttpContext context, + AuthenticationScheme scheme, + TOptions options, + AuthenticationProperties properties) + : base(context, scheme, options) + => Properties = properties ?? new AuthenticationProperties(); + + /// + /// Gets the containing the user claims. + /// + public ClaimsPrincipal Principal { get; set; } + + /// + /// Gets or sets the . + /// + public virtual AuthenticationProperties Properties { get; set; } + + /// + /// Calls success creating a ticket with the and . + /// + public void Success() => Result = HandleRequestResult.Success(new AuthenticationTicket(Principal, Properties, Scheme.Name)); + + public void Fail(Exception failure) => Result = HandleRequestResult.Fail(failure); + + public void Fail(string failureMessage) => Result = HandleRequestResult.Fail(failureMessage); + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/Events/RemoteAuthenticationEvents.cs b/src/Microsoft.AspNetCore.Authentication/Events/RemoteAuthenticationEvents.cs index 6e7d6a35c..be4c6ab49 100644 --- a/src/Microsoft.AspNetCore.Authentication/Events/RemoteAuthenticationEvents.cs +++ b/src/Microsoft.AspNetCore.Authentication/Events/RemoteAuthenticationEvents.cs @@ -3,20 +3,25 @@ using System; using System.Threading.Tasks; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Authentication { - public class RemoteAuthenticationEvents : IRemoteAuthenticationEvents + public class RemoteAuthenticationEvents { - public Func OnRemoteFailure { get; set; } = context => TaskCache.CompletedTask; + public Func OnAccessDenied { get; set; } = context => Task.CompletedTask; + public Func OnRemoteFailure { get; set; } = context => Task.CompletedTask; - public Func OnTicketReceived { get; set; } = context => TaskCache.CompletedTask; + public Func OnTicketReceived { get; set; } = context => Task.CompletedTask; /// - /// Invoked when there is a remote failure + /// Invoked when an access denied error was returned by the remote server. /// - public virtual Task RemoteFailure(FailureContext context) => OnRemoteFailure(context); + public virtual Task AccessDenied(AccessDeniedContext context) => OnAccessDenied(context); + + /// + /// Invoked when there is a remote failure. + /// + public virtual Task RemoteFailure(RemoteFailureContext context) => OnRemoteFailure(context); /// /// Invoked after the remote ticket has been received. diff --git a/src/Microsoft.AspNetCore.Authentication/Events/RemoteFailureContext.cs b/src/Microsoft.AspNetCore.Authentication/Events/RemoteFailureContext.cs new file mode 100644 index 000000000..6b3598f40 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/Events/RemoteFailureContext.cs @@ -0,0 +1,34 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Authentication +{ + /// + /// Provides failure context information to handler providers. + /// + public class RemoteFailureContext : HandleRequestContext + { + public RemoteFailureContext( + HttpContext context, + AuthenticationScheme scheme, + RemoteAuthenticationOptions options, + Exception failure) + : base(context, scheme, options) + { + Failure = failure; + } + + /// + /// User friendly error message for the error. + /// + public Exception Failure { get; set; } + + /// + /// Additional state values for the authentication session. + /// + public AuthenticationProperties Properties { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication/Events/ResultContext.cs b/src/Microsoft.AspNetCore.Authentication/Events/ResultContext.cs new file mode 100644 index 000000000..12b21f4bf --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/Events/ResultContext.cs @@ -0,0 +1,65 @@ +// 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 +{ + /// + /// Base context for events that produce AuthenticateResults. + /// + public abstract class ResultContext : BaseContext where TOptions : AuthenticationSchemeOptions + { + /// + /// Constructor. + /// + /// The context. + /// The authentication scheme. + /// The authentication options associated with the scheme. + protected ResultContext(HttpContext context, AuthenticationScheme scheme, TOptions options) + : base(context, scheme, options) { } + + /// + /// Gets or sets the containing the user claims. + /// + public ClaimsPrincipal Principal { get; set; } + + private AuthenticationProperties _properties; + /// + /// Gets or sets the . + /// + public AuthenticationProperties Properties { + get => _properties ?? (_properties = new AuthenticationProperties()); + set => _properties = value; + } + + /// + /// Gets the result. + /// + public AuthenticateResult Result { get; private set; } + + /// + /// Calls success creating a ticket with the and . + /// + public void Success() => Result = HandleRequestResult.Success(new AuthenticationTicket(Principal, Properties, Scheme.Name)); + + /// + /// Indicates that there was no information returned for this authentication scheme. + /// + public void NoResult() => Result = AuthenticateResult.NoResult(); + + /// + /// Indicates that there was a failure during authentication. + /// + /// + public void Fail(Exception failure) => Result = AuthenticateResult.Fail(failure); + + /// + /// Indicates that there was a failure during authentication. + /// + /// + public void Fail(string failureMessage) => Result = AuthenticateResult.Fail(failureMessage); + } +} diff --git a/src/Microsoft.AspNetCore.Authentication/Events/TicketReceivedContext.cs b/src/Microsoft.AspNetCore.Authentication/Events/TicketReceivedContext.cs index 5d5fd4883..51b77a37f 100644 --- a/src/Microsoft.AspNetCore.Authentication/Events/TicketReceivedContext.cs +++ b/src/Microsoft.AspNetCore.Authentication/Events/TicketReceivedContext.cs @@ -2,32 +2,22 @@ // 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.Builder; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; namespace Microsoft.AspNetCore.Authentication { /// - /// Provides context information to middleware providers. + /// Provides context information to handler providers. /// - public class TicketReceivedContext : BaseControlContext + public class TicketReceivedContext : RemoteAuthenticationContext { - public TicketReceivedContext(HttpContext context, RemoteAuthenticationOptions options, AuthenticationTicket ticket) - : base(context) - { - Options = options; - Ticket = ticket; - if (ticket != null) - { - Principal = ticket.Principal; - Properties = ticket.Properties; - } - } - - public ClaimsPrincipal Principal { get; set; } - public AuthenticationProperties Properties { get; set; } - public RemoteAuthenticationOptions Options { get; set; } + public TicketReceivedContext( + HttpContext context, + AuthenticationScheme scheme, + RemoteAuthenticationOptions options, + AuthenticationTicket ticket) + : base(context, scheme, options, ticket?.Properties) + => Principal = ticket?.Principal; public string ReturnUri { get; set; } } diff --git a/src/Microsoft.AspNetCore.Authentication/HandleRequestResult.cs b/src/Microsoft.AspNetCore.Authentication/HandleRequestResult.cs new file mode 100644 index 000000000..da9b6ea01 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/HandleRequestResult.cs @@ -0,0 +1,96 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.AspNetCore.Authentication +{ + /// + /// Contains the result of an Authenticate call + /// + public class HandleRequestResult : AuthenticateResult + { + /// + /// Indicates that stage of authentication was directly handled by + /// user intervention and no further processing should be attempted. + /// + public bool Handled { get; private set; } + + /// + /// Indicates that the default authentication logic should be + /// skipped and that the rest of the pipeline should be invoked. + /// + public bool Skipped { get; private set; } + + /// + /// Indicates that authentication was successful. + /// + /// The ticket representing the authentication result. + /// The result. + public static new HandleRequestResult Success(AuthenticationTicket ticket) + { + if (ticket == null) + { + throw new ArgumentNullException(nameof(ticket)); + } + return new HandleRequestResult() { Ticket = ticket, Properties = ticket.Properties }; + } + + /// + /// Indicates that there was a failure during authentication. + /// + /// The failure exception. + /// The result. + public static new HandleRequestResult Fail(Exception failure) + { + return new HandleRequestResult() { Failure = failure }; + } + + /// + /// Indicates that there was a failure during authentication. + /// + /// The failure exception. + /// Additional state values for the authentication session. + /// The result. + public static new HandleRequestResult Fail(Exception failure, AuthenticationProperties properties) + { + return new HandleRequestResult() { Failure = failure, Properties = properties }; + } + + /// + /// Indicates that there was a failure during authentication. + /// + /// The failure message. + /// The result. + public static new HandleRequestResult Fail(string failureMessage) + => Fail(new Exception(failureMessage)); + + /// + /// Indicates that there was a failure during authentication. + /// + /// The failure message. + /// Additional state values for the authentication session. + /// The result. + public static new HandleRequestResult Fail(string failureMessage, AuthenticationProperties properties) + => Fail(new Exception(failureMessage), properties); + + /// + /// Discontinue all processing for this request and return to the client. + /// The caller is responsible for generating the full response. + /// + /// The result. + public static HandleRequestResult Handle() + { + return new HandleRequestResult() { Handled = true }; + } + + /// + /// Discontinue processing the request in the current handler. + /// + /// The result. + public static HandleRequestResult SkipHandler() + { + return new HandleRequestResult() { Skipped = true }; + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication/HttpContextExtensions.cs b/src/Microsoft.AspNetCore.Authentication/HttpContextExtensions.cs deleted file mode 100644 index 0d245cf0a..000000000 --- a/src/Microsoft.AspNetCore.Authentication/HttpContextExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features.Authentication; - -namespace Microsoft.AspNetCore.Authentication -{ - internal static class HttpContextExtensions - { - internal static IHttpAuthenticationFeature GetAuthentication(this HttpContext context) - { - var auth = context.Features.Get(); - if (auth == null) - { - auth = new HttpAuthenticationFeature(); - context.Features.Set(auth); - } - return auth; - } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication/IClaimsTransformer.cs b/src/Microsoft.AspNetCore.Authentication/IClaimsTransformer.cs deleted file mode 100644 index cd42915c0..000000000 --- a/src/Microsoft.AspNetCore.Authentication/IClaimsTransformer.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Security.Claims; -using System.Threading.Tasks; - -namespace Microsoft.AspNetCore.Authentication -{ - /// - /// Used for claims transformation. - /// - public interface IClaimsTransformer - { - /// - /// Provides a central transformation point to change the specified principal. - /// - /// containing principal to transform and current HttpContext. - /// The transformed principal. - Task TransformAsync(ClaimsTransformationContext context); - } -} diff --git a/src/Microsoft.AspNetCore.Authentication/Internal/RequestPathBaseCookieBuilder.cs b/src/Microsoft.AspNetCore.Authentication/Internal/RequestPathBaseCookieBuilder.cs new file mode 100644 index 000000000..f42617cb2 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/Internal/RequestPathBaseCookieBuilder.cs @@ -0,0 +1,38 @@ +// 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.Http; + +namespace Microsoft.AspNetCore.Authentication.Internal +{ + /// + /// A cookie builder that sets to the request path base. + /// + public class RequestPathBaseCookieBuilder : CookieBuilder + { + /// + /// Gets an optional value that is appended to the request path base. + /// + protected virtual string AdditionalPath { get; } + + public override CookieOptions Build(HttpContext context, DateTimeOffset expiresFrom) + { + // check if the user has overridden the default value of path. If so, use that instead of our default value. + var path = Path; + if (path == null) + { + var originalPathBase = context.Features.Get()?.OriginalPathBase ?? context.Request.PathBase; + path = originalPathBase + AdditionalPath; + } + + var options = base.Build(context, expiresFrom); + + options.Path = !string.IsNullOrEmpty(path) + ? path + : "/"; + + return options; + } + } +} diff --git a/src/Microsoft.AspNetCore.Authentication/LoggingExtensions.cs b/src/Microsoft.AspNetCore.Authentication/LoggingExtensions.cs index 49fc8db05..042bfabca 100644 --- a/src/Microsoft.AspNetCore.Authentication/LoggingExtensions.cs +++ b/src/Microsoft.AspNetCore.Authentication/LoggingExtensions.cs @@ -7,37 +7,23 @@ namespace Microsoft.Extensions.Logging { internal static class LoggingExtensions { - private static Action _authSchemeAuthenticated; - private static Action _authSchemeNotAuthenticated; - private static Action _authSchemeNotAuthenticatedWithFailure; - private static Action _authSchemeSignedIn; - private static Action _authSchemeSignedOut; - private static Action _authSchemeChallenged; - private static Action _authSchemeForbidden; - private static Action _userAuthorizationFailed; - private static Action _userAuthorizationSucceeded; - private static Action _userPrincipalMerged; - private static Action _remoteAuthenticationError; - private static Action _signInHandled; - private static Action _signInSkipped; - private static Action _correlationPropertyNotFound; - private static Action _correlationCookieNotFound; - private static Action _unexpectedCorrelationCookieValue; + private static readonly Action _authSchemeAuthenticated; + private static readonly Action _authSchemeNotAuthenticated; + private static readonly Action _authSchemeNotAuthenticatedWithFailure; + private static readonly Action _authSchemeChallenged; + private static readonly Action _authSchemeForbidden; + private static readonly Action _remoteAuthenticationError; + private static readonly Action _signInHandled; + private static readonly Action _signInSkipped; + private static readonly Action _correlationPropertyNotFound; + private static readonly Action _correlationCookieNotFound; + private static readonly Action _unexpectedCorrelationCookieValue; + private static readonly Action _accessDeniedError; + private static readonly Action _accessDeniedContextHandled; + private static readonly Action _accessDeniedContextSkipped; static LoggingExtensions() { - _userAuthorizationSucceeded = LoggerMessage.Define( - eventId: 1, - logLevel: LogLevel.Information, - formatString: "Authorization was successful for user: {UserName}."); - _userAuthorizationFailed = LoggerMessage.Define( - eventId: 2, - logLevel: LogLevel.Information, - formatString: "Authorization failed for user: {UserName}."); - _userPrincipalMerged = LoggerMessage.Define( - eventId: 3, - logLevel: LogLevel.Information, - formatString: "HttpContext.User merged via AutomaticAuthentication from authenticationScheme: {AuthenticationScheme}."); _remoteAuthenticationError = LoggerMessage.Define( eventId: 4, logLevel: LogLevel.Information, @@ -56,20 +42,12 @@ static LoggingExtensions() formatString: "{AuthenticationScheme} was not authenticated. Failure message: {FailureMessage}"); _authSchemeAuthenticated = LoggerMessage.Define( eventId: 8, - logLevel: LogLevel.Information, + logLevel: LogLevel.Debug, formatString: "AuthenticationScheme: {AuthenticationScheme} was successfully authenticated."); _authSchemeNotAuthenticated = LoggerMessage.Define( eventId: 9, logLevel: LogLevel.Debug, formatString: "AuthenticationScheme: {AuthenticationScheme} was not authenticated."); - _authSchemeSignedIn = LoggerMessage.Define( - eventId: 10, - logLevel: LogLevel.Information, - formatString: "AuthenticationScheme: {AuthenticationScheme} signed in."); - _authSchemeSignedOut = LoggerMessage.Define( - eventId: 11, - logLevel: LogLevel.Information, - formatString: "AuthenticationScheme: {AuthenticationScheme} signed out."); _authSchemeChallenged = LoggerMessage.Define( eventId: 12, logLevel: LogLevel.Information, @@ -90,6 +68,18 @@ static LoggingExtensions() eventId: 16, logLevel: LogLevel.Warning, formatString: "The correlation cookie value '{CorrelationCookieName}' did not match the expected value '{CorrelationCookieValue}'."); + _accessDeniedError = LoggerMessage.Define( + eventId: 17, + logLevel: LogLevel.Information, + formatString: "Access was denied by the resource owner or by the remote server."); + _accessDeniedContextHandled = LoggerMessage.Define( + eventId: 18, + logLevel: LogLevel.Debug, + formatString: "The AccessDenied event returned Handled."); + _accessDeniedContextSkipped = LoggerMessage.Define( + eventId: 19, + logLevel: LogLevel.Debug, + formatString: "The AccessDenied event returned Skipped."); } public static void AuthenticationSchemeAuthenticated(this ILogger logger, string authenticationScheme) @@ -107,16 +97,6 @@ public static void AuthenticationSchemeNotAuthenticatedWithFailure(this ILogger _authSchemeNotAuthenticatedWithFailure(logger, authenticationScheme, failureMessage, null); } - public static void AuthenticationSchemeSignedIn(this ILogger logger, string authenticationScheme) - { - _authSchemeSignedIn(logger, authenticationScheme, null); - } - - public static void AuthenticationSchemeSignedOut(this ILogger logger, string authenticationScheme) - { - _authSchemeSignedOut(logger, authenticationScheme, null); - } - public static void AuthenticationSchemeChallenged(this ILogger logger, string authenticationScheme) { _authSchemeChallenged(logger, authenticationScheme, null); @@ -127,21 +107,6 @@ public static void AuthenticationSchemeForbidden(this ILogger logger, string aut _authSchemeForbidden(logger, authenticationScheme, null); } - public static void UserAuthorizationSucceeded(this ILogger logger, string userName) - { - _userAuthorizationSucceeded(logger, userName, null); - } - - public static void UserAuthorizationFailed(this ILogger logger, string userName) - { - _userAuthorizationFailed(logger, userName, null); - } - - public static void UserPrinicpalMerged(this ILogger logger, string authenticationScheme) - { - _userPrincipalMerged(logger, authenticationScheme, null); - } - public static void RemoteAuthenticationError(this ILogger logger, string errorMessage) { _remoteAuthenticationError(logger, errorMessage, null); @@ -171,5 +136,20 @@ public static void UnexpectedCorrelationCookieValue(this ILogger logger, string { _unexpectedCorrelationCookieValue(logger, cookieName, cookieValue, null); } + + public static void AccessDeniedError(this ILogger logger) + { + _accessDeniedError(logger, null); + } + + public static void AccessDeniedContextHandled(this ILogger logger) + { + _accessDeniedContextHandled(logger, null); + } + + public static void AccessDeniedContextSkipped(this ILogger logger) + { + _accessDeniedContextSkipped(logger, null); + } } } diff --git a/src/Microsoft.AspNetCore.Authentication/Microsoft.AspNetCore.Authentication.csproj b/src/Microsoft.AspNetCore.Authentication/Microsoft.AspNetCore.Authentication.csproj new file mode 100644 index 000000000..9ae0a7bcc --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/Microsoft.AspNetCore.Authentication.csproj @@ -0,0 +1,22 @@ + + + + ASP.NET Core common types used by the various authentication middleware components. + netcoreapp3.0 + $(NoWarn);CS1591 + true + aspnetcore;authentication;security + + + + + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Authentication/Microsoft.AspNetCore.Authentication.xproj b/src/Microsoft.AspNetCore.Authentication/Microsoft.AspNetCore.Authentication.xproj deleted file mode 100644 index b3345c6cf..000000000 --- a/src/Microsoft.AspNetCore.Authentication/Microsoft.AspNetCore.Authentication.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 2286250a-52c8-4126-9f93-b1e45f0ad078 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/PolicySchemeHandler.cs b/src/Microsoft.AspNetCore.Authentication/PolicySchemeHandler.cs new file mode 100644 index 000000000..4dbbb7de2 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/PolicySchemeHandler.cs @@ -0,0 +1,36 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Security.Claims; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Authentication +{ + /// + /// PolicySchemes are used to redirect authentication methods to another scheme. + /// + public class PolicySchemeHandler : SignInAuthenticationHandler + { + public PolicySchemeHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) + { } + + protected override Task HandleChallengeAsync(AuthenticationProperties properties) + => throw new NotImplementedException(); + + protected override Task HandleForbiddenAsync(AuthenticationProperties properties) + => throw new NotImplementedException(); + + protected override Task HandleSignInAsync(ClaimsPrincipal user, AuthenticationProperties properties) + => throw new NotImplementedException(); + + protected override Task HandleSignOutAsync(AuthenticationProperties properties) + => throw new NotImplementedException(); + + protected override Task HandleAuthenticateAsync() + => throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/AuthenticationToken.cs b/src/Microsoft.AspNetCore.Authentication/PolicySchemeOptions.cs similarity index 53% rename from src/Microsoft.AspNetCore.Authentication/AuthenticationToken.cs rename to src/Microsoft.AspNetCore.Authentication/PolicySchemeOptions.cs index 6503f0bb8..1921c77ec 100644 --- a/src/Microsoft.AspNetCore.Authentication/AuthenticationToken.cs +++ b/src/Microsoft.AspNetCore.Authentication/PolicySchemeOptions.cs @@ -1,12 +1,11 @@ // 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 { - public class AuthenticationToken - { - public string Name { get; set; } - public string Value { get; set; } - } -} \ No newline at end of file + /// + /// Contains the options used by the . + /// + public class PolicySchemeOptions : AuthenticationSchemeOptions + { } +} diff --git a/src/Microsoft.AspNetCore.Authentication/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Authentication/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff..000000000 --- a/src/Microsoft.AspNetCore.Authentication/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.Authentication/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Authentication/Properties/Resources.Designer.cs index a6cf91046..b1941a7dc 100644 --- a/src/Microsoft.AspNetCore.Authentication/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Authentication/Properties/Resources.Designer.cs @@ -1,6 +1,7 @@ // namespace Microsoft.AspNetCore.Authentication { + using System.Globalization; using System.Reflection; using System.Resources; @@ -14,49 +15,71 @@ private static readonly ResourceManager _resourceManager /// internal static string Exception_DefaultDpapiRequiresAppNameKey { - get { return GetString("Exception_DefaultDpapiRequiresAppNameKey"); } + get => GetString("Exception_DefaultDpapiRequiresAppNameKey"); } /// /// The default data protection provider may only be used when the IApplicationBuilder.Properties contains an appropriate 'host.AppName' key. /// internal static string FormatException_DefaultDpapiRequiresAppNameKey() - { - return GetString("Exception_DefaultDpapiRequiresAppNameKey"); - } + => GetString("Exception_DefaultDpapiRequiresAppNameKey"); /// /// The state passed to UnhookAuthentication may only be the return value from HookAuthentication. /// internal static string Exception_UnhookAuthenticationStateType { - get { return GetString("Exception_UnhookAuthenticationStateType"); } + get => GetString("Exception_UnhookAuthenticationStateType"); } /// /// The state passed to UnhookAuthentication may only be the return value from HookAuthentication. /// internal static string FormatException_UnhookAuthenticationStateType() - { - return GetString("Exception_UnhookAuthenticationStateType"); - } + => GetString("Exception_UnhookAuthenticationStateType"); /// /// The AuthenticationTokenProvider's required synchronous events have not been registered. /// internal static string Exception_AuthenticationTokenDoesNotProvideSyncMethods { - get { return GetString("Exception_AuthenticationTokenDoesNotProvideSyncMethods"); } + get => GetString("Exception_AuthenticationTokenDoesNotProvideSyncMethods"); } /// /// The AuthenticationTokenProvider's required synchronous events have not been registered. /// internal static string FormatException_AuthenticationTokenDoesNotProvideSyncMethods() + => GetString("Exception_AuthenticationTokenDoesNotProvideSyncMethods"); + + /// + /// The '{0}' option must be provided. + /// + internal static string Exception_OptionMustBeProvided + { + get => GetString("Exception_OptionMustBeProvided"); + } + + /// + /// The '{0}' option must be provided. + /// + internal static string FormatException_OptionMustBeProvided(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0); + + /// + /// The SignInScheme for a remote authentication handler cannot be set to itself. If it was not explicitly set, the AuthenticationOptions.DefaultSignInScheme or DefaultScheme is used. + /// + internal static string Exception_RemoteSignInSchemeCannotBeSelf { - return GetString("Exception_AuthenticationTokenDoesNotProvideSyncMethods"); + get => GetString("Exception_RemoteSignInSchemeCannotBeSelf"); } + /// + /// The SignInScheme for a remote authentication handler cannot be set to itself. If it was not explicitly set, the AuthenticationOptions.DefaultSignInScheme or DefaultScheme is used. + /// + internal static string FormatException_RemoteSignInSchemeCannotBeSelf() + => GetString("Exception_RemoteSignInSchemeCannotBeSelf"); + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/Microsoft.AspNetCore.Authentication/RemoteAuthenticationHandler.cs b/src/Microsoft.AspNetCore.Authentication/RemoteAuthenticationHandler.cs index 1e41fb0b5..c72583b5c 100644 --- a/src/Microsoft.AspNetCore.Authentication/RemoteAuthenticationHandler.cs +++ b/src/Microsoft.AspNetCore.Authentication/RemoteAuthenticationHandler.cs @@ -3,39 +3,54 @@ using System; using System.Security.Cryptography; +using System.Text.Encodings.Web; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features.Authentication; -using Microsoft.AspNetCore.Http.Authentication; +using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Authentication { - public abstract class RemoteAuthenticationHandler : AuthenticationHandler where TOptions : RemoteAuthenticationOptions + public abstract class RemoteAuthenticationHandler : AuthenticationHandler, IAuthenticationRequestHandler + where TOptions : RemoteAuthenticationOptions, new() { - private const string CorrelationPrefix = ".AspNetCore.Correlation."; private const string CorrelationProperty = ".xsrf"; private const string CorrelationMarker = "N"; private const string AuthSchemeKey = ".AuthScheme"; private static readonly RandomNumberGenerator CryptoRandom = RandomNumberGenerator.Create(); - public override async Task HandleRequestAsync() - { - if (Options.CallbackPath == Request.Path) - { - return await HandleRemoteCallbackAsync(); - } + protected string SignInScheme => Options.SignInScheme; - return false; + /// + /// 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. + /// + protected new RemoteAuthenticationEvents Events + { + get { return (RemoteAuthenticationEvents)base.Events; } + set { base.Events = value; } } - protected virtual async Task HandleRemoteCallbackAsync() + protected RemoteAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) + : base(options, logger, encoder, clock) { } + + protected override Task CreateEventsAsync() + => Task.FromResult(new RemoteAuthenticationEvents()); + + public virtual Task ShouldHandleRequestAsync() + => Task.FromResult(Options.CallbackPath == Request.Path); + + public virtual async Task HandleRequestAsync() { + if (!await ShouldHandleRequestAsync()) + { + return false; + } + AuthenticationTicket ticket = null; Exception exception = null; - + AuthenticationProperties properties = null; try { var authResult = await HandleRemoteAuthenticateAsync(); @@ -47,17 +62,17 @@ protected virtual async Task HandleRemoteCallbackAsync() { return true; } - else if (authResult.Skipped) + else if (authResult.Skipped || authResult.None) { return false; } else if (!authResult.Succeeded) { - exception = authResult.Failure ?? - new InvalidOperationException("Invalid return state, unable to redirect."); + exception = authResult.Failure ?? new InvalidOperationException("Invalid return state, unable to redirect."); + properties = authResult.Properties; } - ticket = authResult.Ticket; + ticket = authResult?.Ticket; } catch (Exception ex) { @@ -67,55 +82,70 @@ protected virtual async Task HandleRemoteCallbackAsync() if (exception != null) { Logger.RemoteAuthenticationError(exception.Message); - var errorContext = new FailureContext(Context, exception); - await Options.Events.RemoteFailure(errorContext); + var errorContext = new RemoteFailureContext(Context, Scheme, Options, exception) + { + Properties = properties + }; + await Events.RemoteFailure(errorContext); - if (errorContext.HandledResponse) + if (errorContext.Result != null) { - return true; + if (errorContext.Result.Handled) + { + return true; + } + else if (errorContext.Result.Skipped) + { + return false; + } + else if (errorContext.Result.Failure != null) + { + throw new Exception("An error was returned from the RemoteFailure event.", errorContext.Result.Failure); + } } - if (errorContext.Skipped) + if (errorContext.Failure != null) { - return false; + throw new Exception("An error was encountered while handling the remote login.", errorContext.Failure); } - - throw new AggregateException("Unhandled remote failure.", exception); } // We have a ticket if we get here - var context = new TicketReceivedContext(Context, Options, ticket) + var ticketContext = new TicketReceivedContext(Context, Scheme, Options, ticket) { - ReturnUri = ticket.Properties.RedirectUri, + ReturnUri = ticket.Properties.RedirectUri }; - // REVIEW: is this safe or good? + ticket.Properties.RedirectUri = null; // Mark which provider produced this identity so we can cross-check later in HandleAuthenticateAsync - context.Properties.Items[AuthSchemeKey] = Options.AuthenticationScheme; + ticketContext.Properties.Items[AuthSchemeKey] = Scheme.Name; - await Options.Events.TicketReceived(context); + await Events.TicketReceived(ticketContext); - if (context.HandledResponse) - { - Logger.SigninHandled(); - return true; - } - else if (context.Skipped) + if (ticketContext.Result != null) { - Logger.SigninSkipped(); - return false; + if (ticketContext.Result.Handled) + { + Logger.SigninHandled(); + return true; + } + else if (ticketContext.Result.Skipped) + { + Logger.SigninSkipped(); + return false; + } } - await Context.Authentication.SignInAsync(Options.SignInScheme, context.Principal, context.Properties); + await Context.SignInAsync(SignInScheme, ticketContext.Principal, ticketContext.Properties); // Default redirect path is the base path - if (string.IsNullOrEmpty(context.ReturnUri)) + if (string.IsNullOrEmpty(ticketContext.ReturnUri)) { - context.ReturnUri = "/"; + ticketContext.ReturnUri = "/"; } - Response.Redirect(context.ReturnUri); + Response.Redirect(ticketContext.ReturnUri); return true; } @@ -124,56 +154,37 @@ protected virtual async Task HandleRemoteCallbackAsync() /// /// The method process the request on the endpoint defined by CallbackPath. /// - protected abstract Task HandleRemoteAuthenticateAsync(); + protected abstract Task HandleRemoteAuthenticateAsync(); protected override async Task HandleAuthenticateAsync() { - // Most RemoteAuthenticationHandlers will have a PriorHandler, but it might not be set up during unit tests. - if (PriorHandler != null) + var result = await Context.AuthenticateAsync(SignInScheme); + if (result != null) { - var authenticateContext = new AuthenticateContext(Options.SignInScheme); - await PriorHandler.AuthenticateAsync(authenticateContext); - if (authenticateContext.Accepted) + if (result.Failure != null) { - if (authenticateContext.Error != null) - { - return AuthenticateResult.Fail(authenticateContext.Error); - } - - // The SignInScheme may be shared with multiple providers, make sure this middleware issued the identity. - string authenticatedScheme; - if (authenticateContext.Principal != null && authenticateContext.Properties != null - && authenticateContext.Properties.TryGetValue(AuthSchemeKey, out authenticatedScheme) - && string.Equals(Options.AuthenticationScheme, authenticatedScheme, StringComparison.Ordinal)) - { - return AuthenticateResult.Success(new AuthenticationTicket(authenticateContext.Principal, - new AuthenticationProperties(authenticateContext.Properties), Options.AuthenticationScheme)); - } + return result; + } - return AuthenticateResult.Fail("Not authenticated"); + // The SignInScheme may be shared with multiple providers, make sure this provider issued the identity. + string authenticatedScheme; + var ticket = result.Ticket; + if (ticket != null && ticket.Principal != null && ticket.Properties != null + && ticket.Properties.Items.TryGetValue(AuthSchemeKey, out authenticatedScheme) + && string.Equals(Scheme.Name, authenticatedScheme, StringComparison.Ordinal)) + { + return AuthenticateResult.Success(new AuthenticationTicket(ticket.Principal, + ticket.Properties, Scheme.Name)); } + return AuthenticateResult.Fail("Not authenticated"); } - return AuthenticateResult.Fail("Remote authentication does not directly support authenticate"); - } - - protected override Task HandleSignOutAsync(SignOutContext context) - { - throw new NotSupportedException(); + return AuthenticateResult.Fail("Remote authentication does not directly support AuthenticateAsync"); } - protected override Task HandleSignInAsync(SignInContext context) - { - throw new NotSupportedException(); - } - - protected override async Task HandleForbiddenAsync(ChallengeContext context) - { - var challengeContext = new ChallengeContext(Options.SignInScheme, context.Properties, ChallengeBehavior.Forbidden); - await PriorHandler.ChallengeAsync(challengeContext); - return challengeContext.Accepted; - } + protected override Task HandleForbiddenAsync(AuthenticationProperties properties) + => Context.ForbidAsync(SignInScheme); protected virtual void GenerateCorrelationId(AuthenticationProperties properties) { @@ -186,16 +197,11 @@ protected virtual void GenerateCorrelationId(AuthenticationProperties properties CryptoRandom.GetBytes(bytes); var correlationId = Base64UrlTextEncoder.Encode(bytes); - var cookieOptions = new CookieOptions - { - HttpOnly = true, - Secure = Request.IsHttps, - Expires = Options.SystemClock.UtcNow.Add(Options.RemoteAuthenticationTimeout), - }; + var cookieOptions = Options.CorrelationCookie.Build(Context, Clock.UtcNow); properties.Items[CorrelationProperty] = correlationId; - var cookieName = CorrelationPrefix + Options.AuthenticationScheme + "." + correlationId; + var cookieName = Options.CorrelationCookie.Name + Scheme.Name + "." + correlationId; Response.Cookies.Append(cookieName, CorrelationMarker, cookieOptions); } @@ -207,16 +213,15 @@ protected virtual bool ValidateCorrelationId(AuthenticationProperties properties throw new ArgumentNullException(nameof(properties)); } - string correlationId; - if (!properties.Items.TryGetValue(CorrelationProperty, out correlationId)) + if (!properties.Items.TryGetValue(CorrelationProperty, out string correlationId)) { - Logger.CorrelationPropertyNotFound(CorrelationPrefix); + Logger.CorrelationPropertyNotFound(Options.CorrelationCookie.Name); return false; } properties.Items.Remove(CorrelationProperty); - var cookieName = CorrelationPrefix + Options.AuthenticationScheme + "." + correlationId; + var cookieName = Options.CorrelationCookie.Name + Scheme.Name + "." + correlationId; var correlationCookie = Request.Cookies[cookieName]; if (string.IsNullOrEmpty(correlationCookie)) @@ -225,11 +230,8 @@ protected virtual bool ValidateCorrelationId(AuthenticationProperties properties return false; } - var cookieOptions = new CookieOptions - { - HttpOnly = true, - Secure = Request.IsHttps - }; + var cookieOptions = Options.CorrelationCookie.Build(Context, Clock.UtcNow); + Response.Cookies.Delete(cookieName, cookieOptions); if (!string.Equals(correlationCookie, CorrelationMarker, StringComparison.Ordinal)) @@ -240,5 +242,48 @@ protected virtual bool ValidateCorrelationId(AuthenticationProperties properties return true; } + + protected virtual async Task HandleAccessDeniedErrorAsync(AuthenticationProperties properties) + { + Logger.AccessDeniedError(); + var context = new AccessDeniedContext(Context, Scheme, Options) + { + AccessDeniedPath = Options.AccessDeniedPath, + Properties = properties, + ReturnUrl = properties?.RedirectUri, + ReturnUrlParameter = Options.ReturnUrlParameter + }; + await Events.AccessDenied(context); + + if (context.Result != null) + { + if (context.Result.Handled) + { + Logger.AccessDeniedContextHandled(); + } + else if (context.Result.Skipped) + { + Logger.AccessDeniedContextSkipped(); + } + + return context.Result; + } + + // If an access denied endpoint was specified, redirect the user agent. + // Otherwise, invoke the RemoteFailure event for further processing. + if (context.AccessDeniedPath.HasValue) + { + string uri = context.AccessDeniedPath; + if (!string.IsNullOrEmpty(context.ReturnUrlParameter) && !string.IsNullOrEmpty(context.ReturnUrl)) + { + uri = QueryHelpers.AddQueryString(uri, context.ReturnUrlParameter, context.ReturnUrl); + } + Response.Redirect(uri); + + return HandleRequestResult.Handle(); + } + + return HandleRequestResult.Fail("Access was denied by the resource owner or by the remote server.", properties); + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/RemoteAuthenticationOptions.cs b/src/Microsoft.AspNetCore.Authentication/RemoteAuthenticationOptions.cs index e990abd05..188b7a991 100644 --- a/src/Microsoft.AspNetCore.Authentication/RemoteAuthenticationOptions.cs +++ b/src/Microsoft.AspNetCore.Authentication/RemoteAuthenticationOptions.cs @@ -3,16 +3,61 @@ using System; using System.Net.Http; +using Microsoft.AspNetCore.Authentication.Internal; +using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Authentication; -namespace Microsoft.AspNetCore.Builder +namespace Microsoft.AspNetCore.Authentication { /// /// Contains the options used by the . /// - public class RemoteAuthenticationOptions : AuthenticationOptions + public class RemoteAuthenticationOptions : AuthenticationSchemeOptions { + private const string CorrelationPrefix = ".AspNetCore.Correlation."; + + private CookieBuilder _correlationCookieBuilder; + + /// + /// Initializes a new . + /// + public RemoteAuthenticationOptions() + { + _correlationCookieBuilder = new CorrelationCookieBuilder(this) + { + Name = CorrelationPrefix, + HttpOnly = true, + SameSite = SameSiteMode.None, + SecurePolicy = CookieSecurePolicy.SameAsRequest, + IsEssential = true, + }; + } + + /// + /// Checks that the options are valid for a specific scheme + /// + /// The scheme being validated. + public override void Validate(string scheme) + { + base.Validate(scheme); + if (string.Equals(scheme, SignInScheme, StringComparison.Ordinal)) + { + throw new InvalidOperationException(Resources.Exception_RemoteSignInSchemeCannotBeSelf); + } + } + + /// + /// Check that the options are valid. Should throw an exception if things are not ok. + /// + public override void Validate() + { + base.Validate(); + if (CallbackPath == null || !CallbackPath.HasValue) + { + throw new ArgumentException(Resources.FormatException_OptionMustBeProvided(nameof(CallbackPath)), nameof(CallbackPath)); + } + } + /// /// Gets or sets timeout value in milliseconds for back channel communications with the remote identity provider. /// @@ -28,35 +73,56 @@ public class RemoteAuthenticationOptions : AuthenticationOptions /// public HttpMessageHandler BackchannelHttpHandler { get; set; } + /// + /// Used to communicate with the remote identity provider. + /// + public HttpClient Backchannel { get; set; } + + /// + /// Gets or sets the type used to secure data. + /// + public IDataProtectionProvider DataProtectionProvider { get; set; } + /// /// The request path within the application's base path where the user-agent will be returned. /// The middleware will process this request when it arrives. /// public PathString CallbackPath { get; set; } + /// + /// Gets or sets the optional path the user agent is redirected to if the user + /// doesn't approve the authorization demand requested by the remote server. + /// This property is not set by default. In this case, an exception is thrown + /// if an access_denied response is returned by the remote authorization server. + /// + public PathString AccessDeniedPath { get; set; } + + /// + /// Gets or sets the name of the parameter used to convey the original location + /// of the user before the remote challenge was triggered up to the access denied page. + /// This property is only used when the is explicitly specified. + /// + // Note: this deliberately matches the default parameter name used by the cookie handler. + public string ReturnUrlParameter { get; set; } = "ReturnUrl"; + /// /// Gets or sets the authentication scheme corresponding to the middleware /// responsible of persisting user's identity after a successful authentication. /// This value typically corresponds to a cookie middleware registered in the Startup class. - /// When omitted, is used as a fallback value. + /// When omitted, is used as a fallback value. /// public string SignInScheme { get; set; } - /// - /// Get or sets the text that the user can display on a sign in user interface. - /// - public string DisplayName - { - get { return Description.DisplayName; } - set { Description.DisplayName = value; } - } - /// /// Gets or sets the time limit for completing the authentication flow (15 minutes by default). /// public TimeSpan RemoteAuthenticationTimeout { get; set; } = TimeSpan.FromMinutes(15); - public IRemoteAuthenticationEvents Events = new RemoteAuthenticationEvents(); + public new RemoteAuthenticationEvents Events + { + get => (RemoteAuthenticationEvents)base.Events; + set => base.Events = value; + } /// /// Defines whether access and refresh tokens should be stored in the @@ -65,5 +131,39 @@ public string DisplayName /// the size of the final authentication cookie. /// public bool SaveTokens { get; set; } + + /// + /// Determines the settings used to create the correlation cookie before the + /// cookie gets added to the response. + /// + public CookieBuilder CorrelationCookie + { + get => _correlationCookieBuilder; + set => _correlationCookieBuilder = value ?? throw new ArgumentNullException(nameof(value)); + } + + private class CorrelationCookieBuilder : RequestPathBaseCookieBuilder + { + private readonly RemoteAuthenticationOptions _options; + + public CorrelationCookieBuilder(RemoteAuthenticationOptions remoteAuthenticationOptions) + { + _options = remoteAuthenticationOptions; + } + + protected override string AdditionalPath => _options.CallbackPath; + + public override CookieOptions Build(HttpContext context, DateTimeOffset expiresFrom) + { + var cookieOptions = base.Build(context, expiresFrom); + + if (!Expiration.HasValue || !cookieOptions.Expires.HasValue) + { + cookieOptions.Expires = expiresFrom.Add(_options.RemoteAuthenticationTimeout); + } + + return cookieOptions; + } + } } } diff --git a/src/Microsoft.AspNetCore.Authentication/Resources.resx b/src/Microsoft.AspNetCore.Authentication/Resources.resx index 77060045e..9e831dc74 100644 --- a/src/Microsoft.AspNetCore.Authentication/Resources.resx +++ b/src/Microsoft.AspNetCore.Authentication/Resources.resx @@ -126,4 +126,10 @@ The AuthenticationTokenProvider's required synchronous events have not been registered. + + The '{0}' option must be provided. + + + The SignInScheme for a remote authentication handler cannot be set to itself. If it was not explicitly set, the AuthenticationOptions.DefaultSignInScheme or DefaultScheme is used. + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/SharedAuthenticationOptions.cs b/src/Microsoft.AspNetCore.Authentication/SharedAuthenticationOptions.cs deleted file mode 100644 index 8b168c9a0..000000000 --- a/src/Microsoft.AspNetCore.Authentication/SharedAuthenticationOptions.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.Authentication -{ - public class SharedAuthenticationOptions - { - /// - /// Gets or sets the authentication scheme corresponding to the default middleware - /// responsible of persisting user's identity after a successful authentication. - /// This value typically corresponds to a cookie middleware registered in the Startup class. - /// - public string SignInScheme { get; set; } - } -} diff --git a/src/Microsoft.AspNetCore.Authentication/SignInAuthenticationHandler.cs b/src/Microsoft.AspNetCore.Authentication/SignInAuthenticationHandler.cs new file mode 100644 index 000000000..dbd612dc1 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/SignInAuthenticationHandler.cs @@ -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 System; +using System.Security.Claims; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Authentication +{ + /// + /// Adds support for SignInAsync + /// + public abstract class SignInAuthenticationHandler : SignOutAuthenticationHandler, IAuthenticationSignInHandler + where TOptions : AuthenticationSchemeOptions, new() + { + public SignInAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) + { } + + public virtual Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties) + { + var target = ResolveTarget(Options.ForwardSignIn); + return (target != null) + ? Context.SignInAsync(target, user, properties) + : HandleSignInAsync(user, properties ?? new AuthenticationProperties()); + } + + /// + /// Override this method to handle SignIn. + /// + /// + /// + /// A Task. + protected abstract Task HandleSignInAsync(ClaimsPrincipal user, AuthenticationProperties properties); + + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/SignOutAuthenticationHandler.cs b/src/Microsoft.AspNetCore.Authentication/SignOutAuthenticationHandler.cs new file mode 100644 index 000000000..015cb39e0 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/SignOutAuthenticationHandler.cs @@ -0,0 +1,36 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Authentication +{ + /// + /// Adds support for SignOutAsync + /// + public abstract class SignOutAuthenticationHandler : AuthenticationHandler, IAuthenticationSignOutHandler + where TOptions : AuthenticationSchemeOptions, new() + { + public SignOutAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) + { } + + public virtual Task SignOutAsync(AuthenticationProperties properties) + { + var target = ResolveTarget(Options.ForwardSignOut); + return (target != null) + ? Context.SignOutAsync(target, properties) + : HandleSignOutAsync(properties ?? new AuthenticationProperties()); + } + + /// + /// Override this method to handle SignOut. + /// + /// + /// A Task. + protected abstract Task HandleSignOutAsync(AuthenticationProperties properties); + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/SystemClock.cs b/src/Microsoft.AspNetCore.Authentication/SystemClock.cs index 0f9c2a30a..2320982ce 100644 --- a/src/Microsoft.AspNetCore.Authentication/SystemClock.cs +++ b/src/Microsoft.AspNetCore.Authentication/SystemClock.cs @@ -1,13 +1,12 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - using System; namespace Microsoft.AspNetCore.Authentication { /// - /// Provides access to the normal system clock. + /// Provides access to the normal system clock with precision in seconds. /// public class SystemClock : ISystemClock { @@ -20,8 +19,8 @@ public DateTimeOffset UtcNow { // the clock measures whole seconds only, to have integral expires_in results, and // because milliseconds do not round-trip serialization formats - DateTimeOffset utcNow = DateTimeOffset.UtcNow; - return utcNow.AddMilliseconds(-utcNow.Millisecond); + var utcNowPrecisionSeconds = new DateTime((DateTime.UtcNow.Ticks / TimeSpan.TicksPerSecond) * TimeSpan.TicksPerSecond, DateTimeKind.Utc); + return new DateTimeOffset(utcNowPrecisionSeconds); } } } diff --git a/src/Microsoft.AspNetCore.Authentication/TokenExtensions.cs b/src/Microsoft.AspNetCore.Authentication/TokenExtensions.cs deleted file mode 100644 index 9f5c96cc1..000000000 --- a/src/Microsoft.AspNetCore.Authentication/TokenExtensions.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.Http.Features.Authentication; - -namespace Microsoft.AspNetCore.Authentication -{ - public static class AuthenticationTokenExtensions - { - private static string TokenNamesKey = ".TokenNames"; - private static string TokenKeyPrefix = ".Token."; - - public static void StoreTokens(this AuthenticationProperties properties, IEnumerable tokens) - { - if (properties == null) - { - throw new ArgumentNullException(nameof(properties)); - } - if (tokens == null) - { - throw new ArgumentNullException(nameof(tokens)); - } - - // Clear old tokens first - var oldTokens = properties.GetTokens(); - foreach (var t in oldTokens) - { - properties.Items.Remove(TokenKeyPrefix + t.Name); - } - properties.Items.Remove(TokenNamesKey); - - var tokenNames = new List(); - foreach (var token in tokens) - { - // REVIEW: should probably check that there are no ; in the token name and throw or encode - tokenNames.Add(token.Name); - properties.Items[TokenKeyPrefix+token.Name] = token.Value; - } - if (tokenNames.Count > 0) - { - properties.Items[TokenNamesKey] = string.Join(";", tokenNames.ToArray()); - } - } - - public static string GetTokenValue(this AuthenticationProperties properties, string tokenName) - { - if (properties == null) - { - throw new ArgumentNullException(nameof(properties)); - } - if (tokenName == null) - { - throw new ArgumentNullException(nameof(tokenName)); - } - - var tokenKey = TokenKeyPrefix + tokenName; - return properties.Items.ContainsKey(tokenKey) - ? properties.Items[tokenKey] - : null; - } - - public static bool UpdateTokenValue(this AuthenticationProperties properties, string tokenName, string tokenValue) - { - if (properties == null) - { - throw new ArgumentNullException(nameof(properties)); - } - if (tokenName == null) - { - throw new ArgumentNullException(nameof(tokenName)); - } - - var tokenKey = TokenKeyPrefix + tokenName; - if (!properties.Items.ContainsKey(tokenKey)) - { - return false; - } - properties.Items[tokenKey] = tokenValue; - return true; - } - - public static IEnumerable GetTokens(this AuthenticationProperties properties) - { - if (properties == null) - { - throw new ArgumentNullException(nameof(properties)); - } - - var tokens = new List(); - if (properties.Items.ContainsKey(TokenNamesKey)) - { - var tokenNames = properties.Items[TokenNamesKey].Split(';'); - foreach (var name in tokenNames) - { - var token = properties.GetTokenValue(name); - if (token != null) - { - tokens.Add(new AuthenticationToken { Name = name, Value = token }); - } - } - } - - return tokens; - } - - public static Task GetTokenAsync(this AuthenticationManager manager, string tokenName) - { - return manager.GetTokenAsync(AuthenticationManager.AutomaticScheme, tokenName); - } - - public static async Task GetTokenAsync(this AuthenticationManager manager, string signInScheme, string tokenName) - { - if (manager == null) - { - throw new ArgumentNullException(nameof(manager)); - } - if (signInScheme == null) - { - throw new ArgumentNullException(nameof(signInScheme)); - } - if (tokenName == null) - { - throw new ArgumentNullException(nameof(tokenName)); - } - - var authContext = new AuthenticateContext(signInScheme); - await manager.AuthenticateAsync(authContext); - return new AuthenticationProperties(authContext.Properties).GetTokenValue(tokenName); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/baseline.net45.json b/src/Microsoft.AspNetCore.Authentication/baseline.net45.json deleted file mode 100644 index 1f69da5a8..000000000 --- a/src/Microsoft.AspNetCore.Authentication/baseline.net45.json +++ /dev/null @@ -1,2897 +0,0 @@ -{ - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", - "Types": [ - { - "Name": "Microsoft.AspNetCore.Builder.AuthenticationOptions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_AuthenticationScheme", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AutomaticAuthenticate", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_AutomaticAuthenticate", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AutomaticChallenge", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_AutomaticChallenge", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ClaimsIssuer", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ClaimsIssuer", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Description", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationDescription", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Description", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationDescription" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Protected", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.ClaimsTransformationAppBuilderExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "UseClaimsTransformation", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "UseClaimsTransformation", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "transform", - "Type": "System.Func>" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "UseClaimsTransformation", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.ClaimsTransformationOptions" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.ClaimsTransformationOptions", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Transformer", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.IClaimsTransformer", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Transformer", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.IClaimsTransformer" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.AuthenticationOptions", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_BackchannelTimeout", - "Parameters": [], - "ReturnType": "System.TimeSpan", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_BackchannelTimeout", - "Parameters": [ - { - "Name": "value", - "Type": "System.TimeSpan" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_BackchannelHttpHandler", - "Parameters": [], - "ReturnType": "System.Net.Http.HttpMessageHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_BackchannelHttpHandler", - "Parameters": [ - { - "Name": "value", - "Type": "System.Net.Http.HttpMessageHandler" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_CallbackPath", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_CallbackPath", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.PathString" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SignInScheme", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SignInScheme", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_DisplayName", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_DisplayName", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_RemoteAuthenticationTimeout", - "Parameters": [], - "ReturnType": "System.TimeSpan", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_RemoteAuthenticationTimeout", - "Parameters": [ - { - "Name": "value", - "Type": "System.TimeSpan" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SaveTokens", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SaveTokens", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Field", - "Name": "Events", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents", - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.AuthenticateResult", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Succeeded", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Ticket", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Failure", - "Parameters": [], - "ReturnType": "System.Exception", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Skipped", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Success", - "Parameters": [ - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticateResult", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Skip", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticateResult", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Fail", - "Parameters": [ - { - "Name": "failure", - "Type": "System.Exception" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticateResult", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Fail", - "Parameters": [ - { - "Name": "failureMessage", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticateResult", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_SignInAccepted", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SignInAccepted", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_SignOutAccepted", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SignOutAccepted", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ChallengeCalled", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ChallengeCalled", - "Parameters": [ - { - "Name": "value", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Void", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Context", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpContext", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Request", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpRequest", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Response", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpResponse", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OriginalPathBase", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OriginalPath", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Logger", - "Parameters": [], - "ReturnType": "Microsoft.Extensions.Logging.ILogger", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_UrlEncoder", - "Parameters": [], - "ReturnType": "System.Text.Encodings.Web.UrlEncoder", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_PriorHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_PriorHandler", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_CurrentUri", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "T0", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "InitializeAsync", - "Parameters": [ - { - "Name": "options", - "Type": "T0" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "logger", - "Type": "Microsoft.Extensions.Logging.ILogger" - }, - { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "BuildRedirectUri", - "Parameters": [ - { - "Name": "targetPath", - "Type": "System.String" - } - ], - "ReturnType": "System.String", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "FinishResponseAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleRequestAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetDescriptions", - "Parameters": [ - { - "Name": "describeContext", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.DescribeSchemesContext" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ShouldHandleScheme", - "Parameters": [ - { - "Name": "authenticationScheme", - "Type": "System.String" - }, - { - "Name": "handleAutomatic", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AuthenticateAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.AuthenticateContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleAuthenticateOnceAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleAuthenticateAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Abstract": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "SignInAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignInContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleSignInAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignInContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "SignOutAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignOutContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleSignOutAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignOutContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleForbiddenAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleUnauthorizedAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ChallengeAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Protected", - "GenericParameter": [] - } - ], - "GenericParameters": [ - { - "ParameterName": "TOptions", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [ - "Microsoft.AspNetCore.Builder.AuthenticationOptions" - ] - } - ] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_AuthenticationScheme", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "T0", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Options", - "Parameters": [ - { - "Name": "value", - "Type": "T0" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Logger", - "Parameters": [], - "ReturnType": "Microsoft.Extensions.Logging.ILogger", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Logger", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.Extensions.Logging.ILogger" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_UrlEncoder", - "Parameters": [], - "ReturnType": "System.Text.Encodings.Web.UrlEncoder", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_UrlEncoder", - "Parameters": [ - { - "Name": "value", - "Type": "System.Text.Encodings.Web.UrlEncoder" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Invoke", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "CreateHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "Virtual": true, - "Abstract": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" - }, - { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" - }, - { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" - } - ], - "Visibility": "Protected", - "GenericParameter": [] - } - ], - "GenericParameters": [ - { - "ParameterName": "TOptions", - "ParameterPosition": 0, - "New": true, - "BaseTypeOrInterfaces": [ - "Microsoft.AspNetCore.Builder.AuthenticationOptions" - ] - } - ] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_AuthenticationScheme", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Principal", - "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "principal", - "Type": "System.Security.Claims.ClaimsPrincipal" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - }, - { - "Name": "authenticationScheme", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.AuthenticationToken", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Name", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Name", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Value", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Value", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.ClaimsTransformationContext", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Context", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpContext", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Principal", - "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Principal", - "Parameters": [ - { - "Name": "value", - "Type": "System.Security.Claims.ClaimsPrincipal" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.ClaimsTransformationHandler", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_PriorHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_PriorHandler", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AuthenticateAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.AuthenticateContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ChallengeAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetDescriptions", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.DescribeSchemesContext" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "SignInAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignInContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "SignOutAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignOutContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RegisterAuthenticationHandler", - "Parameters": [ - { - "Name": "auth", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.IHttpAuthenticationFeature" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "UnregisterAuthenticationHandler", - "Parameters": [ - { - "Name": "auth", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.IHttpAuthenticationFeature" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "transform", - "Type": "Microsoft.AspNetCore.Authentication.IClaimsTransformer" - }, - { - "Name": "httpContext", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.ClaimsTransformationMiddleware", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.ClaimsTransformationOptions", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Options", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Builder.ClaimsTransformationOptions" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Invoke", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.ClaimsTransformer", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IClaimsTransformer" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_OnTransform", - "Parameters": [], - "ReturnType": "System.Func>", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnTransform", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func>" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "TransformAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.ClaimsTransformationContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IClaimsTransformer", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.IClaimsTransformer", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "TransformAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.ClaimsTransformationContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.ISystemClock", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_UtcNow", - "Parameters": [], - "ReturnType": "System.DateTimeOffset", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "HandleRequestAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleRemoteCallbackAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleRemoteAuthenticateAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Abstract": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleAuthenticateAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleSignOutAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignOutContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleSignInAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignInContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleForbiddenAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GenerateCorrelationId", - "Parameters": [ - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ValidateCorrelationId", - "Parameters": [ - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Boolean", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Protected", - "GenericParameter": [] - } - ], - "GenericParameters": [ - { - "ParameterName": "TOptions", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [ - "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions" - ] - } - ] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.SharedAuthenticationOptions", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_SignInScheme", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_SignInScheme", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.SystemClock", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.ISystemClock" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_UtcNow", - "Parameters": [], - "ReturnType": "System.DateTimeOffset", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISystemClock", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.AuthenticationTokenExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "StoreTokens", - "Parameters": [ - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - }, - { - "Name": "tokens", - "Type": "System.Collections.Generic.IEnumerable" - } - ], - "ReturnType": "System.Void", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetTokenValue", - "Parameters": [ - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - }, - { - "Name": "tokenName", - "Type": "System.String" - } - ], - "ReturnType": "System.String", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetTokens", - "Parameters": [ - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Collections.Generic.IEnumerable", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetTokenAsync", - "Parameters": [ - { - "Name": "manager", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationManager" - }, - { - "Name": "tokenName", - "Type": "System.String" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetTokenAsync", - "Parameters": [ - { - "Name": "manager", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationManager" - }, - { - "Name": "signInScheme", - "Type": "System.String" - }, - { - "Name": "tokenName", - "Type": "System.String" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.IDataSerializer", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Serialize", - "Parameters": [ - { - "Name": "model", - "Type": "T0" - } - ], - "ReturnType": "System.Byte[]", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Deserialize", - "Parameters": [ - { - "Name": "data", - "Type": "System.Byte[]" - } - ], - "ReturnType": "T0", - "GenericParameter": [] - } - ], - "GenericParameters": [ - { - "ParameterName": "TModel", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Protect", - "Parameters": [ - { - "Name": "data", - "Type": "T0" - } - ], - "ReturnType": "System.String", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Protect", - "Parameters": [ - { - "Name": "data", - "Type": "T0" - }, - { - "Name": "purpose", - "Type": "System.String" - } - ], - "ReturnType": "System.String", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Unprotect", - "Parameters": [ - { - "Name": "protectedText", - "Type": "System.String" - } - ], - "ReturnType": "T0", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Unprotect", - "Parameters": [ - { - "Name": "protectedText", - "Type": "System.String" - }, - { - "Name": "purpose", - "Type": "System.String" - } - ], - "ReturnType": "T0", - "GenericParameter": [] - } - ], - "GenericParameters": [ - { - "ParameterName": "TData", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.PropertiesDataFormat", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.SecureDataFormat", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "protector", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtector" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.PropertiesSerializer", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IDataSerializer" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_Default", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.PropertiesSerializer", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Serialize", - "Parameters": [ - { - "Name": "model", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Byte[]", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Deserialize", - "Parameters": [ - { - "Name": "data", - "Type": "System.Byte[]" - } - ], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Write", - "Parameters": [ - { - "Name": "writer", - "Type": "System.IO.BinaryWriter" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Read", - "Parameters": [ - { - "Name": "reader", - "Type": "System.IO.BinaryReader" - } - ], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Virtual": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.SecureDataFormat", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.ISecureDataFormat" - ], - "Members": [ - { - "Kind": "Method", - "Name": "Protect", - "Parameters": [ - { - "Name": "data", - "Type": "T0" - } - ], - "ReturnType": "System.String", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Protect", - "Parameters": [ - { - "Name": "data", - "Type": "T0" - }, - { - "Name": "purpose", - "Type": "System.String" - } - ], - "ReturnType": "System.String", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Unprotect", - "Parameters": [ - { - "Name": "protectedText", - "Type": "System.String" - } - ], - "ReturnType": "T0", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Unprotect", - "Parameters": [ - { - "Name": "protectedText", - "Type": "System.String" - }, - { - "Name": "purpose", - "Type": "System.String" - } - ], - "ReturnType": "T0", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "serializer", - "Type": "Microsoft.AspNetCore.Authentication.IDataSerializer" - }, - { - "Name": "protector", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtector" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [ - { - "ParameterName": "TData", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.Base64UrlTextEncoder", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "Encode", - "Parameters": [ - { - "Name": "data", - "Type": "System.Byte[]" - } - ], - "ReturnType": "System.String", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Decode", - "Parameters": [ - { - "Name": "text", - "Type": "System.String" - } - ], - "ReturnType": "System.Byte[]", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.TicketDataFormat", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.SecureDataFormat", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "protector", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtector" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.TicketSerializer", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IDataSerializer" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_Default", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.TicketSerializer", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Serialize", - "Parameters": [ - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - } - ], - "ReturnType": "System.Byte[]", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Deserialize", - "Parameters": [ - { - "Name": "data", - "Type": "System.Byte[]" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Write", - "Parameters": [ - { - "Name": "writer", - "Type": "System.IO.BinaryWriter" - }, - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "WriteIdentity", - "Parameters": [ - { - "Name": "writer", - "Type": "System.IO.BinaryWriter" - }, - { - "Name": "identity", - "Type": "System.Security.Claims.ClaimsIdentity" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "WriteClaim", - "Parameters": [ - { - "Name": "writer", - "Type": "System.IO.BinaryWriter" - }, - { - "Name": "claim", - "Type": "System.Security.Claims.Claim" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Read", - "Parameters": [ - { - "Name": "reader", - "Type": "System.IO.BinaryReader" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", - "Virtual": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ReadIdentity", - "Parameters": [ - { - "Name": "reader", - "Type": "System.IO.BinaryReader" - } - ], - "ReturnType": "System.Security.Claims.ClaimsIdentity", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ReadClaim", - "Parameters": [ - { - "Name": "reader", - "Type": "System.IO.BinaryReader" - }, - { - "Name": "identity", - "Type": "System.Security.Claims.ClaimsIdentity" - } - ], - "ReturnType": "System.Security.Claims.Claim", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.BaseContext", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_HttpContext", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpContext", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Request", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpRequest", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Response", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpResponse", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - } - ], - "Visibility": "Protected", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.BaseControlContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_State", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.EventResultState", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_State", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.EventResultState" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_HandledResponse", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Skipped", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleResponse", - "Parameters": [], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "SkipToNextMiddleware", - "Parameters": [], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Ticket", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Ticket", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "CheckEventResult", - "Parameters": [ - { - "Name": "result", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticateResult", - "Direction": "Out" - } - ], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - } - ], - "Visibility": "Protected", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.EventResultState", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "Continue", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "Skipped", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - }, - { - "Kind": "Field", - "Name": "HandledResponse", - "Parameters": [], - "GenericParameter": [], - "Literal": "2" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.FailureContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseControlContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Failure", - "Parameters": [], - "ReturnType": "System.Exception", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Failure", - "Parameters": [ - { - "Name": "value", - "Type": "System.Exception" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "failure", - "Type": "System.Exception" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "RemoteFailure", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.FailureContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "TicketReceived", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.TicketReceivedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_OnRemoteFailure", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnRemoteFailure", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnTicketReceived", - "Parameters": [], - "ReturnType": "System.Func", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnTicketReceived", - "Parameters": [ - { - "Name": "value", - "Type": "System.Func" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RemoteFailure", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.FailureContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "TicketReceived", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.TicketReceivedContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.TicketReceivedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseControlContext", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Principal", - "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Principal", - "Parameters": [ - { - "Name": "value", - "Type": "System.Security.Claims.ClaimsPrincipal" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Properties", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Options", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ReturnUri", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ReturnUri", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions" - }, - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.Extensions.DependencyInjection.AuthenticationServiceCollectionExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "AddAuthentication", - "Parameters": [ - { - "Name": "services", - "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" - } - ], - "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddAuthentication", - "Parameters": [ - { - "Name": "services", - "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" - }, - { - "Name": "configureOptions", - "Type": "System.Action" - } - ], - "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - } - ], - "SourceFilters": [] -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/baseline.netcore.json b/src/Microsoft.AspNetCore.Authentication/baseline.netcore.json index 1f69da5a8..08eeb5e7b 100644 --- a/src/Microsoft.AspNetCore.Authentication/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Authentication/baseline.netcore.json @@ -1,488 +1,565 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Authentication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Authentication, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { - "Name": "Microsoft.AspNetCore.Builder.AuthenticationOptions", + "Name": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Visibility": "Public", "Kind": "Class", - "Abstract": true, "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_AuthenticationScheme", + "Name": "get_Services", "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_AuthenticationScheme", + "Name": "AddScheme", "Parameters": [ { - "Name": "value", + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" } ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AutomaticAuthenticate", - "Parameters": [], - "ReturnType": "System.Boolean", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Virtual": true, "Visibility": "Public", - "GenericParameter": [] + "GenericParameter": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] + }, + { + "ParameterName": "THandler", + "ParameterPosition": 1, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationHandler" + ] + } + ] }, { "Kind": "Method", - "Name": "set_AutomaticAuthenticate", + "Name": "AddScheme", "Parameters": [ { - "Name": "value", - "Type": "System.Boolean" + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" } ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AutomaticChallenge", - "Parameters": [], - "ReturnType": "System.Boolean", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Virtual": true, "Visibility": "Public", - "GenericParameter": [] + "GenericParameter": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] + }, + { + "ParameterName": "THandler", + "ParameterPosition": 1, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationHandler" + ] + } + ] }, { "Kind": "Method", - "Name": "set_AutomaticChallenge", + "Name": "AddRemoteScheme", "Parameters": [ { - "Name": "value", - "Type": "System.Boolean" + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" } ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ClaimsIssuer", - "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Virtual": true, "Visibility": "Public", - "GenericParameter": [] + "GenericParameter": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions" + ] + }, + { + "ParameterName": "THandler", + "ParameterPosition": 1, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler" + ] + } + ] }, { "Kind": "Method", - "Name": "set_ClaimsIssuer", + "Name": "AddPolicyScheme", "Parameters": [ { - "Name": "value", + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" } ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Description", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationDescription", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "set_Description", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationDescription" + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" } ], - "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Protected", - "GenericParameter": [] } ], "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Builder.ClaimsTransformationAppBuilderExtensions", + "Name": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", "Visibility": "Public", "Kind": "Class", "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authentication.IAuthenticationHandler" + ], "Members": [ { "Kind": "Method", - "Name": "UseClaimsTransformation", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, + "Name": "get_Scheme", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationScheme", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "UseClaimsTransformation", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "transform", - "Type": "System.Func>" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, + "Name": "get_Options", + "Parameters": [], + "ReturnType": "T0", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "UseClaimsTransformation", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.ClaimsTransformationOptions" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.ClaimsTransformationOptions", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Transformer", + "Name": "get_Context", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.IClaimsTransformer", - "Visibility": "Public", + "ReturnType": "Microsoft.AspNetCore.Http.HttpContext", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Transformer", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.IClaimsTransformer" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", + "Name": "get_Request", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Http.HttpRequest", + "Visibility": "Protected", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "get_Response", "Parameters": [], - "Visibility": "Public", + "ReturnType": "Microsoft.AspNetCore.Http.HttpResponse", + "Visibility": "Protected", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Builder.AuthenticationOptions", - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Method", - "Name": "get_BackchannelTimeout", + "Name": "get_OriginalPath", "Parameters": [], - "ReturnType": "System.TimeSpan", - "Visibility": "Public", + "ReturnType": "Microsoft.AspNetCore.Http.PathString", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_BackchannelTimeout", - "Parameters": [ - { - "Name": "value", - "Type": "System.TimeSpan" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", + "Name": "get_OriginalPathBase", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Http.PathString", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_BackchannelHttpHandler", + "Name": "get_Logger", "Parameters": [], - "ReturnType": "System.Net.Http.HttpMessageHandler", - "Visibility": "Public", + "ReturnType": "Microsoft.Extensions.Logging.ILogger", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_BackchannelHttpHandler", - "Parameters": [ - { - "Name": "value", - "Type": "System.Net.Http.HttpMessageHandler" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", + "Name": "get_UrlEncoder", + "Parameters": [], + "ReturnType": "System.Text.Encodings.Web.UrlEncoder", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_CallbackPath", + "Name": "get_Clock", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Visibility": "Public", + "ReturnType": "Microsoft.AspNetCore.Authentication.ISystemClock", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_CallbackPath", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.PathString" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", + "Name": "get_OptionsMonitor", + "Parameters": [], + "ReturnType": "Microsoft.Extensions.Options.IOptionsMonitor", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_SignInScheme", + "Name": "get_Events", "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", + "ReturnType": "System.Object", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_SignInScheme", + "Name": "set_Events", "Parameters": [ { "Name": "value", - "Type": "System.String" + "Type": "System.Object" } ], "ReturnType": "System.Void", - "Visibility": "Public", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_DisplayName", + "Name": "get_ClaimsIssuer", "Parameters": [], "ReturnType": "System.String", - "Visibility": "Public", + "Virtual": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_CurrentUri", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_DisplayName", + "Name": "InitializeAsync", "Parameters": [ { - "Name": "value", - "Type": "System.String" + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" } ], - "ReturnType": "System.Void", + "ReturnType": "System.Threading.Tasks.Task", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IAuthenticationHandler", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_RemoteAuthenticationTimeout", + "Name": "InitializeEventsAsync", "Parameters": [], - "ReturnType": "System.TimeSpan", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_RemoteAuthenticationTimeout", - "Parameters": [ - { - "Name": "value", - "Type": "System.TimeSpan" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", + "Name": "CreateEventsAsync", + "Parameters": [], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_SaveTokens", + "Name": "InitializeHandlerAsync", "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_SaveTokens", + "Name": "BuildRedirectUri", "Parameters": [ { - "Name": "value", - "Type": "System.Boolean" + "Name": "targetPath", + "Type": "System.String" } ], - "ReturnType": "System.Void", - "Visibility": "Public", + "ReturnType": "System.String", + "Visibility": "Protected", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", + "Kind": "Method", + "Name": "ResolveTarget", + "Parameters": [ + { + "Name": "scheme", + "Type": "System.String" + } + ], + "ReturnType": "System.String", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { - "Kind": "Field", - "Name": "Events", + "Kind": "Method", + "Name": "AuthenticateAsync", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents", + "ReturnType": "System.Threading.Tasks.Task", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IAuthenticationHandler", "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.AuthenticateResult", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Method", - "Name": "get_Succeeded", + "Name": "HandleAuthenticateOnceAsync", "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Ticket", + "Name": "HandleAuthenticateOnceSafeAsync", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Failure", + "Name": "HandleAuthenticateAsync", "Parameters": [], - "ReturnType": "System.Exception", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Abstract": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Skipped", - "Parameters": [], - "ReturnType": "System.Boolean", + "Name": "HandleForbiddenAsync", + "Parameters": [ + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleChallengeAsync", + "Parameters": [ + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ChallengeAsync", + "Parameters": [ + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IAuthenticationHandler", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Success", + "Name": "ForbidAsync", "Parameters": [ { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticateResult", - "Static": true, + "ReturnType": "System.Threading.Tasks.Task", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IAuthenticationHandler", "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" + }, + { + "Name": "logger", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "encoder", + "Type": "System.Text.Encodings.Web.UrlEncoder" + }, + { + "Name": "clock", + "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" + } + ], + "Visibility": "Protected", + "GenericParameter": [] + } + ], + "GenericParameters": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] + } + ] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "Skip", + "Name": "get_Schemes", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticateResult", - "Static": true, + "ReturnType": "Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Fail", + "Name": "set_Schemes", "Parameters": [ { - "Name": "failure", - "Type": "System.Exception" + "Name": "value", + "Type": "Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider" } ], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticateResult", - "Static": true, + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Fail", + "Name": "Invoke", "Parameters": [ { - "Name": "failureMessage", - "Type": "System.String" + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "next", + "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + }, + { + "Name": "schemes", + "Type": "Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider" } ], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticateResult", - "Static": true, "Visibility": "Public", "GenericParameter": [] } @@ -490,148 +567,154 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "Name": "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", "Visibility": "Public", "Kind": "Class", - "Abstract": true, - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler" - ], + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_SignInAccepted", + "Name": "Validate", "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Protected", + "ReturnType": "System.Void", + "Virtual": true, + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_SignInAccepted", + "Name": "Validate", "Parameters": [ { - "Name": "value", - "Type": "System.Boolean" + "Name": "scheme", + "Type": "System.String" } ], "ReturnType": "System.Void", - "Visibility": "Protected", + "Virtual": true, + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_SignOutAccepted", + "Name": "get_ClaimsIssuer", "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Protected", + "ReturnType": "System.String", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_SignOutAccepted", + "Name": "set_ClaimsIssuer", "Parameters": [ { "Name": "value", - "Type": "System.Boolean" + "Type": "System.String" } ], "ReturnType": "System.Void", - "Visibility": "Protected", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_ChallengeCalled", + "Name": "get_Events", "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Protected", + "ReturnType": "System.Object", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_ChallengeCalled", + "Name": "set_Events", "Parameters": [ { "Name": "value", - "Type": "System.Boolean" + "Type": "System.Object" } ], "ReturnType": "System.Void", - "Visibility": "Protected", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Context", + "Name": "get_EventsType", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpContext", - "Visibility": "Protected", + "ReturnType": "System.Type", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Request", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpRequest", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Response", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpResponse", - "Visibility": "Protected", + "Name": "set_EventsType", + "Parameters": [ + { + "Name": "value", + "Type": "System.Type" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_OriginalPathBase", + "Name": "get_ForwardDefault", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Visibility": "Protected", + "ReturnType": "System.String", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_OriginalPath", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.PathString", - "Visibility": "Protected", + "Name": "set_ForwardDefault", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Logger", + "Name": "get_ForwardAuthenticate", "Parameters": [], - "ReturnType": "Microsoft.Extensions.Logging.ILogger", - "Visibility": "Protected", + "ReturnType": "System.String", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_UrlEncoder", - "Parameters": [], - "ReturnType": "System.Text.Encodings.Web.UrlEncoder", - "Visibility": "Protected", + "Name": "set_ForwardAuthenticate", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_PriorHandler", + "Name": "get_ForwardChallenge", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_PriorHandler", + "Name": "set_ForwardChallenge", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler" + "Type": "System.String" } ], "ReturnType": "System.Void", @@ -640,460 +723,480 @@ }, { "Kind": "Method", - "Name": "get_CurrentUri", + "Name": "get_ForwardForbid", "Parameters": [], "ReturnType": "System.String", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "T0", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "InitializeAsync", - "Parameters": [ - { - "Name": "options", - "Type": "T0" - }, - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "logger", - "Type": "Microsoft.Extensions.Logging.ILogger" - }, - { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" - } - ], - "ReturnType": "System.Threading.Tasks.Task", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "BuildRedirectUri", + "Name": "set_ForwardForbid", "Parameters": [ { - "Name": "targetPath", + "Name": "value", "Type": "System.String" } ], - "ReturnType": "System.String", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "FinishResponseAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "HandleRequestAsync", + "Name": "get_ForwardSignIn", "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetDescriptions", + "Name": "set_ForwardSignIn", "Parameters": [ { - "Name": "describeContext", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.DescribeSchemesContext" + "Name": "value", + "Type": "System.String" } ], "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "ShouldHandleScheme", - "Parameters": [ - { - "Name": "authenticationScheme", - "Type": "System.String" - }, - { - "Name": "handleAutomatic", - "Type": "System.Boolean" - } - ], - "ReturnType": "System.Boolean", + "Name": "get_ForwardSignOut", + "Parameters": [], + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "AuthenticateAsync", + "Name": "set_ForwardSignOut", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.AuthenticateContext" + "Name": "value", + "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "HandleAuthenticateOnceAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleAuthenticateAsync", + "Name": "get_ForwardDefaultSelector", "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Abstract": true, - "Visibility": "Protected", + "ReturnType": "System.Func", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "SignInAsync", + "Name": "set_ForwardDefaultSelector", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignInContext" + "Name": "value", + "Type": "System.Func" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.IDataSerializer", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "HandleSignInAsync", + "Name": "Serialize", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignInContext" + "Name": "model", + "Type": "T0" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", + "ReturnType": "System.Byte[]", "GenericParameter": [] }, { "Kind": "Method", - "Name": "SignOutAsync", + "Name": "Deserialize", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignOutContext" + "Name": "data", + "Type": "System.Byte[]" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", + "ReturnType": "T0", "GenericParameter": [] - }, + } + ], + "GenericParameters": [ + { + "ParameterName": "TModel", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [] + } + ] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "HandleSignOutAsync", + "Name": "Protect", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignOutContext" + "Name": "data", + "Type": "T0" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", + "ReturnType": "System.String", "GenericParameter": [] }, { "Kind": "Method", - "Name": "HandleForbiddenAsync", + "Name": "Protect", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" + "Name": "data", + "Type": "T0" + }, + { + "Name": "purpose", + "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", + "ReturnType": "System.String", "GenericParameter": [] }, { "Kind": "Method", - "Name": "HandleUnauthorizedAsync", + "Name": "Unprotect", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" + "Name": "protectedText", + "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", + "ReturnType": "T0", "GenericParameter": [] }, { "Kind": "Method", - "Name": "ChallengeAsync", + "Name": "Unprotect", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" + "Name": "protectedText", + "Type": "System.String" + }, + { + "Name": "purpose", + "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Protected", + "ReturnType": "T0", "GenericParameter": [] } ], "GenericParameters": [ { - "ParameterName": "TOptions", + "ParameterName": "TData", "ParameterPosition": 0, - "BaseTypeOrInterfaces": [ - "Microsoft.AspNetCore.Builder.AuthenticationOptions" - ] + "BaseTypeOrInterfaces": [] } ] }, { - "Name": "Microsoft.AspNetCore.Authentication.AuthenticationMiddleware", + "Name": "Microsoft.AspNetCore.Authentication.PropertiesDataFormat", "Visibility": "Public", "Kind": "Class", - "Abstract": true, + "BaseType": "Microsoft.AspNetCore.Authentication.SecureDataFormat", "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "protector", + "Type": "Microsoft.AspNetCore.DataProtection.IDataProtector" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.PropertiesSerializer", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authentication.IDataSerializer" + ], "Members": [ { "Kind": "Method", - "Name": "get_AuthenticationScheme", + "Name": "get_Default", "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "Microsoft.AspNetCore.Authentication.PropertiesSerializer", + "Static": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_AuthenticationScheme", + "Name": "Serialize", "Parameters": [ { - "Name": "value", - "Type": "System.String" + "Name": "model", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Void", + "ReturnType": "System.Byte[]", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "T0", + "Name": "Deserialize", + "Parameters": [ + { + "Name": "data", + "Type": "System.Byte[]" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationProperties", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Options", + "Name": "Write", "Parameters": [ { - "Name": "value", - "Type": "T0" + "Name": "writer", + "Type": "System.IO.BinaryWriter" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], "ReturnType": "System.Void", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Logger", - "Parameters": [], - "ReturnType": "Microsoft.Extensions.Logging.ILogger", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Logger", + "Name": "Read", "Parameters": [ { - "Name": "value", - "Type": "Microsoft.Extensions.Logging.ILogger" + "Name": "reader", + "Type": "System.IO.BinaryReader" } ], - "ReturnType": "System.Void", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationProperties", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "get_UrlEncoder", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [], - "ReturnType": "System.Text.Encodings.Web.UrlEncoder", "Visibility": "Public", "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.SecureDataFormat", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authentication.ISecureDataFormat" + ], + "Members": [ { "Kind": "Method", - "Name": "set_UrlEncoder", + "Name": "Protect", "Parameters": [ { - "Name": "value", - "Type": "System.Text.Encodings.Web.UrlEncoder" + "Name": "data", + "Type": "T0" } ], - "ReturnType": "System.Void", + "ReturnType": "System.String", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Invoke", + "Name": "Protect", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" + "Name": "data", + "Type": "T0" + }, + { + "Name": "purpose", + "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.String", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "CreateHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "Name": "Unprotect", + "Parameters": [ + { + "Name": "protectedText", + "Type": "System.String" + } + ], + "ReturnType": "T0", + "Sealed": true, "Virtual": true, - "Abstract": true, - "Visibility": "Protected", + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", + "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "Unprotect", "Parameters": [ { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + "Name": "protectedText", + "Type": "System.String" }, { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" - }, + "Name": "purpose", + "Type": "System.String" + } + ], + "ReturnType": "T0", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ { - "Name": "loggerFactory", - "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + "Name": "serializer", + "Type": "Microsoft.AspNetCore.Authentication.IDataSerializer" }, { - "Name": "encoder", - "Type": "System.Text.Encodings.Web.UrlEncoder" + "Name": "protector", + "Type": "Microsoft.AspNetCore.DataProtection.IDataProtector" } ], - "Visibility": "Protected", + "Visibility": "Public", "GenericParameter": [] } ], "GenericParameters": [ { - "ParameterName": "TOptions", + "ParameterName": "TData", "ParameterPosition": 0, - "New": true, - "BaseTypeOrInterfaces": [ - "Microsoft.AspNetCore.Builder.AuthenticationOptions" - ] + "BaseTypeOrInterfaces": [] } ] }, { - "Name": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", + "Name": "Microsoft.AspNetCore.Authentication.Base64UrlTextEncoder", "Visibility": "Public", "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_AuthenticationScheme", - "Parameters": [], + "Name": "Encode", + "Parameters": [ + { + "Name": "data", + "Type": "System.Byte[]" + } + ], "ReturnType": "System.String", + "Static": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Principal", - "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Properties", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", + "Name": "Decode", + "Parameters": [ + { + "Name": "text", + "Type": "System.String" + } + ], + "ReturnType": "System.Byte[]", + "Static": true, "Visibility": "Public", "GenericParameter": [] - }, + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.TicketDataFormat", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.SecureDataFormat", + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Constructor", "Name": ".ctor", "Parameters": [ { - "Name": "principal", - "Type": "System.Security.Claims.ClaimsPrincipal" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - }, - { - "Name": "authenticationScheme", - "Type": "System.String" + "Name": "protector", + "Type": "Microsoft.AspNetCore.DataProtection.IDataProtector" } ], "Visibility": "Public", @@ -1103,245 +1206,206 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.AuthenticationToken", + "Name": "Microsoft.AspNetCore.Authentication.TicketSerializer", "Visibility": "Public", "Kind": "Class", - "ImplementedInterfaces": [], + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authentication.IDataSerializer" + ], "Members": [ { "Kind": "Method", - "Name": "get_Name", + "Name": "get_Default", "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "Microsoft.AspNetCore.Authentication.TicketSerializer", + "Static": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Name", + "Name": "Serialize", "Parameters": [ { - "Name": "value", - "Type": "System.String" + "Name": "ticket", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" } ], - "ReturnType": "System.Void", + "ReturnType": "System.Byte[]", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Value", - "Parameters": [], - "ReturnType": "System.String", + "Name": "Deserialize", + "Parameters": [ + { + "Name": "data", + "Type": "System.Byte[]" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Value", + "Name": "Write", "Parameters": [ { - "Name": "value", - "Type": "System.String" + "Name": "writer", + "Type": "System.IO.BinaryWriter" + }, + { + "Name": "ticket", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" } ], "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.ClaimsTransformationContext", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Context", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpContext", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Principal", - "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Principal", + "Name": "WriteIdentity", "Parameters": [ { - "Name": "value", - "Type": "System.Security.Claims.ClaimsPrincipal" + "Name": "writer", + "Type": "System.IO.BinaryWriter" + }, + { + "Name": "identity", + "Type": "System.Security.Claims.ClaimsIdentity" } ], "ReturnType": "System.Void", - "Visibility": "Public", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", + "Kind": "Method", + "Name": "WriteClaim", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" + "Name": "writer", + "Type": "System.IO.BinaryWriter" + }, + { + "Name": "claim", + "Type": "System.Security.Claims.Claim" } ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.ClaimsTransformationHandler", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_PriorHandler", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", + "ReturnType": "System.Void", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_PriorHandler", + "Name": "Read", "Parameters": [ { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler" + "Name": "reader", + "Type": "System.IO.BinaryReader" } ], - "ReturnType": "System.Void", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "AuthenticateAsync", + "Name": "ReadIdentity", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.AuthenticateContext" + "Name": "reader", + "Type": "System.IO.BinaryReader" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, + "ReturnType": "System.Security.Claims.ClaimsIdentity", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "ChallengeAsync", + "Name": "ReadClaim", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" + "Name": "reader", + "Type": "System.IO.BinaryReader" + }, + { + "Name": "identity", + "Type": "System.Security.Claims.ClaimsIdentity" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, + "ReturnType": "System.Security.Claims.Claim", "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", - "Visibility": "Public", + "Visibility": "Protected", "GenericParameter": [] }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.BaseContext", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ { "Kind": "Method", - "Name": "GetDescriptions", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.DescribeSchemesContext" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", + "Name": "get_Scheme", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationScheme", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "SignInAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignInContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", + "Name": "get_Options", + "Parameters": [], + "ReturnType": "T0", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "SignOutAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignOutContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Http.Features.Authentication.IAuthenticationHandler", + "Name": "get_HttpContext", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Http.HttpContext", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "RegisterAuthenticationHandler", - "Parameters": [ - { - "Name": "auth", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.IHttpAuthenticationFeature" - } - ], - "ReturnType": "System.Void", + "Name": "get_Request", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Http.HttpRequest", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "UnregisterAuthenticationHandler", - "Parameters": [ - { - "Name": "auth", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.IHttpAuthenticationFeature" - } - ], - "ReturnType": "System.Void", + "Name": "get_Response", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Http.HttpResponse", "Visibility": "Public", "GenericParameter": [] }, @@ -1350,57 +1414,73 @@ "Name": ".ctor", "Parameters": [ { - "Name": "transform", - "Type": "Microsoft.AspNetCore.Authentication.IClaimsTransformer" + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" }, { - "Name": "httpContext", - "Type": "Microsoft.AspNetCore.Http.HttpContext" + "Name": "options", + "Type": "T0" } ], - "Visibility": "Public", + "Visibility": "Protected", "GenericParameter": [] } ], - "GenericParameters": [] + "GenericParameters": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] + } + ] }, { - "Name": "Microsoft.AspNetCore.Authentication.ClaimsTransformationMiddleware", + "Name": "Microsoft.AspNetCore.Authentication.HandleRequestContext", "Visibility": "Public", "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.BaseContext", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_Options", + "Name": "get_Result", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.ClaimsTransformationOptions", + "ReturnType": "Microsoft.AspNetCore.Authentication.HandleRequestResult", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Options", + "Name": "set_Result", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Builder.ClaimsTransformationOptions" + "Type": "Microsoft.AspNetCore.Authentication.HandleRequestResult" } ], "ReturnType": "System.Void", + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleResponse", + "Parameters": [], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Invoke", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", + "Name": "SkipHandler", + "Parameters": [], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, @@ -1409,237 +1489,150 @@ "Name": ".ctor", "Parameters": [ { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" }, { "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" + "Type": "T0" } ], - "Visibility": "Public", + "Visibility": "Protected", "GenericParameter": [] } ], - "GenericParameters": [] + "GenericParameters": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] + } + ] }, { - "Name": "Microsoft.AspNetCore.Authentication.ClaimsTransformer", + "Name": "Microsoft.AspNetCore.Authentication.PrincipalContext", "Visibility": "Public", "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IClaimsTransformer" - ], + "Abstract": true, + "BaseType": "Microsoft.AspNetCore.Authentication.PropertiesContext", + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_OnTransform", + "Name": "get_Principal", "Parameters": [], - "ReturnType": "System.Func>", + "ReturnType": "System.Security.Claims.ClaimsPrincipal", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_OnTransform", + "Name": "set_Principal", "Parameters": [ { "Name": "value", - "Type": "System.Func>" + "Type": "System.Security.Claims.ClaimsPrincipal" } ], "ReturnType": "System.Void", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "TransformAsync", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.ClaimsTransformationContext" + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "T0" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IClaimsTransformer", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.IClaimsTransformer", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "TransformAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.ClaimsTransformationContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", + "Visibility": "Protected", "GenericParameter": [] } ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.ISystemClock", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ + "GenericParameters": [ { - "Kind": "Method", - "Name": "get_UtcNow", - "Parameters": [], - "ReturnType": "System.DateTimeOffset", - "GenericParameter": [] + "ParameterName": "TOptions", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] } - ], - "GenericParameters": [] + ] }, { - "Name": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler", + "Name": "Microsoft.AspNetCore.Authentication.PropertiesContext", "Visibility": "Public", "Kind": "Class", "Abstract": true, - "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "BaseType": "Microsoft.AspNetCore.Authentication.BaseContext", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "HandleRequestAsync", + "Name": "get_Properties", "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationProperties", "Virtual": true, - "Override": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "HandleRemoteCallbackAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleRemoteAuthenticateAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Abstract": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleAuthenticateAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleSignOutAsync", + "Name": "set_Properties", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignOutContext" + "Name": "value", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", "Virtual": true, - "Override": true, "Visibility": "Protected", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "HandleSignInAsync", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.SignInContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleForbiddenAsync", - "Parameters": [ + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.Features.Authentication.ChallengeContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GenerateCorrelationId", - "Parameters": [ + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - } - ], - "ReturnType": "System.Void", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "ValidateCorrelationId", - "Parameters": [ + "Name": "options", + "Type": "T0" + }, { "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Boolean", - "Virtual": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], "Visibility": "Protected", "GenericParameter": [] } @@ -1649,20 +1642,21 @@ "ParameterName": "TOptions", "ParameterPosition": 0, "BaseTypeOrInterfaces": [ - "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions" + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" ] } ] }, { - "Name": "Microsoft.AspNetCore.Authentication.SharedAuthenticationOptions", + "Name": "Microsoft.AspNetCore.Authentication.RedirectContext", "Visibility": "Public", "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.PropertiesContext", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_SignInScheme", + "Name": "get_RedirectUri", "Parameters": [], "ReturnType": "System.String", "Visibility": "Public", @@ -1670,7 +1664,7 @@ }, { "Kind": "Method", - "Name": "set_SignInScheme", + "Name": "set_RedirectUri", "Parameters": [ { "Name": "value", @@ -1684,277 +1678,243 @@ { "Kind": "Constructor", "Name": ".ctor", - "Parameters": [], + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "T0" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + }, + { + "Name": "redirectUri", + "Type": "System.String" + } + ], "Visibility": "Public", "GenericParameter": [] } ], - "GenericParameters": [] + "GenericParameters": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] + } + ] }, { - "Name": "Microsoft.AspNetCore.Authentication.SystemClock", + "Name": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", "Visibility": "Public", "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.ISystemClock" - ], + "Abstract": true, + "BaseType": "Microsoft.AspNetCore.Authentication.HandleRequestContext", + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_UtcNow", + "Name": "get_Principal", "Parameters": [], - "ReturnType": "System.DateTimeOffset", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISystemClock", + "ReturnType": "System.Security.Claims.ClaimsPrincipal", "Visibility": "Public", "GenericParameter": [] }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.AuthenticationTokenExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ { "Kind": "Method", - "Name": "StoreTokens", + "Name": "set_Principal", "Parameters": [ { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - }, - { - "Name": "tokens", - "Type": "System.Collections.Generic.IEnumerable" + "Name": "value", + "Type": "System.Security.Claims.ClaimsPrincipal" } ], "ReturnType": "System.Void", - "Static": true, - "Extension": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetTokenValue", - "Parameters": [ - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" - }, - { - "Name": "tokenName", - "Type": "System.String" - } - ], - "ReturnType": "System.String", - "Static": true, - "Extension": true, + "Name": "get_Properties", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationProperties", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetTokens", + "Name": "set_Properties", "Parameters": [ { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Name": "value", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Collections.Generic.IEnumerable", - "Static": true, - "Extension": true, + "ReturnType": "System.Void", + "Virtual": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Success", + "Parameters": [], + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetTokenAsync", + "Name": "Fail", "Parameters": [ { - "Name": "manager", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationManager" - }, - { - "Name": "tokenName", - "Type": "System.String" + "Name": "failure", + "Type": "System.Exception" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Static": true, - "Extension": true, + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "GetTokenAsync", + "Name": "Fail", "Parameters": [ { - "Name": "manager", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationManager" - }, - { - "Name": "signInScheme", - "Type": "System.String" - }, - { - "Name": "tokenName", + "Name": "failureMessage", "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Static": true, - "Extension": true, + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.IDataSerializer", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ + }, { - "Kind": "Method", - "Name": "Serialize", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { - "Name": "model", + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", "Type": "T0" - } - ], - "ReturnType": "System.Byte[]", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Deserialize", - "Parameters": [ + }, { - "Name": "data", - "Type": "System.Byte[]" + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "T0", + "Visibility": "Protected", "GenericParameter": [] } ], "GenericParameters": [ { - "ParameterName": "TModel", + "ParameterName": "TOptions", "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] } ] }, { - "Name": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", + "Name": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, + "Kind": "Class", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "Protect", + "Name": "get_OnRemoteFailure", + "Parameters": [], + "ReturnType": "System.Func", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_OnRemoteFailure", "Parameters": [ { - "Name": "data", - "Type": "T0" + "Name": "value", + "Type": "System.Func" } ], - "ReturnType": "System.String", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Protect", + "Name": "get_OnTicketReceived", + "Parameters": [], + "ReturnType": "System.Func", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_OnTicketReceived", "Parameters": [ { - "Name": "data", - "Type": "T0" - }, - { - "Name": "purpose", - "Type": "System.String" + "Name": "value", + "Type": "System.Func" } ], - "ReturnType": "System.String", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Unprotect", + "Name": "RemoteFailure", "Parameters": [ { - "Name": "protectedText", - "Type": "System.String" + "Name": "context", + "Type": "Microsoft.AspNetCore.Authentication.RemoteFailureContext" } ], - "ReturnType": "T0", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Unprotect", + "Name": "TicketReceived", "Parameters": [ { - "Name": "protectedText", - "Type": "System.String" - }, - { - "Name": "purpose", - "Type": "System.String" + "Name": "context", + "Type": "Microsoft.AspNetCore.Authentication.TicketReceivedContext" } ], - "ReturnType": "T0", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [ - { - "ParameterName": "TData", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.PropertiesDataFormat", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.SecureDataFormat", - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Constructor", "Name": ".ctor", - "Parameters": [ - { - "Name": "protector", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtector" - } - ], + "Parameters": [], "Visibility": "Public", "GenericParameter": [] } @@ -1962,88 +1922,75 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.PropertiesSerializer", + "Name": "Microsoft.AspNetCore.Authentication.RemoteFailureContext", "Visibility": "Public", "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IDataSerializer" - ], + "BaseType": "Microsoft.AspNetCore.Authentication.HandleRequestContext", + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_Default", + "Name": "get_Failure", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.PropertiesSerializer", - "Static": true, + "ReturnType": "System.Exception", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Serialize", + "Name": "set_Failure", "Parameters": [ { - "Name": "model", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Name": "value", + "Type": "System.Exception" } ], - "ReturnType": "System.Byte[]", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Deserialize", - "Parameters": [ - { - "Name": "data", - "Type": "System.Byte[]" - } - ], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", + "Name": "get_Properties", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationProperties", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Write", + "Name": "set_Properties", "Parameters": [ { - "Name": "writer", - "Type": "System.IO.BinaryWriter" - }, - { - "Name": "properties", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Name": "value", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], "ReturnType": "System.Void", - "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { - "Kind": "Method", - "Name": "Read", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [ { - "Name": "reader", - "Type": "System.IO.BinaryReader" + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions" + }, + { + "Name": "failure", + "Type": "System.Exception" } ], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", - "Virtual": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], "Visibility": "Public", "GenericParameter": [] } @@ -2051,82 +1998,102 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.SecureDataFormat", + "Name": "Microsoft.AspNetCore.Authentication.ResultContext", "Visibility": "Public", "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.ISecureDataFormat" - ], + "Abstract": true, + "BaseType": "Microsoft.AspNetCore.Authentication.BaseContext", + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "Protect", - "Parameters": [ - { - "Name": "data", - "Type": "T0" - } - ], - "ReturnType": "System.String", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", + "Name": "get_Principal", + "Parameters": [], + "ReturnType": "System.Security.Claims.ClaimsPrincipal", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Protect", + "Name": "set_Principal", "Parameters": [ { - "Name": "data", - "Type": "T0" - }, - { - "Name": "purpose", - "Type": "System.String" + "Name": "value", + "Type": "System.Security.Claims.ClaimsPrincipal" } ], - "ReturnType": "System.String", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Unprotect", + "Name": "get_Properties", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationProperties", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Properties", "Parameters": [ { - "Name": "protectedText", - "Type": "System.String" + "Name": "value", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "T0", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Unprotect", - "Parameters": [ - { - "Name": "protectedText", - "Type": "System.String" - }, + "Name": "get_Result", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticateResult", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Success", + "Parameters": [], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "NoResult", + "Parameters": [], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Fail", + "Parameters": [ { - "Name": "purpose", + "Name": "failure", + "Type": "System.Exception" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Fail", + "Parameters": [ + { + "Name": "failureMessage", "Type": "System.String" } ], - "ReturnType": "T0", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISecureDataFormat", + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, @@ -2135,80 +2102,79 @@ "Name": ".ctor", "Parameters": [ { - "Name": "serializer", - "Type": "Microsoft.AspNetCore.Authentication.IDataSerializer" + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" }, { - "Name": "protector", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtector" + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "T0" } ], - "Visibility": "Public", + "Visibility": "Protected", "GenericParameter": [] } ], "GenericParameters": [ { - "ParameterName": "TData", + "ParameterName": "TOptions", "ParameterPosition": 0, - "BaseTypeOrInterfaces": [] + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] } ] }, { - "Name": "Microsoft.AspNetCore.Authentication.Base64UrlTextEncoder", + "Name": "Microsoft.AspNetCore.Authentication.TicketReceivedContext", "Visibility": "Public", "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, + "BaseType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationContext", "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "Encode", - "Parameters": [ - { - "Name": "data", - "Type": "System.Byte[]" - } - ], + "Name": "get_ReturnUri", + "Parameters": [], "ReturnType": "System.String", - "Static": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Decode", + "Name": "set_ReturnUri", "Parameters": [ { - "Name": "text", + "Name": "value", "Type": "System.String" } ], - "ReturnType": "System.Byte[]", - "Static": true, + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.TicketDataFormat", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.SecureDataFormat", - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Constructor", "Name": ".ctor", "Parameters": [ { - "Name": "protector", - "Type": "Microsoft.AspNetCore.DataProtection.IDataProtector" + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "scheme", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme" + }, + { + "Name": "options", + "Type": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions" + }, + { + "Name": "ticket", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" } ], "Visibility": "Public", @@ -2218,150 +2184,122 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.TicketSerializer", + "Name": "Microsoft.AspNetCore.Authentication.HandleRequestResult", "Visibility": "Public", "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IDataSerializer" - ], + "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticateResult", + "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_Default", + "Name": "get_Handled", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.TicketSerializer", - "Static": true, + "ReturnType": "System.Boolean", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Serialize", - "Parameters": [ - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" - } - ], - "ReturnType": "System.Byte[]", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", + "Name": "get_Skipped", + "Parameters": [], + "ReturnType": "System.Boolean", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Deserialize", + "Name": "Success", "Parameters": [ { - "Name": "data", - "Type": "System.Byte[]" + "Name": "ticket", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" } ], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IDataSerializer", + "ReturnType": "Microsoft.AspNetCore.Authentication.HandleRequestResult", + "Static": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Write", + "Name": "Fail", "Parameters": [ { - "Name": "writer", - "Type": "System.IO.BinaryWriter" - }, - { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" + "Name": "failure", + "Type": "System.Exception" } ], - "ReturnType": "System.Void", - "Virtual": true, + "ReturnType": "Microsoft.AspNetCore.Authentication.HandleRequestResult", + "Static": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "WriteIdentity", + "Name": "Fail", "Parameters": [ { - "Name": "writer", - "Type": "System.IO.BinaryWriter" + "Name": "failure", + "Type": "System.Exception" }, { - "Name": "identity", - "Type": "System.Security.Claims.ClaimsIdentity" + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "System.Void", - "Virtual": true, - "Visibility": "Protected", + "ReturnType": "Microsoft.AspNetCore.Authentication.HandleRequestResult", + "Static": true, + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "WriteClaim", + "Name": "Fail", "Parameters": [ { - "Name": "writer", - "Type": "System.IO.BinaryWriter" - }, - { - "Name": "claim", - "Type": "System.Security.Claims.Claim" + "Name": "failureMessage", + "Type": "System.String" } ], - "ReturnType": "System.Void", - "Virtual": true, - "Visibility": "Protected", + "ReturnType": "Microsoft.AspNetCore.Authentication.HandleRequestResult", + "Static": true, + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "Read", + "Name": "Fail", "Parameters": [ { - "Name": "reader", - "Type": "System.IO.BinaryReader" + "Name": "failureMessage", + "Type": "System.String" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", - "Virtual": true, + "ReturnType": "Microsoft.AspNetCore.Authentication.HandleRequestResult", + "Static": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "ReadIdentity", - "Parameters": [ - { - "Name": "reader", - "Type": "System.IO.BinaryReader" - } - ], - "ReturnType": "System.Security.Claims.ClaimsIdentity", - "Virtual": true, - "Visibility": "Protected", + "Name": "Handle", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.HandleRequestResult", + "Static": true, + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "ReadClaim", - "Parameters": [ - { - "Name": "reader", - "Type": "System.IO.BinaryReader" - }, - { - "Name": "identity", - "Type": "System.Security.Claims.ClaimsIdentity" - } - ], - "ReturnType": "System.Security.Claims.Claim", - "Virtual": true, - "Visibility": "Protected", + "Name": "SkipHandler", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.HandleRequestResult", + "Static": true, + "Visibility": "Public", "GenericParameter": [] }, { @@ -2375,34 +2313,101 @@ "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.BaseContext", + "Name": "Microsoft.AspNetCore.Authentication.ISystemClock", "Visibility": "Public", - "Kind": "Class", + "Kind": "Interface", "Abstract": true, "ImplementedInterfaces": [], "Members": [ { "Kind": "Method", - "Name": "get_HttpContext", + "Name": "get_UtcNow", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpContext", - "Visibility": "Public", + "ReturnType": "System.DateTimeOffset", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.PolicySchemeHandler", + "Visibility": "Public", + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.SignInAuthenticationHandler", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "HandleChallengeAsync", + "Parameters": [ + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Request", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpRequest", - "Visibility": "Public", + "Name": "HandleForbiddenAsync", + "Parameters": [ + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Response", + "Name": "HandleSignInAsync", + "Parameters": [ + { + "Name": "user", + "Type": "System.Security.Claims.ClaimsPrincipal" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleSignOutAsync", + "Parameters": [ + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleAuthenticateAsync", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpResponse", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { @@ -2410,109 +2415,174 @@ "Name": ".ctor", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" + }, + { + "Name": "logger", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "encoder", + "Type": "System.Text.Encodings.Web.UrlEncoder" + }, + { + "Name": "clock", + "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" } ], - "Visibility": "Protected", + "Visibility": "Public", "GenericParameter": [] } ], "GenericParameters": [] }, { - "Name": "Microsoft.AspNetCore.Authentication.BaseControlContext", + "Name": "Microsoft.AspNetCore.Authentication.PolicySchemeOptions", "Visibility": "Public", "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseContext", + "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", "ImplementedInterfaces": [], "Members": [ { - "Kind": "Method", - "Name": "get_State", + "Kind": "Constructor", + "Name": ".ctor", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.EventResultState", "Visibility": "Public", "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authentication.IAuthenticationRequestHandler" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_SignInScheme", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Events", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", + "Visibility": "Protected", + "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_State", + "Name": "set_Events", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.EventResultState" + "Type": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents" } ], "ReturnType": "System.Void", - "Visibility": "Public", + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_HandledResponse", + "Name": "CreateEventsAsync", "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Skipped", + "Name": "ShouldHandleRequestAsync", "Parameters": [], - "ReturnType": "System.Boolean", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "HandleResponse", + "Name": "HandleRequestAsync", "Parameters": [], - "ReturnType": "System.Void", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IAuthenticationRequestHandler", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "SkipToNextMiddleware", + "Name": "HandleRemoteAuthenticateAsync", "Parameters": [], - "ReturnType": "System.Void", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Abstract": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "get_Ticket", + "Name": "HandleAuthenticateAsync", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationTicket", - "Visibility": "Public", + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Ticket", + "Name": "HandleForbiddenAsync", "Parameters": [ { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Override": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "GenerateCorrelationId", + "Parameters": [ + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], "ReturnType": "System.Void", - "Visibility": "Public", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { "Kind": "Method", - "Name": "CheckEventResult", + "Name": "ValidateCorrelationId", "Parameters": [ { - "Name": "result", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticateResult", - "Direction": "Out" + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" } ], "ReturnType": "System.Boolean", - "Visibility": "Public", + "Virtual": true, + "Visibility": "Protected", "GenericParameter": [] }, { @@ -2520,69 +2590,84 @@ "Name": ".ctor", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" + }, + { + "Name": "logger", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + }, + { + "Name": "encoder", + "Type": "System.Text.Encodings.Web.UrlEncoder" + }, + { + "Name": "clock", + "Type": "Microsoft.AspNetCore.Authentication.ISystemClock" } ], "Visibility": "Protected", "GenericParameter": [] } ], - "GenericParameters": [] + "GenericParameters": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions" + ] + } + ] }, { - "Name": "Microsoft.AspNetCore.Authentication.EventResultState", + "Name": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions", "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, + "Kind": "Class", + "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions", "ImplementedInterfaces": [], "Members": [ { - "Kind": "Field", - "Name": "Continue", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" + "Kind": "Method", + "Name": "Validate", + "Parameters": [ + { + "Name": "scheme", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] }, { - "Kind": "Field", - "Name": "Skipped", + "Kind": "Method", + "Name": "Validate", "Parameters": [], - "GenericParameter": [], - "Literal": "1" + "ReturnType": "System.Void", + "Virtual": true, + "Override": true, + "Visibility": "Public", + "GenericParameter": [] }, - { - "Kind": "Field", - "Name": "HandledResponse", - "Parameters": [], - "GenericParameter": [], - "Literal": "2" - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.FailureContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseControlContext", - "ImplementedInterfaces": [], - "Members": [ { "Kind": "Method", - "Name": "get_Failure", + "Name": "get_BackchannelTimeout", "Parameters": [], - "ReturnType": "System.Exception", + "ReturnType": "System.TimeSpan", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Failure", + "Name": "set_BackchannelTimeout", "Parameters": [ { "Name": "value", - "Type": "System.Exception" + "Type": "System.TimeSpan" } ], "ReturnType": "System.Void", @@ -2590,81 +2675,62 @@ "GenericParameter": [] }, { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "failure", - "Type": "System.Exception" - } - ], + "Kind": "Method", + "Name": "get_BackchannelHttpHandler", + "Parameters": [], + "ReturnType": "System.Net.Http.HttpMessageHandler", "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ + }, { "Kind": "Method", - "Name": "RemoteFailure", + "Name": "set_BackchannelHttpHandler", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.FailureContext" + "Name": "value", + "Type": "System.Net.Http.HttpMessageHandler" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "TicketReceived", + "Name": "get_Backchannel", + "Parameters": [], + "ReturnType": "System.Net.Http.HttpClient", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_Backchannel", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.TicketReceivedContext" + "Name": "value", + "Type": "System.Net.Http.HttpClient" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Void", + "Visibility": "Public", "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents" - ], - "Members": [ + }, { "Kind": "Method", - "Name": "get_OnRemoteFailure", + "Name": "get_DataProtectionProvider", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_OnRemoteFailure", + "Name": "set_DataProtectionProvider", "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider" } ], "ReturnType": "System.Void", @@ -2673,19 +2739,19 @@ }, { "Kind": "Method", - "Name": "get_OnTicketReceived", + "Name": "get_CallbackPath", "Parameters": [], - "ReturnType": "System.Func", + "ReturnType": "Microsoft.AspNetCore.Http.PathString", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_OnTicketReceived", + "Name": "set_CallbackPath", "Parameters": [ { "Name": "value", - "Type": "System.Func" + "Type": "Microsoft.AspNetCore.Http.PathString" } ], "ReturnType": "System.Void", @@ -2694,66 +2760,40 @@ }, { "Kind": "Method", - "Name": "RemoteFailure", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.FailureContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents", + "Name": "get_SignInScheme", + "Parameters": [], + "ReturnType": "System.String", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "TicketReceived", + "Name": "set_SignInScheme", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authentication.TicketReceivedContext" + "Name": "value", + "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IRemoteAuthenticationEvents", + "ReturnType": "System.Void", "Visibility": "Public", "GenericParameter": [] }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authentication.TicketReceivedContext", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authentication.BaseControlContext", - "ImplementedInterfaces": [], - "Members": [ { "Kind": "Method", - "Name": "get_Principal", + "Name": "get_RemoteAuthenticationTimeout", "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", + "ReturnType": "System.TimeSpan", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Principal", + "Name": "set_RemoteAuthenticationTimeout", "Parameters": [ { "Name": "value", - "Type": "System.Security.Claims.ClaimsPrincipal" + "Type": "System.TimeSpan" } ], "ReturnType": "System.Void", @@ -2762,19 +2802,19 @@ }, { "Kind": "Method", - "Name": "get_Properties", + "Name": "get_Events", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties", + "ReturnType": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Properties", + "Name": "set_Events", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties" + "Type": "Microsoft.AspNetCore.Authentication.RemoteAuthenticationEvents" } ], "ReturnType": "System.Void", @@ -2783,19 +2823,19 @@ }, { "Kind": "Method", - "Name": "get_Options", + "Name": "get_SaveTokens", "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions", + "ReturnType": "System.Boolean", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_Options", + "Name": "set_SaveTokens", "Parameters": [ { "Name": "value", - "Type": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions" + "Type": "System.Boolean" } ], "ReturnType": "System.Void", @@ -2804,19 +2844,19 @@ }, { "Kind": "Method", - "Name": "get_ReturnUri", + "Name": "get_CorrelationCookie", "Parameters": [], - "ReturnType": "System.String", + "ReturnType": "Microsoft.AspNetCore.Http.CookieBuilder", "Visibility": "Public", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_ReturnUri", + "Name": "set_CorrelationCookie", "Parameters": [ { "Name": "value", - "Type": "System.String" + "Type": "Microsoft.AspNetCore.Http.CookieBuilder" } ], "ReturnType": "System.Void", @@ -2826,24 +2866,227 @@ { "Kind": "Constructor", "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.SignInAuthenticationHandler", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "BaseType": "Microsoft.AspNetCore.Authentication.SignOutAuthenticationHandler", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authentication.IAuthenticationSignInHandler" + ], + "Members": [ + { + "Kind": "Method", + "Name": "SignInAsync", "Parameters": [ { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" + "Name": "user", + "Type": "System.Security.Claims.ClaimsPrincipal" }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IAuthenticationSignInHandler", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleSignInAsync", + "Parameters": [ + { + "Name": "user", + "Type": "System.Security.Claims.ClaimsPrincipal" + }, + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Abstract": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ { "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions" + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" }, { - "Name": "ticket", - "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket" + "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": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] + } + ] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.SignOutAuthenticationHandler", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authentication.IAuthenticationSignOutHandler" + ], + "Members": [ + { + "Kind": "Method", + "Name": "SignOutAsync", + "Parameters": [ + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.IAuthenticationSignOutHandler", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "HandleSignOutAsync", + "Parameters": [ + { + "Name": "properties", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "Abstract": true, + "Visibility": "Protected", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptionsMonitor" + }, + { + "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": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] + } + ] + }, + { + "Name": "Microsoft.AspNetCore.Authentication.SystemClock", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authentication.ISystemClock" + ], + "Members": [ + { + "Kind": "Method", + "Name": "get_UtcNow", + "Parameters": [], + "ReturnType": "System.DateTimeOffset", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authentication.ISystemClock", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Builder.AuthAppBuilderExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "UseAuthentication", + "Parameters": [ + { + "Name": "app", + "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" + } + ], + "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], "GenericParameters": [] }, { @@ -2864,7 +3107,26 @@ "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" } ], - "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddAuthentication", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + }, + { + "Name": "defaultScheme", + "Type": "System.String" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, "Extension": true, "Visibility": "Public", @@ -2880,18 +3142,189 @@ }, { "Name": "configureOptions", - "Type": "System.Action" + "Type": "System.Action" } ], - "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder", "Static": true, "Extension": true, "Visibility": "Public", "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AddScheme", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", + "Type": "System.String" + }, + { + "Name": "configureScheme", + "Type": "System.Action" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] + }, + { + "ParameterName": "THandler", + "ParameterPosition": 1, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationHandler" + ] + } + ] + }, + { + "Kind": "Method", + "Name": "AddScheme", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] + }, + { + "ParameterName": "THandler", + "ParameterPosition": 1, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationHandler" + ] + } + ] + }, + { + "Kind": "Method", + "Name": "AddScheme", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions" + ] + }, + { + "ParameterName": "THandler", + "ParameterPosition": 1, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.AuthenticationHandler" + ] + } + ] + }, + { + "Kind": "Method", + "Name": "AddRemoteScheme", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + }, + { + "Name": "authenticationScheme", + "Type": "System.String" + }, + { + "Name": "displayName", + "Type": "System.String" + }, + { + "Name": "configureOptions", + "Type": "System.Action" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [ + { + "ParameterName": "TOptions", + "ParameterPosition": 0, + "New": true, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions" + ] + }, + { + "ParameterName": "THandler", + "ParameterPosition": 1, + "BaseTypeOrInterfaces": [ + "Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler" + ] + } + ] } ], "GenericParameters": [] } - ], - "SourceFilters": [] + ] } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/breakingchanges.netcore.json b/src/Microsoft.AspNetCore.Authentication/breakingchanges.netcore.json new file mode 100644 index 000000000..d5bc6954e --- /dev/null +++ b/src/Microsoft.AspNetCore.Authentication/breakingchanges.netcore.json @@ -0,0 +1,22 @@ + [ + { + "TypeId": "public static class Microsoft.Extensions.DependencyInjection.AuthenticationServiceCollectionExtensions", + "MemberId": "public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddRemoteScheme(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.String authenticationScheme, System.String displayName, System.Action configureOptions) where T0 : Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions, new() where T1 : Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler", + "Kind": "Removal" + }, + { + "TypeId": "public static class Microsoft.Extensions.DependencyInjection.AuthenticationServiceCollectionExtensions", + "MemberId": "public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddScheme(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.String authenticationScheme, System.Action configureOptions) where T0 : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions, new() where T1 : Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "Kind": "Removal" + }, + { + "TypeId": "public static class Microsoft.Extensions.DependencyInjection.AuthenticationServiceCollectionExtensions", + "MemberId": "public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddScheme(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.String authenticationScheme, System.String displayName, System.Action configureScheme, System.Action configureOptions) where T0 : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions, new() where T1 : Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "Kind": "Removal" + }, + { + "TypeId": "public static class Microsoft.Extensions.DependencyInjection.AuthenticationServiceCollectionExtensions", + "MemberId": "public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddScheme(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.String authenticationScheme, System.String displayName, System.Action configureOptions) where T0 : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions, new() where T1 : Microsoft.AspNetCore.Authentication.AuthenticationHandler", + "Kind": "Removal" + } + ] \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authentication/project.json b/src/Microsoft.AspNetCore.Authentication/project.json deleted file mode 100644 index 0dcf5a789..000000000 --- a/src/Microsoft.AspNetCore.Authentication/project.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core common types used by the various authentication middleware components.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/security" - }, - "tags": [ - "aspnetcore", - "authentication", - "security" - ] - }, - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "dependencies": { - "Microsoft.AspNetCore.DataProtection": "1.2.0-*", - "Microsoft.AspNetCore.Http": "1.2.0-*", - "Microsoft.AspNetCore.Http.Extensions": "1.2.0-*", - "Microsoft.Extensions.Logging.Abstractions": "1.2.0-*", - "Microsoft.Extensions.Options": "1.2.0-*", - "Microsoft.Extensions.SecurityHelper.Sources": { - "type": "build", - "version": "1.2.0-*" - }, - "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.2.0-*", - "type": "build" - }, - "Microsoft.Extensions.WebEncoders": "1.2.0-*", - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": { - "frameworkAssemblies": { - "System.Net.Http": "" - } - }, - "netstandard1.3": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authorization.Policy/AuthorizationAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.Authorization.Policy/AuthorizationAppBuilderExtensions.cs new file mode 100644 index 000000000..66f0eb6f1 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization.Policy/AuthorizationAppBuilderExtensions.cs @@ -0,0 +1,29 @@ +// 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.Authorization; + +namespace Microsoft.AspNetCore.Builder +{ + /// + /// Extension methods to add authorization capabilities to an HTTP application pipeline. + /// + public static class AuthorizationAppBuilderExtensions + { + /// + /// Adds the to the specified , which enables authorization capabilities. + /// + /// The to add the middleware to. + /// A reference to this instance after the operation has completed. + public static IApplicationBuilder UseAuthorization(this IApplicationBuilder app) + { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + return app.UseMiddleware(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Authorization.Policy/AuthorizationEndpointConventionBuilderExtensions.cs b/src/Microsoft.AspNetCore.Authorization.Policy/AuthorizationEndpointConventionBuilderExtensions.cs new file mode 100644 index 000000000..81b05d70a --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization.Policy/AuthorizationEndpointConventionBuilderExtensions.cs @@ -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 System.Linq; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Routing; + +namespace Microsoft.AspNetCore.Builder +{ + public static class AuthorizationEndpointConventionBuilderExtensions + { + public static IEndpointConventionBuilder RequireAuthorization(this IEndpointConventionBuilder builder, params IAuthorizeData[] authorizeData) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (authorizeData == null) + { + throw new ArgumentNullException(nameof(authorizeData)); + } + + builder.Apply(endpointBuilder => + { + foreach (var data in authorizeData) + { + endpointBuilder.Metadata.Add(data); + } + }); + return builder; + } + + public static IEndpointConventionBuilder RequireAuthorization(this IEndpointConventionBuilder builder, params string[] policyNames) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (policyNames == null) + { + throw new ArgumentNullException(nameof(policyNames)); + } + + return builder.RequireAuthorization(policyNames.Select(n => new AuthorizeAttribute(n)).ToArray()); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authorization.Policy/AuthorizationMiddleware.cs b/src/Microsoft.AspNetCore.Authorization.Policy/AuthorizationMiddleware.cs new file mode 100644 index 000000000..1da5b123f --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization.Policy/AuthorizationMiddleware.cs @@ -0,0 +1,104 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization.Policy; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Endpoints; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.AspNetCore.Authorization +{ + public class AuthorizationMiddleware + { + private readonly RequestDelegate _next; + private readonly IAuthorizationPolicyProvider _policyProvider; + + public AuthorizationMiddleware(RequestDelegate next, IAuthorizationPolicyProvider policyProvider) + { + if (next == null) + { + throw new ArgumentNullException(nameof(next)); + } + + if (policyProvider == null) + { + throw new ArgumentNullException(nameof(policyProvider)); + } + + _next = next; + _policyProvider = policyProvider; + } + + public async Task Invoke(HttpContext context) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + var endpoint = context.GetEndpoint(); + var authorizeData = endpoint?.Metadata.GetOrderedMetadata() ?? Array.Empty(); + var policy = await AuthorizationPolicy.CombineAsync(_policyProvider, authorizeData); + if (policy == null) + { + await _next(context); + return; + } + + // Policy evaluator has transient lifetime so it fetched from request services instead of injecting in constructor + var policyEvaluator = context.RequestServices.GetRequiredService(); + + var authenticateResult = await policyEvaluator.AuthenticateAsync(policy, context); + + // Allow Anonymous skips all authorization + if (endpoint?.Metadata.GetMetadata() != null) + { + await _next(context); + return; + } + + // Note that the resource will be null if there is no matched endpoint + var authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticateResult, context, resource: endpoint); + + if (authorizeResult.Challenged) + { + if (policy.AuthenticationSchemes.Any()) + { + foreach (var scheme in policy.AuthenticationSchemes) + { + await context.ChallengeAsync(scheme); + } + } + else + { + await context.ChallengeAsync(); + } + + return; + } + else if (authorizeResult.Forbidden) + { + if (policy.AuthenticationSchemes.Any()) + { + foreach (var scheme in policy.AuthenticationSchemes) + { + await context.ForbidAsync(scheme); + } + } + else + { + await context.ForbidAsync(); + } + + return; + } + + await _next(context); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authorization.Policy/IPolicyEvaluator.cs b/src/Microsoft.AspNetCore.Authorization.Policy/IPolicyEvaluator.cs new file mode 100644 index 000000000..dd5e6fc03 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization.Policy/IPolicyEvaluator.cs @@ -0,0 +1,40 @@ +// 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 System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Authorization.Policy +{ + /// + /// Base class for authorization handlers that need to be called for a specific requirement type. + /// + public interface IPolicyEvaluator + { + /// + /// Does authentication for and sets the resulting + /// to . If no schemes are set, this is a no-op. + /// + /// The . + /// The . + /// unless all schemes specified by fail to authenticate. + Task AuthenticateAsync(AuthorizationPolicy policy, HttpContext context); + + /// + /// Attempts authorization for a policy using . + /// + /// The . + /// The result of a call to . + /// The . + /// + /// An optional resource the policy should be checked with. + /// If a resource is not required for policy evaluation you may pass null as the value. + /// + /// Returns if authorization succeeds. + /// Otherwise returns if , otherwise + /// returns + Task AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object resource); + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authorization.Policy/Microsoft.AspNetCore.Authorization.Policy.csproj b/src/Microsoft.AspNetCore.Authorization.Policy/Microsoft.AspNetCore.Authorization.Policy.csproj new file mode 100644 index 000000000..d3ad99a51 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization.Policy/Microsoft.AspNetCore.Authorization.Policy.csproj @@ -0,0 +1,22 @@ + + + + ASP.NET Core authorization policy helper classes. + netcoreapp3.0 + $(NoWarn);CS1591;NU1605 + true + aspnetcore;authorization + + + + + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Authorization.Policy/PolicyAuthorizationResult.cs b/src/Microsoft.AspNetCore.Authorization.Policy/PolicyAuthorizationResult.cs new file mode 100644 index 000000000..d7d481dcd --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization.Policy/PolicyAuthorizationResult.cs @@ -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. + +namespace Microsoft.AspNetCore.Authorization.Policy +{ + public class PolicyAuthorizationResult + { + private PolicyAuthorizationResult() { } + + /// + /// If true, means the callee should challenge and try again. + /// + public bool Challenged { get; private set; } + + /// + /// Authorization was forbidden. + /// + public bool Forbidden { get; private set; } + + /// + /// Authorization was successful. + /// + public bool Succeeded { get; private set; } + + public static PolicyAuthorizationResult Challenge() + => new PolicyAuthorizationResult { Challenged = true }; + + public static PolicyAuthorizationResult Forbid() + => new PolicyAuthorizationResult { Forbidden = true }; + + public static PolicyAuthorizationResult Success() + => new PolicyAuthorizationResult { Succeeded = true }; + + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authorization.Policy/PolicyEvaluator.cs b/src/Microsoft.AspNetCore.Authorization.Policy/PolicyEvaluator.cs new file mode 100644 index 000000000..3100ff4d3 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization.Policy/PolicyEvaluator.cs @@ -0,0 +1,96 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Internal; + +namespace Microsoft.AspNetCore.Authorization.Policy +{ + public class PolicyEvaluator : IPolicyEvaluator + { + private readonly IAuthorizationService _authorization; + + /// + /// Constructor + /// + /// The authorization service. + public PolicyEvaluator(IAuthorizationService authorization) + { + _authorization = authorization; + } + + /// + /// Does authentication for and sets the resulting + /// to . If no schemes are set, this is a no-op. + /// + /// The . + /// The . + /// unless all schemes specified by failed to authenticate. + public virtual async Task AuthenticateAsync(AuthorizationPolicy policy, HttpContext context) + { + if (policy.AuthenticationSchemes != null && policy.AuthenticationSchemes.Count > 0) + { + ClaimsPrincipal newPrincipal = null; + foreach (var scheme in policy.AuthenticationSchemes) + { + var result = await context.AuthenticateAsync(scheme); + if (result != null && result.Succeeded) + { + newPrincipal = SecurityHelper.MergeUserPrincipal(newPrincipal, result.Principal); + } + } + + if (newPrincipal != null) + { + context.User = newPrincipal; + return AuthenticateResult.Success(new AuthenticationTicket(newPrincipal, string.Join(";", policy.AuthenticationSchemes))); + } + else + { + context.User = new ClaimsPrincipal(new ClaimsIdentity()); + return AuthenticateResult.NoResult(); + } + } + + return (context.User?.Identity?.IsAuthenticated ?? false) + ? AuthenticateResult.Success(new AuthenticationTicket(context.User, "context.User")) + : AuthenticateResult.NoResult(); + } + + /// + /// Attempts authorization for a policy using . + /// + /// The . + /// The result of a call to . + /// The . + /// + /// An optional resource the policy should be checked with. + /// If a resource is not required for policy evaluation you may pass null as the value. + /// + /// Returns if authorization succeeds. + /// Otherwise returns if , otherwise + /// returns + public virtual async Task AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object resource) + { + if (policy == null) + { + throw new ArgumentNullException(nameof(policy)); + } + + var result = await _authorization.AuthorizeAsync(context.User, resource, policy); + if (result.Succeeded) + { + return PolicyAuthorizationResult.Success(); + } + + // If authentication was successful, return forbidden, otherwise challenge + return (authenticationResult.Succeeded) + ? PolicyAuthorizationResult.Forbid() + : PolicyAuthorizationResult.Challenge(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authorization.Policy/PolicyServiceCollectionExtensions.cs b/src/Microsoft.AspNetCore.Authorization.Policy/PolicyServiceCollectionExtensions.cs new file mode 100644 index 000000000..9b72a5cab --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization.Policy/PolicyServiceCollectionExtensions.cs @@ -0,0 +1,31 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNetCore.Authorization.Policy; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// Extension methods for setting up authorization services in an . + /// + public static class PolicyServiceCollectionExtensions + { + /// + /// Adds authorization policy services to the specified . + /// + /// The to add services to. + /// The so that additional calls can be chained. + public static IServiceCollection AddAuthorizationPolicyEvaluator(this IServiceCollection services) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + services.TryAdd(ServiceDescriptor.Transient()); + return services; + } + } +} diff --git a/src/Microsoft.AspNetCore.Authorization.Policy/baseline.netcore.json b/src/Microsoft.AspNetCore.Authorization.Policy/baseline.netcore.json new file mode 100644 index 000000000..e8708538d --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization.Policy/baseline.netcore.json @@ -0,0 +1,211 @@ +{ + "AssemblyIdentity": "Microsoft.AspNetCore.Authorization.Policy, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "Types": [ + { + "Name": "Microsoft.AspNetCore.Authorization.Policy.IPolicyEvaluator", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AuthenticateAsync", + "Parameters": [ + { + "Name": "policy", + "Type": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AuthorizeAsync", + "Parameters": [ + { + "Name": "policy", + "Type": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy" + }, + { + "Name": "authenticationResult", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticateResult" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "resource", + "Type": "System.Object" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authorization.Policy.PolicyAuthorizationResult", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Challenged", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Forbidden", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Succeeded", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Challenge", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authorization.Policy.PolicyAuthorizationResult", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Forbid", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authorization.Policy.PolicyAuthorizationResult", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Success", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authorization.Policy.PolicyAuthorizationResult", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authorization.Policy.PolicyEvaluator", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authorization.Policy.IPolicyEvaluator" + ], + "Members": [ + { + "Kind": "Method", + "Name": "AuthenticateAsync", + "Parameters": [ + { + "Name": "policy", + "Type": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authorization.Policy.IPolicyEvaluator", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "AuthorizeAsync", + "Parameters": [ + { + "Name": "policy", + "Type": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy" + }, + { + "Name": "authenticationResult", + "Type": "Microsoft.AspNetCore.Authentication.AuthenticateResult" + }, + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Http.HttpContext" + }, + { + "Name": "resource", + "Type": "System.Object" + } + ], + "ReturnType": "System.Threading.Tasks.Task", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authorization.Policy.IPolicyEvaluator", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "authorization", + "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationService" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.Extensions.DependencyInjection.PolicyServiceCollectionExtensions", + "Visibility": "Public", + "Kind": "Class", + "Abstract": true, + "Static": true, + "Sealed": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "AddAuthorizationPolicyEvaluator", + "Parameters": [ + { + "Name": "services", + "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" + } + ], + "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", + "Static": true, + "Extension": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + } + ] +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authorization/AuthorizationFailure.cs b/src/Microsoft.AspNetCore.Authorization/AuthorizationFailure.cs new file mode 100644 index 000000000..89956c9aa --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization/AuthorizationFailure.cs @@ -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 System.Collections.Generic; +using System.Security.Claims; + +namespace Microsoft.AspNetCore.Authorization +{ + /// + /// Encapsulates a failure result of . + /// + public class AuthorizationFailure + { + private AuthorizationFailure() { } + + /// + /// Failure was due to being called. + /// + public bool FailCalled { get; private set; } + + /// + /// Failure was due to these requirements not being met via . + /// + public IEnumerable FailedRequirements { get; private set; } + + /// + /// Return a failure due to being called. + /// + /// The failure. + public static AuthorizationFailure ExplicitFail() + => new AuthorizationFailure + { + FailCalled = true, + FailedRequirements = new IAuthorizationRequirement[0] + }; + + /// + /// Return a failure due to some requirements not being met via . + /// + /// The requirements that were not met. + /// The failure. + public static AuthorizationFailure Failed(IEnumerable failed) + => new AuthorizationFailure { FailedRequirements = failed }; + + } +} diff --git a/src/Microsoft.AspNetCore.Authorization/AuthorizationOptions.cs b/src/Microsoft.AspNetCore.Authorization/AuthorizationOptions.cs index 6899913af..f0c5527d2 100644 --- a/src/Microsoft.AspNetCore.Authorization/AuthorizationOptions.cs +++ b/src/Microsoft.AspNetCore.Authorization/AuthorizationOptions.cs @@ -20,13 +20,25 @@ public class AuthorizationOptions public bool InvokeHandlersAfterFailure { get; set; } = true; /// - /// Gets or sets the default authorization policy. + /// Gets or sets the default authorization policy. Defaults to require authenticated users. /// /// - /// The default policy is to require any authenticated user. + /// The default policy used when evaluating with no policy name specified. /// public AuthorizationPolicy DefaultPolicy { get; set; } = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build(); + /// + /// Gets or sets the required authorization policy. Defaults to null. + /// + /// + /// By default the required policy is null. + /// + /// If a required policy has been specified then it is always evaluated, even if there are no + /// instances for a resource. If a resource has + /// then they are evaluated together with the required policy. + /// + public AuthorizationPolicy RequiredPolicy { get; set; } + /// /// Add an authorization policy with the provided name. /// diff --git a/src/Microsoft.AspNetCore.Authorization/AuthorizationPolicy.cs b/src/Microsoft.AspNetCore.Authorization/AuthorizationPolicy.cs index 5cba0fd9e..b3b54f300 100644 --- a/src/Microsoft.AspNetCore.Authorization/AuthorizationPolicy.cs +++ b/src/Microsoft.AspNetCore.Authorization/AuthorizationPolicy.cs @@ -120,46 +120,74 @@ public static async Task CombineAsync(IAuthorizationPolicyP throw new ArgumentNullException(nameof(authorizeData)); } - var policyBuilder = new AuthorizationPolicyBuilder(); - var any = false; - foreach (var authorizeDatum in authorizeData) + // Avoid allocating enumerator if the data is known to be empty + var skipEnumeratingData = false; + if (authorizeData is IList dataList) { - any = true; - var useDefaultPolicy = true; - if (!string.IsNullOrWhiteSpace(authorizeDatum.Policy)) + skipEnumeratingData = dataList.Count == 0; + } + + AuthorizationPolicyBuilder policyBuilder = null; + if (!skipEnumeratingData) + { + foreach (var authorizeDatum in authorizeData) { - var policy = await policyProvider.GetPolicyAsync(authorizeDatum.Policy); - if (policy == null) + if (policyBuilder == null) { - throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound(authorizeDatum.Policy)); + policyBuilder = new AuthorizationPolicyBuilder(); } - policyBuilder.Combine(policy); - useDefaultPolicy = false; - } - var rolesSplit = authorizeDatum.Roles?.Split(','); - if (rolesSplit != null && rolesSplit.Any()) - { - var trimmedRolesSplit = rolesSplit.Where(r => !string.IsNullOrWhiteSpace(r)).Select(r => r.Trim()); - policyBuilder.RequireRole(trimmedRolesSplit); - useDefaultPolicy = false; - } - var authTypesSplit = authorizeDatum.ActiveAuthenticationSchemes?.Split(','); - if (authTypesSplit != null && authTypesSplit.Any()) - { - foreach (var authType in authTypesSplit) + + var useDefaultPolicy = true; + if (!string.IsNullOrWhiteSpace(authorizeDatum.Policy)) + { + var policy = await policyProvider.GetPolicyAsync(authorizeDatum.Policy); + if (policy == null) + { + throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound(authorizeDatum.Policy)); + } + policyBuilder.Combine(policy); + useDefaultPolicy = false; + } + + var rolesSplit = authorizeDatum.Roles?.Split(','); + if (rolesSplit != null && rolesSplit.Any()) + { + var trimmedRolesSplit = rolesSplit.Where(r => !string.IsNullOrWhiteSpace(r)).Select(r => r.Trim()); + policyBuilder.RequireRole(trimmedRolesSplit); + useDefaultPolicy = false; + } + + var authTypesSplit = authorizeDatum.AuthenticationSchemes?.Split(','); + if (authTypesSplit != null && authTypesSplit.Any()) { - if (!string.IsNullOrWhiteSpace(authType)) + foreach (var authType in authTypesSplit) { - policyBuilder.AuthenticationSchemes.Add(authType.Trim()); + if (!string.IsNullOrWhiteSpace(authType)) + { + policyBuilder.AuthenticationSchemes.Add(authType.Trim()); + } } } + + if (useDefaultPolicy) + { + policyBuilder.Combine(await policyProvider.GetDefaultPolicyAsync()); + } } - if (useDefaultPolicy) + } + + var requiredPolicy = await policyProvider.GetRequiredPolicyAsync(); + if (requiredPolicy != null) + { + if (policyBuilder == null) { - policyBuilder.Combine(await policyProvider.GetDefaultPolicyAsync()); + policyBuilder = new AuthorizationPolicyBuilder(); } + + policyBuilder.Combine(requiredPolicy); } - return any ? policyBuilder.Build() : null; + + return policyBuilder?.Build(); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authorization/AuthorizationPolicyBuilder.cs b/src/Microsoft.AspNetCore.Authorization/AuthorizationPolicyBuilder.cs index 37335df8f..2f483e37c 100644 --- a/src/Microsoft.AspNetCore.Authorization/AuthorizationPolicyBuilder.cs +++ b/src/Microsoft.AspNetCore.Authorization/AuthorizationPolicyBuilder.cs @@ -96,16 +96,16 @@ public AuthorizationPolicyBuilder Combine(AuthorizationPolicy policy) /// to the current instance. /// /// The claim type required. - /// Values the claim must process one or more of for evaluation to succeed. + /// Values the claim must process one or more of for evaluation to succeed. /// A reference to this instance after the operation has completed. - public AuthorizationPolicyBuilder RequireClaim(string claimType, params string[] requiredValues) + public AuthorizationPolicyBuilder RequireClaim(string claimType, params string[] allowedValues) { if (claimType == null) { throw new ArgumentNullException(nameof(claimType)); } - return RequireClaim(claimType, (IEnumerable)requiredValues); + return RequireClaim(claimType, (IEnumerable)allowedValues); } /// @@ -113,16 +113,16 @@ public AuthorizationPolicyBuilder RequireClaim(string claimType, params string[] /// to the current instance. /// /// The claim type required. - /// Values the claim must process one or more of for evaluation to succeed. + /// Values the claim must process one or more of for evaluation to succeed. /// A reference to this instance after the operation has completed. - public AuthorizationPolicyBuilder RequireClaim(string claimType, IEnumerable requiredValues) + public AuthorizationPolicyBuilder RequireClaim(string claimType, IEnumerable allowedValues) { if (claimType == null) { throw new ArgumentNullException(nameof(claimType)); } - Requirements.Add(new ClaimsAuthorizationRequirement(claimType, requiredValues)); + Requirements.Add(new ClaimsAuthorizationRequirement(claimType, allowedValues)); return this; } @@ -147,7 +147,7 @@ public AuthorizationPolicyBuilder RequireClaim(string claimType) /// Adds a /// to the current instance. /// - /// The roles required. + /// The allowed roles. /// A reference to this instance after the operation has completed. public AuthorizationPolicyBuilder RequireRole(params string[] roles) { @@ -163,7 +163,7 @@ public AuthorizationPolicyBuilder RequireRole(params string[] roles) /// Adds a /// to the current instance. /// - /// The roles required. + /// The allowed roles. /// A reference to this instance after the operation has completed. public AuthorizationPolicyBuilder RequireRole(IEnumerable roles) { @@ -247,4 +247,4 @@ public AuthorizationPolicy Build() return new AuthorizationPolicy(Requirements, AuthenticationSchemes.Distinct()); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.AspNetCore.Authorization/AuthorizationResult.cs b/src/Microsoft.AspNetCore.Authorization/AuthorizationResult.cs new file mode 100644 index 000000000..46dca35fb --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization/AuthorizationResult.cs @@ -0,0 +1,37 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Security.Claims; + +namespace Microsoft.AspNetCore.Authorization +{ + /// + /// Encapsulates the result of . + /// + public class AuthorizationResult + { + private AuthorizationResult() { } + + /// + /// True if authorization was successful. + /// + public bool Succeeded { get; private set; } + + /// + /// Contains information about why authorization failed. + /// + public AuthorizationFailure Failure { get; private set; } + + /// + /// Returns a successful result. + /// + /// A successful result. + public static AuthorizationResult Success() => new AuthorizationResult { Succeeded = true }; + + public static AuthorizationResult Failed(AuthorizationFailure failure) => new AuthorizationResult { Failure = failure }; + + public static AuthorizationResult Failed() => new AuthorizationResult { Failure = AuthorizationFailure.ExplicitFail() }; + + } +} diff --git a/src/Microsoft.AspNetCore.Authorization/AuthorizationServiceCollectionExtensions.cs b/src/Microsoft.AspNetCore.Authorization/AuthorizationServiceCollectionExtensions.cs index a9961b69e..c089fba28 100644 --- a/src/Microsoft.AspNetCore.Authorization/AuthorizationServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNetCore.Authorization/AuthorizationServiceCollectionExtensions.cs @@ -27,6 +27,7 @@ public static IServiceCollection AddAuthorization(this IServiceCollection servic services.TryAdd(ServiceDescriptor.Transient()); services.TryAdd(ServiceDescriptor.Transient()); + services.TryAdd(ServiceDescriptor.Transient()); services.TryAdd(ServiceDescriptor.Transient()); services.TryAdd(ServiceDescriptor.Transient()); services.TryAddEnumerable(ServiceDescriptor.Transient()); diff --git a/src/Microsoft.AspNetCore.Authorization/AuthorizationServiceExtensions.cs b/src/Microsoft.AspNetCore.Authorization/AuthorizationServiceExtensions.cs index 3b78c952e..866b5dbc5 100644 --- a/src/Microsoft.AspNetCore.Authorization/AuthorizationServiceExtensions.cs +++ b/src/Microsoft.AspNetCore.Authorization/AuthorizationServiceExtensions.cs @@ -24,7 +24,7 @@ public static class AuthorizationServiceExtensions /// A flag indicating whether requirement evaluation has succeeded or failed. /// This value is true when the user fulfills the policy, otherwise false. /// - public static Task AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, object resource, IAuthorizationRequirement requirement) + public static Task AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, object resource, IAuthorizationRequirement requirement) { if (service == null) { @@ -50,7 +50,7 @@ public static Task AuthorizeAsync(this IAuthorizationService service, Clai /// A flag indicating whether policy evaluation has succeeded or failed. /// This value is true when the user fulfills the policy, otherwise false. /// - public static Task AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, object resource, AuthorizationPolicy policy) + public static Task AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, object resource, AuthorizationPolicy policy) { if (service == null) { @@ -62,7 +62,7 @@ public static Task AuthorizeAsync(this IAuthorizationService service, Clai throw new ArgumentNullException(nameof(policy)); } - return service.AuthorizeAsync(user, resource, policy.Requirements.ToArray()); + return service.AuthorizeAsync(user, resource, policy.Requirements); } /// @@ -75,7 +75,7 @@ public static Task AuthorizeAsync(this IAuthorizationService service, Clai /// A flag indicating whether policy evaluation has succeeded or failed. /// This value is true when the user fulfills the policy, otherwise false. /// - public static Task AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, AuthorizationPolicy policy) + public static Task AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, AuthorizationPolicy policy) { if (service == null) { @@ -100,7 +100,7 @@ public static Task AuthorizeAsync(this IAuthorizationService service, Clai /// A flag indicating whether policy evaluation has succeeded or failed. /// This value is true when the user fulfills the policy, otherwise false. /// - public static Task AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, string policyName) + public static Task AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, string policyName) { if (service == null) { diff --git a/src/Microsoft.AspNetCore.Authorization/AuthorizeAttribute.cs b/src/Microsoft.AspNetCore.Authorization/AuthorizeAttribute.cs index c911dc56b..b1f0f8bae 100644 --- a/src/Microsoft.AspNetCore.Authorization/AuthorizeAttribute.cs +++ b/src/Microsoft.AspNetCore.Authorization/AuthorizeAttribute.cs @@ -25,13 +25,19 @@ public AuthorizeAttribute(string policy) Policy = policy; } - /// + /// + /// Gets or sets the policy name that determines access to the resource. + /// public string Policy { get; set; } - /// + /// + /// Gets or sets a comma delimited list of roles that are allowed to access the resource. + /// public string Roles { get; set; } - /// - public string ActiveAuthenticationSchemes { get; set; } + /// + /// Gets or sets a comma delimited list of schemes from which user information is constructed. + /// + public string AuthenticationSchemes { get; set; } } } diff --git a/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationEvaluator.cs b/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationEvaluator.cs index 64cc695b8..4bbc283be 100644 --- a/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationEvaluator.cs +++ b/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationEvaluator.cs @@ -9,23 +9,15 @@ namespace Microsoft.AspNetCore.Authorization public class DefaultAuthorizationEvaluator : IAuthorizationEvaluator { /// - /// Returns true, if authorization has failed. + /// Determines whether the authorization result was successful or not. /// /// The authorization information. - /// True if authorization has failed. - public virtual bool HasFailed(AuthorizationHandlerContext context) - { - return context.HasFailed; - } - - /// - /// Returns true, if authorization has succeeded. - /// - /// The authorization information. - /// True if authorization has succeeded. - public virtual bool HasSucceeded(AuthorizationHandlerContext context) - { - return context.HasSucceeded; - } + /// The . + public AuthorizationResult Evaluate(AuthorizationHandlerContext context) + => context.HasSucceeded + ? AuthorizationResult.Success() + : AuthorizationResult.Failed(context.HasFailed + ? AuthorizationFailure.ExplicitFail() + : AuthorizationFailure.Failed(context.PendingRequirements)); } } diff --git a/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationHandlerProvider.cs b/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationHandlerProvider.cs new file mode 100644 index 000000000..d297d4cdc --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationHandlerProvider.cs @@ -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; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.Authorization +{ + /// + /// The default implementation of a handler provider, + /// which provides the s for an authorization request. + /// + public class DefaultAuthorizationHandlerProvider : IAuthorizationHandlerProvider + { + private readonly IEnumerable _handlers; + + /// + /// Creates a new instance of . + /// + /// The s. + public DefaultAuthorizationHandlerProvider(IEnumerable handlers) + { + if (handlers == null) + { + throw new ArgumentNullException(nameof(handlers)); + } + + _handlers = handlers; + } + + public Task> GetHandlersAsync(AuthorizationHandlerContext context) + => Task.FromResult(_handlers); + } +} diff --git a/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationPolicyProvider.cs b/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationPolicyProvider.cs index 0e4329dcc..f5e665273 100644 --- a/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationPolicyProvider.cs +++ b/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationPolicyProvider.cs @@ -14,6 +14,8 @@ namespace Microsoft.AspNetCore.Authorization public class DefaultAuthorizationPolicyProvider : IAuthorizationPolicyProvider { private readonly AuthorizationOptions _options; + private Task _cachedDefaultPolicy; + private Task _cachedRequiredPolicy; /// /// Creates a new instance of . @@ -35,7 +37,26 @@ public DefaultAuthorizationPolicyProvider(IOptions options /// The default authorization policy. public Task GetDefaultPolicyAsync() { - return Task.FromResult(_options.DefaultPolicy); + return GetCachedPolicy(ref _cachedDefaultPolicy, _options.DefaultPolicy); + } + + /// + /// Gets the required authorization policy. + /// + /// The required authorization policy. + public Task GetRequiredPolicyAsync() + { + return GetCachedPolicy(ref _cachedRequiredPolicy, _options.RequiredPolicy); + } + + private Task GetCachedPolicy(ref Task cachedPolicy, AuthorizationPolicy currentPolicy) + { + var local = cachedPolicy; + if (local == null || local.Result != currentPolicy) + { + cachedPolicy = local = Task.FromResult(currentPolicy); + } + return local; } /// diff --git a/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationService.cs b/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationService.cs index 8980d51ac..bc5d571c4 100644 --- a/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationService.cs +++ b/src/Microsoft.AspNetCore.Authorization/DefaultAuthorizationService.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Security.Claims; using System.Security.Principal; using System.Threading.Tasks; @@ -19,19 +18,11 @@ public class DefaultAuthorizationService : IAuthorizationService { private readonly AuthorizationOptions _options; private readonly IAuthorizationHandlerContextFactory _contextFactory; + private readonly IAuthorizationHandlerProvider _handlers; private readonly IAuthorizationEvaluator _evaluator; private readonly IAuthorizationPolicyProvider _policyProvider; - private readonly IList _handlers; private readonly ILogger _logger; - /// - /// Creates a new instance of . - /// - /// The used to provide policies. - /// The handlers used to fulfill s. - /// The logger used to log messages, warnings and errors. - public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IEnumerable handlers, ILogger logger) : this(policyProvider, handlers, logger, new DefaultAuthorizationHandlerContextFactory(), new DefaultAuthorizationEvaluator(), Options.Create(new AuthorizationOptions())) { } - /// /// Creates a new instance of . /// @@ -39,9 +30,9 @@ public class DefaultAuthorizationService : IAuthorizationService /// The handlers used to fulfill s. /// The logger used to log messages, warnings and errors. /// The used to create the context to handle the authorization. - /// The used to determine if authorzation was successful. + /// The used to determine if authorization was successful. /// The used. - public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IEnumerable handlers, ILogger logger, IAuthorizationHandlerContextFactory contextFactory, IAuthorizationEvaluator evaluator, IOptions options) + public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IAuthorizationHandlerProvider handlers, ILogger logger, IAuthorizationHandlerContextFactory contextFactory, IAuthorizationEvaluator evaluator, IOptions options) { if (options == null) { @@ -69,7 +60,7 @@ public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, } _options = options.Value; - _handlers = handlers.ToArray(); + _handlers = handlers; _policyProvider = policyProvider; _logger = logger; _evaluator = evaluator; @@ -83,10 +74,10 @@ public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, /// The resource to evaluate the requirements against. /// The requirements to evaluate. /// - /// A flag indicating whether authorization has succeded. + /// A flag indicating whether authorization has succeeded. /// This value is true when the user fulfills the policy otherwise false. /// - public async Task AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable requirements) + public async Task AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable requirements) { if (requirements == null) { @@ -94,7 +85,8 @@ public async Task AuthorizeAsync(ClaimsPrincipal user, object resource, IE } var authContext = _contextFactory.CreateContext(requirements, user, resource); - foreach (var handler in _handlers) + var handlers = await _handlers.GetHandlersAsync(authContext); + foreach (var handler in handlers) { await handler.HandleAsync(authContext); if (!_options.InvokeHandlersAfterFailure && authContext.HasFailed) @@ -103,38 +95,16 @@ public async Task AuthorizeAsync(ClaimsPrincipal user, object resource, IE } } - if (_evaluator.HasSucceeded(authContext)) + var result = _evaluator.Evaluate(authContext); + if (result.Succeeded) { - _logger.UserAuthorizationSucceeded(GetUserNameForLogging(user)); - return true; + _logger.UserAuthorizationSucceeded(); } else { - _logger.UserAuthorizationFailed(GetUserNameForLogging(user)); - return false; + _logger.UserAuthorizationFailed(); } - } - - private string GetUserNameForLogging(ClaimsPrincipal user) - { - var identity = user?.Identity; - if (identity != null) - { - var name = identity.Name; - if (name != null) - { - return name; - } - return GetClaimValue(identity, "sub") - ?? GetClaimValue(identity, ClaimTypes.Name) - ?? GetClaimValue(identity, ClaimTypes.NameIdentifier); - } - return null; - } - - private static string GetClaimValue(IIdentity identity, string claimsType) - { - return (identity as ClaimsIdentity)?.FindFirst(claimsType)?.Value; + return result; } /// @@ -144,10 +114,10 @@ private static string GetClaimValue(IIdentity identity, string claimsType) /// The resource the policy should be checked with. /// The name of the policy to check against a specific context. /// - /// A flag indicating whether authorization has succeded. + /// A flag indicating whether authorization has succeeded. /// This value is true when the user fulfills the policy otherwise false. /// - public async Task AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName) + public async Task AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName) { if (policyName == null) { diff --git a/src/Microsoft.AspNetCore.Authorization/IAuthorizationEvaluator.cs b/src/Microsoft.AspNetCore.Authorization/IAuthorizationEvaluator.cs index 7b2c5d1bc..baa6f828c 100644 --- a/src/Microsoft.AspNetCore.Authorization/IAuthorizationEvaluator.cs +++ b/src/Microsoft.AspNetCore.Authorization/IAuthorizationEvaluator.cs @@ -9,17 +9,10 @@ namespace Microsoft.AspNetCore.Authorization public interface IAuthorizationEvaluator { /// - /// Returns true, if authorization has failed. + /// Determines whether the authorization result was successful or not. /// /// The authorization information. - /// True if authorization has failed. - bool HasFailed(AuthorizationHandlerContext context); - - /// - /// Returns true, if authorization has succeeded. - /// - /// The authorization information. - /// True if authorization has succeeded. - bool HasSucceeded(AuthorizationHandlerContext context); + /// The . + AuthorizationResult Evaluate(AuthorizationHandlerContext context); } } diff --git a/src/Microsoft.AspNetCore.Authorization/IAuthorizationHandlerProvider.cs b/src/Microsoft.AspNetCore.Authorization/IAuthorizationHandlerProvider.cs new file mode 100644 index 000000000..7f0d9f5d3 --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization/IAuthorizationHandlerProvider.cs @@ -0,0 +1,21 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.Authorization +{ + /// + /// A type which can provide the s for an authorization request. + /// + public interface IAuthorizationHandlerProvider + { + /// + /// Return the handlers that will be called for the authorization request. + /// + /// The . + /// The list of handlers. + Task> GetHandlersAsync(AuthorizationHandlerContext context); + } +} diff --git a/src/Microsoft.AspNetCore.Authorization/IAuthorizationPolicyProvider.cs b/src/Microsoft.AspNetCore.Authorization/IAuthorizationPolicyProvider.cs index 9e9d0f468..4560d11e0 100644 --- a/src/Microsoft.AspNetCore.Authorization/IAuthorizationPolicyProvider.cs +++ b/src/Microsoft.AspNetCore.Authorization/IAuthorizationPolicyProvider.cs @@ -22,5 +22,11 @@ public interface IAuthorizationPolicyProvider /// /// The default authorization policy. Task GetDefaultPolicyAsync(); + + /// + /// Gets the required authorization policy. + /// + /// The required authorization policy. + Task GetRequiredPolicyAsync(); } } diff --git a/src/Microsoft.AspNetCore.Authorization/IAuthorizationService.cs b/src/Microsoft.AspNetCore.Authorization/IAuthorizationService.cs index a130c84b0..8976425ba 100644 --- a/src/Microsoft.AspNetCore.Authorization/IAuthorizationService.cs +++ b/src/Microsoft.AspNetCore.Authorization/IAuthorizationService.cs @@ -29,7 +29,7 @@ public interface IAuthorizationService /// Resource is an optional parameter and may be null. Please ensure that you check it is not /// null before acting upon it. /// - Task AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable requirements); + Task AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable requirements); /// /// Checks if a user meets a specific authorization policy @@ -43,12 +43,12 @@ public interface IAuthorizationService /// /// A flag indicating whether authorization has succeeded. /// Returns a flag indicating whether the user, and optional resource has fulfilled the policy. - /// true when the the policy has been fulfilled; otherwise false. + /// true when the policy has been fulfilled; otherwise false. /// /// /// Resource is an optional parameter and may be null. Please ensure that you check it is not /// null before acting upon it. /// - Task AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName); + Task AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName); } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authorization/IAuthorizeData.cs b/src/Microsoft.AspNetCore.Authorization/IAuthorizeData.cs index b48449b5c..1196db82d 100644 --- a/src/Microsoft.AspNetCore.Authorization/IAuthorizeData.cs +++ b/src/Microsoft.AspNetCore.Authorization/IAuthorizeData.cs @@ -21,6 +21,6 @@ public interface IAuthorizeData /// /// Gets or sets a comma delimited list of schemes from which user information is constructed. /// - string ActiveAuthenticationSchemes { get; set; } + string AuthenticationSchemes { get; set; } } } diff --git a/src/Microsoft.AspNetCore.Authorization/Infrastructure/ClaimsAuthorizationRequirement.cs b/src/Microsoft.AspNetCore.Authorization/Infrastructure/ClaimsAuthorizationRequirement.cs index 4248e4813..93b1deea6 100644 --- a/src/Microsoft.AspNetCore.Authorization/Infrastructure/ClaimsAuthorizationRequirement.cs +++ b/src/Microsoft.AspNetCore.Authorization/Infrastructure/ClaimsAuthorizationRequirement.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Authorization.Infrastructure { @@ -68,7 +67,7 @@ protected override Task HandleRequirementAsync(AuthorizationHandlerContext conte context.Succeed(requirement); } } - return TaskCache.CompletedTask; + return Task.CompletedTask; } } } diff --git a/src/Microsoft.AspNetCore.Authorization/Infrastructure/DenyAnonymousAuthorizationRequirement.cs b/src/Microsoft.AspNetCore.Authorization/Infrastructure/DenyAnonymousAuthorizationRequirement.cs index 5bae319b3..e88cce7aa 100644 --- a/src/Microsoft.AspNetCore.Authorization/Infrastructure/DenyAnonymousAuthorizationRequirement.cs +++ b/src/Microsoft.AspNetCore.Authorization/Infrastructure/DenyAnonymousAuthorizationRequirement.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Threading.Tasks; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Authorization.Infrastructure { @@ -28,7 +27,7 @@ protected override Task HandleRequirementAsync(AuthorizationHandlerContext conte { context.Succeed(requirement); } - return TaskCache.CompletedTask; + return Task.CompletedTask; } } } diff --git a/src/Microsoft.AspNetCore.Authorization/Infrastructure/NameAuthorizationRequirement.cs b/src/Microsoft.AspNetCore.Authorization/Infrastructure/NameAuthorizationRequirement.cs index 9fb295082..02ab946fa 100644 --- a/src/Microsoft.AspNetCore.Authorization/Infrastructure/NameAuthorizationRequirement.cs +++ b/src/Microsoft.AspNetCore.Authorization/Infrastructure/NameAuthorizationRequirement.cs @@ -4,7 +4,6 @@ using System; using System.Linq; using System.Threading.Tasks; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Authorization.Infrastructure { @@ -47,7 +46,7 @@ protected override Task HandleRequirementAsync(AuthorizationHandlerContext conte context.Succeed(requirement); } } - return TaskCache.CompletedTask; + return Task.CompletedTask; } } } diff --git a/src/Microsoft.AspNetCore.Authorization/Infrastructure/PassThroughAuthorizationHandler.cs b/src/Microsoft.AspNetCore.Authorization/Infrastructure/PassThroughAuthorizationHandler.cs index 60fd66b85..6f0b8293f 100644 --- a/src/Microsoft.AspNetCore.Authorization/Infrastructure/PassThroughAuthorizationHandler.cs +++ b/src/Microsoft.AspNetCore.Authorization/Infrastructure/PassThroughAuthorizationHandler.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Authorization.Infrastructure { /// - /// Infrastructre class which allows an to + /// Infrastructure class which allows an to /// be its own . /// public class PassThroughAuthorizationHandler : IAuthorizationHandler diff --git a/src/Microsoft.AspNetCore.Authorization/Infrastructure/RolesAuthorizationRequirement.cs b/src/Microsoft.AspNetCore.Authorization/Infrastructure/RolesAuthorizationRequirement.cs index 44e2b9a22..811e17aac 100644 --- a/src/Microsoft.AspNetCore.Authorization/Infrastructure/RolesAuthorizationRequirement.cs +++ b/src/Microsoft.AspNetCore.Authorization/Infrastructure/RolesAuthorizationRequirement.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Authorization.Infrastructure { @@ -62,7 +61,7 @@ protected override Task HandleRequirementAsync(AuthorizationHandlerContext conte context.Succeed(requirement); } } - return TaskCache.CompletedTask; + return Task.CompletedTask; } } diff --git a/src/Microsoft.AspNetCore.Authorization/LoggingExtensions.cs b/src/Microsoft.AspNetCore.Authorization/LoggingExtensions.cs index 1d524dd74..386df85e0 100644 --- a/src/Microsoft.AspNetCore.Authorization/LoggingExtensions.cs +++ b/src/Microsoft.AspNetCore.Authorization/LoggingExtensions.cs @@ -7,29 +7,25 @@ namespace Microsoft.Extensions.Logging { internal static class LoggingExtensions { - private static Action _userAuthorizationFailed; - private static Action _userAuthorizationSucceeded; + private static Action _userAuthorizationFailed; + private static Action _userAuthorizationSucceeded; static LoggingExtensions() { - _userAuthorizationSucceeded = LoggerMessage.Define( + _userAuthorizationSucceeded = LoggerMessage.Define( eventId: 1, logLevel: LogLevel.Information, - formatString: "Authorization was successful for user: {UserName}."); - _userAuthorizationFailed = LoggerMessage.Define( + formatString: "Authorization was successful."); + _userAuthorizationFailed = LoggerMessage.Define( eventId: 2, logLevel: LogLevel.Information, - formatString: "Authorization failed for user: {UserName}."); + formatString: "Authorization failed."); } - public static void UserAuthorizationSucceeded(this ILogger logger, string userName) - { - _userAuthorizationSucceeded(logger, userName, null); - } + public static void UserAuthorizationSucceeded(this ILogger logger) + => _userAuthorizationSucceeded(logger, null); - public static void UserAuthorizationFailed(this ILogger logger, string userName) - { - _userAuthorizationFailed(logger, userName, null); - } + public static void UserAuthorizationFailed(this ILogger logger) + => _userAuthorizationFailed(logger, null); } } diff --git a/src/Microsoft.AspNetCore.Authorization/Microsoft.AspNetCore.Authorization.csproj b/src/Microsoft.AspNetCore.Authorization/Microsoft.AspNetCore.Authorization.csproj new file mode 100644 index 000000000..9192ac8cf --- /dev/null +++ b/src/Microsoft.AspNetCore.Authorization/Microsoft.AspNetCore.Authorization.csproj @@ -0,0 +1,20 @@ + + + + ASP.NET Core authorization classes. +Commonly used types: +Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute +Microsoft.AspNetCore.Authorization.AuthorizeAttribute + netcoreapp3.0 + $(NoWarn);CS1591 + true + aspnetcore;authorization + false + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Authorization/Microsoft.AspNetCore.Authorization.xproj b/src/Microsoft.AspNetCore.Authorization/Microsoft.AspNetCore.Authorization.xproj deleted file mode 100644 index cc6041f8f..000000000 --- a/src/Microsoft.AspNetCore.Authorization/Microsoft.AspNetCore.Authorization.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 6ab3e514-5894-4131-9399-dc7d5284addb - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authorization/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Authorization/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff..000000000 --- a/src/Microsoft.AspNetCore.Authorization/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.Authorization/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Authorization/Properties/Resources.Designer.cs index 116001e65..c83fa9ea5 100644 --- a/src/Microsoft.AspNetCore.Authorization/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Authorization/Properties/Resources.Designer.cs @@ -15,48 +15,42 @@ private static readonly ResourceManager _resourceManager /// internal static string Exception_AuthorizationPolicyEmpty { - get { return GetString("Exception_AuthorizationPolicyEmpty"); } + get => GetString("Exception_AuthorizationPolicyEmpty"); } /// /// AuthorizationPolicy must have at least one requirement. /// internal static string FormatException_AuthorizationPolicyEmpty() - { - return GetString("Exception_AuthorizationPolicyEmpty"); - } + => GetString("Exception_AuthorizationPolicyEmpty"); /// /// The AuthorizationPolicy named: '{0}' was not found. /// internal static string Exception_AuthorizationPolicyNotFound { - get { return GetString("Exception_AuthorizationPolicyNotFound"); } + get => GetString("Exception_AuthorizationPolicyNotFound"); } /// /// The AuthorizationPolicy named: '{0}' was not found. /// internal static string FormatException_AuthorizationPolicyNotFound(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("Exception_AuthorizationPolicyNotFound"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("Exception_AuthorizationPolicyNotFound"), p0); /// /// At least one role must be specified. /// internal static string Exception_RoleRequirementEmpty { - get { return GetString("Exception_RoleRequirementEmpty"); } + get => GetString("Exception_RoleRequirementEmpty"); } /// /// At least one role must be specified. /// internal static string FormatException_RoleRequirementEmpty() - { - return GetString("Exception_RoleRequirementEmpty"); - } + => GetString("Exception_RoleRequirementEmpty"); private static string GetString(string name, params string[] formatterNames) { diff --git a/src/Microsoft.AspNetCore.Authorization/baseline.net45.json b/src/Microsoft.AspNetCore.Authorization/baseline.net45.json deleted file mode 100644 index 8ae585270..000000000 --- a/src/Microsoft.AspNetCore.Authorization/baseline.net45.json +++ /dev/null @@ -1,1593 +0,0 @@ -{ - "AssemblyIdentity": "Microsoft.AspNetCore.Authorization, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", - "Types": [ - { - "Name": "Microsoft.Extensions.DependencyInjection.AuthorizationServiceCollectionExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "AddAuthorization", - "Parameters": [ - { - "Name": "services", - "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" - } - ], - "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddAuthorization", - "Parameters": [ - { - "Name": "services", - "Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection" - }, - { - "Name": "configure", - "Type": "System.Action" - } - ], - "ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "System.Attribute", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAllowAnonymous" - ], - "Members": [ - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.AuthorizationHandler", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizationHandler" - ], - "Members": [ - { - "Kind": "Method", - "Name": "HandleAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleRequirementAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" - }, - { - "Name": "requirement", - "Type": "T0" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Abstract": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Protected", - "GenericParameter": [] - } - ], - "GenericParameters": [ - { - "ParameterName": "TRequirement", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizationRequirement" - ] - } - ] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.AuthorizationHandler", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizationHandler" - ], - "Members": [ - { - "Kind": "Method", - "Name": "HandleAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleRequirementAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" - }, - { - "Name": "requirement", - "Type": "T0" - }, - { - "Name": "resource", - "Type": "T1" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Abstract": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Protected", - "GenericParameter": [] - } - ], - "GenericParameters": [ - { - "ParameterName": "TRequirement", - "ParameterPosition": 0, - "BaseTypeOrInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizationRequirement" - ] - }, - { - "ParameterName": "TResource", - "ParameterPosition": 1, - "BaseTypeOrInterfaces": [] - } - ] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Requirements", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IEnumerable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_User", - "Parameters": [], - "ReturnType": "System.Security.Claims.ClaimsPrincipal", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Resource", - "Parameters": [], - "ReturnType": "System.Object", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_PendingRequirements", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IEnumerable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_HasFailed", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_HasSucceeded", - "Parameters": [], - "ReturnType": "System.Boolean", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Fail", - "Parameters": [], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Succeed", - "Parameters": [ - { - "Name": "requirement", - "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationRequirement" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "requirements", - "Type": "System.Collections.Generic.IEnumerable" - }, - { - "Name": "user", - "Type": "System.Security.Claims.ClaimsPrincipal" - }, - { - "Name": "resource", - "Type": "System.Object" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.AuthorizationOptions", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_DefaultPolicy", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_DefaultPolicy", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddPolicy", - "Parameters": [ - { - "Name": "name", - "Type": "System.String" - }, - { - "Name": "policy", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddPolicy", - "Parameters": [ - { - "Name": "name", - "Type": "System.String" - }, - { - "Name": "configurePolicy", - "Type": "System.Action" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetPolicy", - "Parameters": [ - { - "Name": "name", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Requirements", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IReadOnlyList", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AuthenticationSchemes", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IReadOnlyList", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Combine", - "Parameters": [ - { - "Name": "policies", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy[]", - "IsParams": true - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Combine", - "Parameters": [ - { - "Name": "policies", - "Type": "System.Collections.Generic.IEnumerable" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "CombineAsync", - "Parameters": [ - { - "Name": "policyProvider", - "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationPolicyProvider" - }, - { - "Name": "authorizeData", - "Type": "System.Collections.Generic.IEnumerable" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Static": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "requirements", - "Type": "System.Collections.Generic.IEnumerable" - }, - { - "Name": "authenticationSchemes", - "Type": "System.Collections.Generic.IEnumerable" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Requirements", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IList", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Requirements", - "Parameters": [ - { - "Name": "value", - "Type": "System.Collections.Generic.IList" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AuthenticationSchemes", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IList", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_AuthenticationSchemes", - "Parameters": [ - { - "Name": "value", - "Type": "System.Collections.Generic.IList" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddAuthenticationSchemes", - "Parameters": [ - { - "Name": "schemes", - "Type": "System.String[]", - "IsParams": true - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AddRequirements", - "Parameters": [ - { - "Name": "requirements", - "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationRequirement[]", - "IsParams": true - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Combine", - "Parameters": [ - { - "Name": "policy", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RequireClaim", - "Parameters": [ - { - "Name": "claimType", - "Type": "System.String" - }, - { - "Name": "requiredValues", - "Type": "System.String[]", - "IsParams": true - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RequireClaim", - "Parameters": [ - { - "Name": "claimType", - "Type": "System.String" - }, - { - "Name": "requiredValues", - "Type": "System.Collections.Generic.IEnumerable" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RequireClaim", - "Parameters": [ - { - "Name": "claimType", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RequireRole", - "Parameters": [ - { - "Name": "roles", - "Type": "System.String[]", - "IsParams": true - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RequireRole", - "Parameters": [ - { - "Name": "roles", - "Type": "System.Collections.Generic.IEnumerable" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RequireUserName", - "Parameters": [ - { - "Name": "userName", - "Type": "System.String" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RequireAuthenticatedUser", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RequireAssertion", - "Parameters": [ - { - "Name": "handler", - "Type": "System.Func" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "RequireAssertion", - "Parameters": [ - { - "Name": "handler", - "Type": "System.Func>" - } - ], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Build", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "authenticationSchemes", - "Type": "System.String[]", - "IsParams": true - } - ], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "policy", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.AuthorizationServiceExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "AuthorizeAsync", - "Parameters": [ - { - "Name": "service", - "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationService" - }, - { - "Name": "user", - "Type": "System.Security.Claims.ClaimsPrincipal" - }, - { - "Name": "resource", - "Type": "System.Object" - }, - { - "Name": "requirement", - "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationRequirement" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AuthorizeAsync", - "Parameters": [ - { - "Name": "service", - "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationService" - }, - { - "Name": "user", - "Type": "System.Security.Claims.ClaimsPrincipal" - }, - { - "Name": "resource", - "Type": "System.Object" - }, - { - "Name": "policy", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AuthorizeAsync", - "Parameters": [ - { - "Name": "service", - "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationService" - }, - { - "Name": "user", - "Type": "System.Security.Claims.ClaimsPrincipal" - }, - { - "Name": "policy", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AuthorizeAsync", - "Parameters": [ - { - "Name": "service", - "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationService" - }, - { - "Name": "user", - "Type": "System.Security.Claims.ClaimsPrincipal" - }, - { - "Name": "policyName", - "Type": "System.String" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.AuthorizeAttribute", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "System.Attribute", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizeData" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_Policy", - "Parameters": [], - "ReturnType": "System.String", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizeData", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Policy", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizeData", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Roles", - "Parameters": [], - "ReturnType": "System.String", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizeData", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Roles", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizeData", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ActiveAuthenticationSchemes", - "Parameters": [], - "ReturnType": "System.String", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizeData", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ActiveAuthenticationSchemes", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizeData", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "policy", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.DefaultAuthorizationPolicyProvider", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizationPolicyProvider" - ], - "Members": [ - { - "Kind": "Method", - "Name": "GetDefaultPolicyAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizationPolicyProvider", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetPolicyAsync", - "Parameters": [ - { - "Name": "policyName", - "Type": "System.String" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizationPolicyProvider", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.DefaultAuthorizationService", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizationService" - ], - "Members": [ - { - "Kind": "Method", - "Name": "AuthorizeAsync", - "Parameters": [ - { - "Name": "user", - "Type": "System.Security.Claims.ClaimsPrincipal" - }, - { - "Name": "resource", - "Type": "System.Object" - }, - { - "Name": "requirements", - "Type": "System.Collections.Generic.IEnumerable" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizationService", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AuthorizeAsync", - "Parameters": [ - { - "Name": "user", - "Type": "System.Security.Claims.ClaimsPrincipal" - }, - { - "Name": "resource", - "Type": "System.Object" - }, - { - "Name": "policyName", - "Type": "System.String" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizationService", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "policyProvider", - "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationPolicyProvider" - }, - { - "Name": "handlers", - "Type": "System.Collections.Generic.IEnumerable" - }, - { - "Name": "logger", - "Type": "Microsoft.Extensions.Logging.ILogger" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.IAllowAnonymous", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.IAuthorizationHandler", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "HandleAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.IAuthorizationPolicyProvider", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "GetPolicyAsync", - "Parameters": [ - { - "Name": "policyName", - "Type": "System.String" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "GetDefaultPolicyAsync", - "Parameters": [], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.IAuthorizationRequirement", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.IAuthorizationService", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "AuthorizeAsync", - "Parameters": [ - { - "Name": "user", - "Type": "System.Security.Claims.ClaimsPrincipal" - }, - { - "Name": "resource", - "Type": "System.Object" - }, - { - "Name": "requirements", - "Type": "System.Collections.Generic.IEnumerable" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "AuthorizeAsync", - "Parameters": [ - { - "Name": "user", - "Type": "System.Security.Claims.ClaimsPrincipal" - }, - { - "Name": "resource", - "Type": "System.Object" - }, - { - "Name": "policyName", - "Type": "System.String" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.IAuthorizeData", - "Visibility": "Public", - "Kind": "Interface", - "Abstract": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Policy", - "Parameters": [], - "ReturnType": "System.String", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Policy", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Roles", - "Parameters": [], - "ReturnType": "System.String", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Roles", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_ActiveAuthenticationSchemes", - "Parameters": [], - "ReturnType": "System.String", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_ActiveAuthenticationSchemes", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.Infrastructure.AssertionRequirement", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizationHandler", - "Microsoft.AspNetCore.Authorization.IAuthorizationRequirement" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_Handler", - "Parameters": [], - "ReturnType": "System.Func>", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "handler", - "Type": "System.Func" - } - ], - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "handler", - "Type": "System.Func>" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authorization.AuthorizationHandler", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizationRequirement" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_ClaimType", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_AllowedValues", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IEnumerable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleRequirementAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" - }, - { - "Name": "requirement", - "Type": "Microsoft.AspNetCore.Authorization.Infrastructure.ClaimsAuthorizationRequirement" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "claimType", - "Type": "System.String" - }, - { - "Name": "allowedValues", - "Type": "System.Collections.Generic.IEnumerable" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.Infrastructure.DenyAnonymousAuthorizationRequirement", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authorization.AuthorizationHandler", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizationRequirement" - ], - "Members": [ - { - "Kind": "Method", - "Name": "HandleRequirementAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" - }, - { - "Name": "requirement", - "Type": "Microsoft.AspNetCore.Authorization.Infrastructure.DenyAnonymousAuthorizationRequirement" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.Infrastructure.NameAuthorizationRequirement", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authorization.AuthorizationHandler", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizationRequirement" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_RequiredName", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleRequirementAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" - }, - { - "Name": "requirement", - "Type": "Microsoft.AspNetCore.Authorization.Infrastructure.NameAuthorizationRequirement" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "requiredName", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.Infrastructure.OperationAuthorizationRequirement", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizationRequirement" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_Name", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Name", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.Infrastructure.PassThroughAuthorizationHandler", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizationHandler" - ], - "Members": [ - { - "Kind": "Method", - "Name": "HandleAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Sealed": true, - "Virtual": true, - "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizationHandler", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Authorization.Infrastructure.RolesAuthorizationRequirement", - "Visibility": "Public", - "Kind": "Class", - "BaseType": "Microsoft.AspNetCore.Authorization.AuthorizationHandler", - "ImplementedInterfaces": [ - "Microsoft.AspNetCore.Authorization.IAuthorizationRequirement" - ], - "Members": [ - { - "Kind": "Method", - "Name": "get_AllowedRoles", - "Parameters": [], - "ReturnType": "System.Collections.Generic.IEnumerable", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "HandleRequirementAsync", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" - }, - { - "Name": "requirement", - "Type": "Microsoft.AspNetCore.Authorization.Infrastructure.RolesAuthorizationRequirement" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Virtual": true, - "Override": true, - "Visibility": "Protected", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "allowedRoles", - "Type": "System.Collections.Generic.IEnumerable" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - } - ], - "SourceFilters": [] -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authorization/baseline.netcore.json b/src/Microsoft.AspNetCore.Authorization/baseline.netcore.json index 8ae585270..9910c93f6 100644 --- a/src/Microsoft.AspNetCore.Authorization/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.Authorization/baseline.netcore.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.Authorization, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.Authorization, Version=2.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.Extensions.DependencyInjection.AuthorizationServiceCollectionExtensions", @@ -66,6 +66,54 @@ ], "GenericParameters": [] }, + { + "Name": "Microsoft.AspNetCore.Authorization.AuthorizationFailure", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_FailCalled", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_FailedRequirements", + "Parameters": [], + "ReturnType": "System.Collections.Generic.IEnumerable", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "ExplicitFail", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationFailure", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Failed", + "Parameters": [ + { + "Name": "failed", + "Type": "System.Collections.Generic.IEnumerable" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationFailure", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, { "Name": "Microsoft.AspNetCore.Authorization.AuthorizationHandler", "Visibility": "Public", @@ -208,6 +256,7 @@ "Name": "get_Requirements", "Parameters": [], "ReturnType": "System.Collections.Generic.IEnumerable", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, @@ -216,6 +265,7 @@ "Name": "get_User", "Parameters": [], "ReturnType": "System.Security.Claims.ClaimsPrincipal", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, @@ -224,6 +274,7 @@ "Name": "get_Resource", "Parameters": [], "ReturnType": "System.Object", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, @@ -232,6 +283,7 @@ "Name": "get_PendingRequirements", "Parameters": [], "ReturnType": "System.Collections.Generic.IEnumerable", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, @@ -240,6 +292,7 @@ "Name": "get_HasFailed", "Parameters": [], "ReturnType": "System.Boolean", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, @@ -248,6 +301,7 @@ "Name": "get_HasSucceeded", "Parameters": [], "ReturnType": "System.Boolean", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, @@ -256,6 +310,7 @@ "Name": "Fail", "Parameters": [], "ReturnType": "System.Void", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, @@ -269,6 +324,7 @@ } ], "ReturnType": "System.Void", + "Virtual": true, "Visibility": "Public", "GenericParameter": [] }, @@ -301,6 +357,27 @@ "Kind": "Class", "ImplementedInterfaces": [], "Members": [ + { + "Kind": "Method", + "Name": "get_InvokeHandlersAfterFailure", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_InvokeHandlersAfterFailure", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Method", "Name": "get_DefaultPolicy", @@ -714,6 +791,63 @@ ], "GenericParameters": [] }, + { + "Name": "Microsoft.AspNetCore.Authorization.AuthorizationResult", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "get_Succeeded", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_Failure", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationFailure", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Success", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationResult", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Failed", + "Parameters": [ + { + "Name": "failure", + "Type": "Microsoft.AspNetCore.Authorization.AuthorizationFailure" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationResult", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "Failed", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationResult", + "Static": true, + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, { "Name": "Microsoft.AspNetCore.Authorization.AuthorizationServiceExtensions", "Visibility": "Public", @@ -744,7 +878,7 @@ "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationRequirement" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Threading.Tasks.Task", "Static": true, "Extension": true, "Visibility": "Public", @@ -771,7 +905,7 @@ "Type": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Threading.Tasks.Task", "Static": true, "Extension": true, "Visibility": "Public", @@ -794,7 +928,7 @@ "Type": "Microsoft.AspNetCore.Authorization.AuthorizationPolicy" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Threading.Tasks.Task", "Static": true, "Extension": true, "Visibility": "Public", @@ -817,7 +951,7 @@ "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Threading.Tasks.Task", "Static": true, "Extension": true, "Visibility": "Public", @@ -891,7 +1025,7 @@ }, { "Kind": "Method", - "Name": "get_ActiveAuthenticationSchemes", + "Name": "get_AuthenticationSchemes", "Parameters": [], "ReturnType": "System.String", "Sealed": true, @@ -902,7 +1036,7 @@ }, { "Kind": "Method", - "Name": "set_ActiveAuthenticationSchemes", + "Name": "set_AuthenticationSchemes", "Parameters": [ { "Name": "value", @@ -916,6 +1050,27 @@ "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Method", + "Name": "get_ActiveAuthenticationSchemes", + "Parameters": [], + "ReturnType": "System.String", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ActiveAuthenticationSchemes", + "Parameters": [ + { + "Name": "value", + "Type": "System.String" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Constructor", "Name": ".ctor", @@ -938,6 +1093,120 @@ ], "GenericParameters": [] }, + { + "Name": "Microsoft.AspNetCore.Authorization.DefaultAuthorizationEvaluator", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authorization.IAuthorizationEvaluator" + ], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationResult", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizationEvaluator", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authorization.DefaultAuthorizationHandlerContextFactory", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authorization.IAuthorizationHandlerContextFactory" + ], + "Members": [ + { + "Kind": "Method", + "Name": "CreateContext", + "Parameters": [ + { + "Name": "requirements", + "Type": "System.Collections.Generic.IEnumerable" + }, + { + "Name": "user", + "Type": "System.Security.Claims.ClaimsPrincipal" + }, + { + "Name": "resource", + "Type": "System.Object" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext", + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizationHandlerContextFactory", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authorization.DefaultAuthorizationHandlerProvider", + "Visibility": "Public", + "Kind": "Class", + "ImplementedInterfaces": [ + "Microsoft.AspNetCore.Authorization.IAuthorizationHandlerProvider" + ], + "Members": [ + { + "Kind": "Method", + "Name": "GetHandlersAsync", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task>", + "Sealed": true, + "Virtual": true, + "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizationHandlerProvider", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "handlers", + "Type": "System.Collections.Generic.IEnumerable" + } + ], + "Visibility": "Public", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, { "Name": "Microsoft.AspNetCore.Authorization.DefaultAuthorizationPolicyProvider", "Visibility": "Public", @@ -1012,7 +1281,7 @@ "Type": "System.Collections.Generic.IEnumerable" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Threading.Tasks.Task", "Sealed": true, "Virtual": true, "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizationService", @@ -1036,7 +1305,7 @@ "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Threading.Tasks.Task", "Sealed": true, "Virtual": true, "ImplementedInterface": "Microsoft.AspNetCore.Authorization.IAuthorizationService", @@ -1053,11 +1322,23 @@ }, { "Name": "handlers", - "Type": "System.Collections.Generic.IEnumerable" + "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationHandlerProvider" }, { "Name": "logger", "Type": "Microsoft.Extensions.Logging.ILogger" + }, + { + "Name": "contextFactory", + "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationHandlerContextFactory" + }, + { + "Name": "evaluator", + "Type": "Microsoft.AspNetCore.Authorization.IAuthorizationEvaluator" + }, + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" } ], "Visibility": "Public", @@ -1075,6 +1356,28 @@ "Members": [], "GenericParameters": [] }, + { + "Name": "Microsoft.AspNetCore.Authorization.IAuthorizationEvaluator", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "Evaluate", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationResult", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, { "Name": "Microsoft.AspNetCore.Authorization.IAuthorizationHandler", "Visibility": "Public", @@ -1097,6 +1400,58 @@ ], "GenericParameters": [] }, + { + "Name": "Microsoft.AspNetCore.Authorization.IAuthorizationHandlerContextFactory", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "CreateContext", + "Parameters": [ + { + "Name": "requirements", + "Type": "System.Collections.Generic.IEnumerable" + }, + { + "Name": "user", + "Type": "System.Security.Claims.ClaimsPrincipal" + }, + { + "Name": "resource", + "Type": "System.Object" + } + ], + "ReturnType": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, + { + "Name": "Microsoft.AspNetCore.Authorization.IAuthorizationHandlerProvider", + "Visibility": "Public", + "Kind": "Interface", + "Abstract": true, + "ImplementedInterfaces": [], + "Members": [ + { + "Kind": "Method", + "Name": "GetHandlersAsync", + "Parameters": [ + { + "Name": "context", + "Type": "Microsoft.AspNetCore.Authorization.AuthorizationHandlerContext" + } + ], + "ReturnType": "System.Threading.Tasks.Task>", + "GenericParameter": [] + } + ], + "GenericParameters": [] + }, { "Name": "Microsoft.AspNetCore.Authorization.IAuthorizationPolicyProvider", "Visibility": "Public", @@ -1159,7 +1514,7 @@ "Type": "System.Collections.Generic.IEnumerable" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Threading.Tasks.Task", "GenericParameter": [] }, { @@ -1179,7 +1534,7 @@ "Type": "System.String" } ], - "ReturnType": "System.Threading.Tasks.Task", + "ReturnType": "System.Threading.Tasks.Task", "GenericParameter": [] } ], @@ -1232,14 +1587,14 @@ }, { "Kind": "Method", - "Name": "get_ActiveAuthenticationSchemes", + "Name": "get_AuthenticationSchemes", "Parameters": [], "ReturnType": "System.String", "GenericParameter": [] }, { "Kind": "Method", - "Name": "set_ActiveAuthenticationSchemes", + "Name": "set_AuthenticationSchemes", "Parameters": [ { "Name": "value", @@ -1588,6 +1943,5 @@ ], "GenericParameters": [] } - ], - "SourceFilters": [] + ] } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Authorization/project.json b/src/Microsoft.AspNetCore.Authorization/project.json deleted file mode 100644 index 883e92641..000000000 --- a/src/Microsoft.AspNetCore.Authorization/project.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core authorization classes.\r\nCommonly used types:\r\nMicrosoft.AspNetCore.Authorization.AllowAnonymousAttribute\r\nMicrosoft.AspNetCore.Authorization.AuthorizeAttribute", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/security" - }, - "tags": [ - "aspnetcore", - "authorization" - ] - }, - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "1.2.0-*", - "Microsoft.Extensions.Options": "1.2.0-*", - "Microsoft.Extensions.TaskCache.Sources": { - "version": "1.2.0-*", - "type": "build" - }, - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": { - "frameworkAssemblies": { - "System.Runtime": { - "type": "build" - } - } - }, - "netstandard1.3": { - "dependencies": { - "System.Security.Claims": "4.4.0-*" - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.ChunkingCookieManager.Sources/Microsoft.AspNetCore.ChunkingCookieManager.Sources.xproj b/src/Microsoft.AspNetCore.ChunkingCookieManager.Sources/Microsoft.AspNetCore.ChunkingCookieManager.Sources.xproj deleted file mode 100644 index 593e5d681..000000000 --- a/src/Microsoft.AspNetCore.ChunkingCookieManager.Sources/Microsoft.AspNetCore.ChunkingCookieManager.Sources.xproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - 14.0.25420 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 2690fbe6-9d27-4c84-b82c-11188b0bcda3 - Microsoft.AspNetCore.ChunkingCookieManager.Sources - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.ChunkingCookieManager.Sources/project.json b/src/Microsoft.AspNetCore.ChunkingCookieManager.Sources/project.json deleted file mode 100644 index 7ccf0307d..000000000 --- a/src/Microsoft.AspNetCore.ChunkingCookieManager.Sources/project.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "version": "1.2.0-*", - "shared": "*.cs", - "dependencies": { - "Microsoft.AspNetCore.Http.Abstractions": "1.2.0-*", - "Microsoft.Net.Http.Headers": "1.2.0-*", - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.CookiePolicy/AppendCookieContext.cs b/src/Microsoft.AspNetCore.CookiePolicy/AppendCookieContext.cs index 1b13251f7..bbb4899c0 100644 --- a/src/Microsoft.AspNetCore.CookiePolicy/AppendCookieContext.cs +++ b/src/Microsoft.AspNetCore.CookiePolicy/AppendCookieContext.cs @@ -19,5 +19,8 @@ public AppendCookieContext(HttpContext context, CookieOptions options, string na public CookieOptions CookieOptions { get; } public string CookieName { get; set; } public string CookieValue { get; set; } + public bool IsConsentNeeded { get; internal set; } + public bool HasConsent { get; internal set; } + public bool IssueCookie { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.CookiePolicy/CookiePolicyAppBuilderExtensions.cs b/src/Microsoft.AspNetCore.CookiePolicy/CookiePolicyAppBuilderExtensions.cs index bb5700fc6..1564193b9 100644 --- a/src/Microsoft.AspNetCore.CookiePolicy/CookiePolicyAppBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.CookiePolicy/CookiePolicyAppBuilderExtensions.cs @@ -13,9 +13,9 @@ namespace Microsoft.AspNetCore.Builder public static class CookiePolicyAppBuilderExtensions { /// - /// Adds the middleware to the specified , which enables cookie policy capabilities. + /// Adds the handler to the specified , which enables cookie policy capabilities. /// - /// The to add the middleware to. + /// The to add the handler to. /// A reference to this instance after the operation has completed. public static IApplicationBuilder UseCookiePolicy(this IApplicationBuilder app) { @@ -28,10 +28,10 @@ public static IApplicationBuilder UseCookiePolicy(this IApplicationBuilder app) } /// - /// Adds the middleware to the specified , which enables cookie policy capabilities. + /// Adds the handler to the specified , which enables cookie policy capabilities. /// - /// The to add the middleware to. - /// A that specifies options for the middleware. + /// The to add the handler to. + /// A that specifies options for the handler. /// A reference to this instance after the operation has completed. public static IApplicationBuilder UseCookiePolicy(this IApplicationBuilder app, CookiePolicyOptions options) { diff --git a/src/Microsoft.AspNetCore.CookiePolicy/CookiePolicyMiddleware.cs b/src/Microsoft.AspNetCore.CookiePolicy/CookiePolicyMiddleware.cs index 46daaad81..1a810b7d5 100644 --- a/src/Microsoft.AspNetCore.CookiePolicy/CookiePolicyMiddleware.cs +++ b/src/Microsoft.AspNetCore.CookiePolicy/CookiePolicyMiddleware.cs @@ -6,6 +6,8 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.CookiePolicy @@ -13,13 +15,20 @@ namespace Microsoft.AspNetCore.CookiePolicy public class CookiePolicyMiddleware { private readonly RequestDelegate _next; + private readonly ILogger _logger; - public CookiePolicyMiddleware( - RequestDelegate next, - IOptions options) + public CookiePolicyMiddleware(RequestDelegate next, IOptions options, ILoggerFactory factory) + { + Options = options.Value; + _next = next ?? throw new ArgumentNullException(nameof(next)); + _logger = factory.CreateLogger(); + } + + public CookiePolicyMiddleware(RequestDelegate next, IOptions options) { Options = options.Value; _next = next; + _logger = NullLogger.Instance; } public CookiePolicyOptions Options { get; set; } @@ -27,141 +36,21 @@ public CookiePolicyMiddleware( public Task Invoke(HttpContext context) { var feature = context.Features.Get() ?? new ResponseCookiesFeature(context.Features); - context.Features.Set(new CookiesWrapperFeature(context, Options, feature)); + var wrapper = new ResponseCookiesWrapper(context, Options, feature, _logger); + context.Features.Set(new CookiesWrapperFeature(wrapper)); + context.Features.Set(wrapper); + return _next(context); } private class CookiesWrapperFeature : IResponseCookiesFeature { - public CookiesWrapperFeature(HttpContext context, CookiePolicyOptions options, IResponseCookiesFeature feature) - { - Wrapper = new CookiesWrapper(context, options, feature); - } - - public IResponseCookies Wrapper { get; } - - public IResponseCookies Cookies - { - get - { - return Wrapper; - } - } - } - - private class CookiesWrapper : IResponseCookies - { - public CookiesWrapper(HttpContext context, CookiePolicyOptions options, IResponseCookiesFeature feature) - { - Context = context; - Feature = feature; - Policy = options; - } - - public HttpContext Context { get; } - - public IResponseCookiesFeature Feature { get; } - - public IResponseCookies Cookies + public CookiesWrapperFeature(ResponseCookiesWrapper wrapper) { - get - { - return Feature.Cookies; - } + Cookies = wrapper; } - public CookiePolicyOptions Policy { get; } - - private bool PolicyRequiresCookieOptions() - { - return Policy.HttpOnly != HttpOnlyPolicy.None || Policy.Secure != CookieSecurePolicy.None; - } - - public void Append(string key, string value) - { - if (PolicyRequiresCookieOptions() || Policy.OnAppendCookie != null) - { - Append(key, value, new CookieOptions()); - } - else - { - Cookies.Append(key, value); - } - } - - public void Append(string key, string value, CookieOptions options) - { - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - ApplyPolicy(options); - if (Policy.OnAppendCookie != null) - { - var context = new AppendCookieContext(Context, options, key, value); - Policy.OnAppendCookie(context); - key = context.CookieName; - value = context.CookieValue; - } - Cookies.Append(key, value, options); - } - - public void Delete(string key) - { - if (PolicyRequiresCookieOptions() || Policy.OnDeleteCookie != null) - { - Delete(key, new CookieOptions()); - } - else - { - Cookies.Delete(key); - } - } - - public void Delete(string key, CookieOptions options) - { - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - ApplyPolicy(options); - if (Policy.OnDeleteCookie != null) - { - var context = new DeleteCookieContext(Context, options, key); - Policy.OnDeleteCookie(context); - key = context.CookieName; - } - Cookies.Delete(key, options); - } - - private void ApplyPolicy(CookieOptions options) - { - switch (Policy.Secure) - { - case CookieSecurePolicy.Always: - options.Secure = true; - break; - case CookieSecurePolicy.SameAsRequest: - options.Secure = Context.Request.IsHttps; - break; - case CookieSecurePolicy.None: - break; - default: - throw new InvalidOperationException(); - } - switch (Policy.HttpOnly) - { - case HttpOnlyPolicy.Always: - options.HttpOnly = true; - break; - case HttpOnlyPolicy.None: - break; - default: - throw new InvalidOperationException(); - } - } + public IResponseCookies Cookies { get; } } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.CookiePolicy/CookiePolicyOptions.cs b/src/Microsoft.AspNetCore.CookiePolicy/CookiePolicyOptions.cs index 6aed18bfb..32d047297 100644 --- a/src/Microsoft.AspNetCore.CookiePolicy/CookiePolicyOptions.cs +++ b/src/Microsoft.AspNetCore.CookiePolicy/CookiePolicyOptions.cs @@ -12,6 +12,11 @@ namespace Microsoft.AspNetCore.Builder /// public class CookiePolicyOptions { + /// + /// Affects the cookie's same site attribute. + /// + public SameSiteMode MinimumSameSitePolicy { get; set; } = SameSiteMode.Lax; + /// /// Affects whether cookies must be HttpOnly. /// @@ -22,6 +27,18 @@ public class CookiePolicyOptions /// public CookieSecurePolicy Secure { get; set; } = CookieSecurePolicy.None; + public CookieBuilder ConsentCookie { get; set; } = new CookieBuilder() + { + Name = ".AspNet.Consent", + Expiration = TimeSpan.FromDays(365), + IsEssential = true, + }; + + /// + /// Checks if consent policies should be evaluated on this request. The default is false. + /// + public Func CheckConsentNeeded { get; set; } + /// /// Called when a cookie is appended. /// diff --git a/src/Microsoft.AspNetCore.CookiePolicy/DeleteCookieContext.cs b/src/Microsoft.AspNetCore.CookiePolicy/DeleteCookieContext.cs index f0693bf71..fd79ea8d4 100644 --- a/src/Microsoft.AspNetCore.CookiePolicy/DeleteCookieContext.cs +++ b/src/Microsoft.AspNetCore.CookiePolicy/DeleteCookieContext.cs @@ -17,5 +17,8 @@ public DeleteCookieContext(HttpContext context, CookieOptions options, string na public HttpContext Context { get; } public CookieOptions CookieOptions { get; } public string CookieName { get; set; } + public bool IsConsentNeeded { get; internal set; } + public bool HasConsent { get; internal set; } + public bool IssueCookie { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.CookiePolicy/LoggingExtensions.cs b/src/Microsoft.AspNetCore.CookiePolicy/LoggingExtensions.cs new file mode 100644 index 000000000..21b04facc --- /dev/null +++ b/src/Microsoft.AspNetCore.CookiePolicy/LoggingExtensions.cs @@ -0,0 +1,105 @@ +// 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 _needsConsent; + private static Action _hasConsent; + private static Action _consentGranted; + private static Action _consentWithdrawn; + private static Action _cookieSuppressed; + private static Action _deleteCookieSuppressed; + private static Action _upgradedToSecure; + private static Action _upgradedSameSite; + private static Action _upgradedToHttpOnly; + + static LoggingExtensions() + { + _needsConsent = LoggerMessage.Define( + eventId: 1, + logLevel: LogLevel.Trace, + formatString: "Needs consent: {needsConsent}."); + _hasConsent = LoggerMessage.Define( + eventId: 2, + logLevel: LogLevel.Trace, + formatString: "Has consent: {hasConsent}."); + _consentGranted = LoggerMessage.Define( + eventId: 3, + logLevel: LogLevel.Debug, + formatString: "Consent granted."); + _consentWithdrawn = LoggerMessage.Define( + eventId: 4, + logLevel: LogLevel.Debug, + formatString: "Consent withdrawn."); + _cookieSuppressed = LoggerMessage.Define( + eventId: 5, + logLevel: LogLevel.Debug, + formatString: "Cookie '{key}' suppressed due to consent policy."); + _deleteCookieSuppressed = LoggerMessage.Define( + eventId: 6, + logLevel: LogLevel.Debug, + formatString: "Delete cookie '{key}' suppressed due to developer policy."); + _upgradedToSecure = LoggerMessage.Define( + eventId: 7, + logLevel: LogLevel.Debug, + formatString: "Cookie '{key}' upgraded to 'secure'."); + _upgradedSameSite = LoggerMessage.Define( + eventId: 8, + logLevel: LogLevel.Debug, + formatString: "Cookie '{key}' same site mode upgraded to '{mode}'."); + _upgradedToHttpOnly = LoggerMessage.Define( + eventId: 9, + logLevel: LogLevel.Debug, + formatString: "Cookie '{key}' upgraded to 'httponly'."); + } + + public static void NeedsConsent(this ILogger logger, bool needsConsent) + { + _needsConsent(logger, needsConsent, null); + } + + public static void HasConsent(this ILogger logger, bool hasConsent) + { + _hasConsent(logger, hasConsent, null); + } + + public static void ConsentGranted(this ILogger logger) + { + _consentGranted(logger, null); + } + + public static void ConsentWithdrawn(this ILogger logger) + { + _consentWithdrawn(logger, null); + } + + public static void CookieSuppressed(this ILogger logger, string key) + { + _cookieSuppressed(logger, key, null); + } + + public static void DeleteCookieSuppressed(this ILogger logger, string key) + { + _deleteCookieSuppressed(logger, key, null); + } + + public static void CookieUpgradedToSecure(this ILogger logger, string key) + { + _upgradedToSecure(logger, key, null); + } + + public static void CookieSameSiteUpgraded(this ILogger logger, string key, string mode) + { + _upgradedSameSite(logger, key, mode, null); + } + + public static void CookieUpgradedToHttpOnly(this ILogger logger, string key) + { + _upgradedToHttpOnly(logger, key, null); + } + } +} diff --git a/src/Microsoft.AspNetCore.CookiePolicy/Microsoft.AspNetCore.CookiePolicy.csproj b/src/Microsoft.AspNetCore.CookiePolicy/Microsoft.AspNetCore.CookiePolicy.csproj new file mode 100644 index 000000000..81760d50a --- /dev/null +++ b/src/Microsoft.AspNetCore.CookiePolicy/Microsoft.AspNetCore.CookiePolicy.csproj @@ -0,0 +1,17 @@ + + + + ASP.NET Core cookie policy classes to control the behavior of cookies. + netcoreapp3.0 + $(NoWarn);CS1591 + true + aspnetcore + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.CookiePolicy/Microsoft.AspNetCore.CookiePolicy.xproj b/src/Microsoft.AspNetCore.CookiePolicy/Microsoft.AspNetCore.CookiePolicy.xproj deleted file mode 100644 index 0cd49f324..000000000 --- a/src/Microsoft.AspNetCore.CookiePolicy/Microsoft.AspNetCore.CookiePolicy.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 86183dc3-02a8-4a68-8b60-71ecec066e79 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.CookiePolicy/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.CookiePolicy/Properties/AssemblyInfo.cs deleted file mode 100644 index 76feceeff..000000000 --- a/src/Microsoft.AspNetCore.CookiePolicy/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection; -using System.Resources; - -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.CookiePolicy/ResponseCookiesWrapper.cs b/src/Microsoft.AspNetCore.CookiePolicy/ResponseCookiesWrapper.cs new file mode 100644 index 000000000..126c4d7bd --- /dev/null +++ b/src/Microsoft.AspNetCore.CookiePolicy/ResponseCookiesWrapper.cs @@ -0,0 +1,281 @@ +// 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.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.CookiePolicy +{ + internal class ResponseCookiesWrapper : IResponseCookies, ITrackingConsentFeature + { + private const string ConsentValue = "yes"; + private readonly ILogger _logger; + private bool? _isConsentNeeded; + private bool? _hasConsent; + + public ResponseCookiesWrapper(HttpContext context, CookiePolicyOptions options, IResponseCookiesFeature feature, ILogger logger) + { + Context = context; + Feature = feature; + Options = options; + _logger = logger; + } + + private HttpContext Context { get; } + + private IResponseCookiesFeature Feature { get; } + + private IResponseCookies Cookies => Feature.Cookies; + + private CookiePolicyOptions Options { get; } + + public bool IsConsentNeeded + { + get + { + if (!_isConsentNeeded.HasValue) + { + _isConsentNeeded = Options.CheckConsentNeeded == null ? false + : Options.CheckConsentNeeded(Context); + _logger.NeedsConsent(_isConsentNeeded.Value); + } + + return _isConsentNeeded.Value; + } + } + + public bool HasConsent + { + get + { + if (!_hasConsent.HasValue) + { + var cookie = Context.Request.Cookies[Options.ConsentCookie.Name]; + _hasConsent = string.Equals(cookie, ConsentValue, StringComparison.Ordinal); + _logger.HasConsent(_hasConsent.Value); + } + + return _hasConsent.Value; + } + } + + public bool CanTrack => !IsConsentNeeded || HasConsent; + + public void GrantConsent() + { + if (!HasConsent && !Context.Response.HasStarted) + { + var cookieOptions = Options.ConsentCookie.Build(Context); + // Note policy will be applied. We don't want to bypass policy because we want HttpOnly, Secure, etc. to apply. + Append(Options.ConsentCookie.Name, ConsentValue, cookieOptions); + _logger.ConsentGranted(); + } + _hasConsent = true; + } + + public void WithdrawConsent() + { + if (HasConsent && !Context.Response.HasStarted) + { + var cookieOptions = Options.ConsentCookie.Build(Context); + // Note policy will be applied. We don't want to bypass policy because we want HttpOnly, Secure, etc. to apply. + Delete(Options.ConsentCookie.Name, cookieOptions); + _logger.ConsentWithdrawn(); + } + _hasConsent = false; + } + + // Note policy will be applied. We don't want to bypass policy because we want HttpOnly, Secure, etc. to apply. + public string CreateConsentCookie() + { + var key = Options.ConsentCookie.Name; + var value = ConsentValue; + var options = Options.ConsentCookie.Build(Context); + ApplyAppendPolicy(ref key, ref value, options); + + var setCookieHeaderValue = new Net.Http.Headers.SetCookieHeaderValue( + Uri.EscapeDataString(key), + Uri.EscapeDataString(value)) + { + Domain = options.Domain, + Path = options.Path, + Expires = options.Expires, + MaxAge = options.MaxAge, + Secure = options.Secure, + SameSite = (Net.Http.Headers.SameSiteMode)options.SameSite, + HttpOnly = options.HttpOnly + }; + + return setCookieHeaderValue.ToString(); + } + + private bool CheckPolicyRequired() + { + return !CanTrack + || Options.MinimumSameSitePolicy != SameSiteMode.None + || Options.HttpOnly != HttpOnlyPolicy.None + || Options.Secure != CookieSecurePolicy.None; + } + + public void Append(string key, string value) + { + if (CheckPolicyRequired() || Options.OnAppendCookie != null) + { + Append(key, value, new CookieOptions()); + } + else + { + Cookies.Append(key, value); + } + } + + public void Append(string key, string value, CookieOptions options) + { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + if (ApplyAppendPolicy(ref key, ref value, options)) + { + Cookies.Append(key, value, options); + } + else + { + _logger.CookieSuppressed(key); + } + } + + private bool ApplyAppendPolicy(ref string key, ref string value, CookieOptions options) + { + var issueCookie = CanTrack || options.IsEssential; + ApplyPolicy(key, options); + if (Options.OnAppendCookie != null) + { + var context = new AppendCookieContext(Context, options, key, value) + { + IsConsentNeeded = IsConsentNeeded, + HasConsent = HasConsent, + IssueCookie = issueCookie, + }; + Options.OnAppendCookie(context); + + key = context.CookieName; + value = context.CookieValue; + issueCookie = context.IssueCookie; + } + + return issueCookie; + } + + public void Delete(string key) + { + if (CheckPolicyRequired() || Options.OnDeleteCookie != null) + { + Delete(key, new CookieOptions()); + } + else + { + Cookies.Delete(key); + } + } + + public void Delete(string key, CookieOptions options) + { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + // Assume you can always delete cookies unless directly overridden in the user event. + var issueCookie = true; + ApplyPolicy(key, options); + if (Options.OnDeleteCookie != null) + { + var context = new DeleteCookieContext(Context, options, key) + { + IsConsentNeeded = IsConsentNeeded, + HasConsent = HasConsent, + IssueCookie = issueCookie, + }; + Options.OnDeleteCookie(context); + + key = context.CookieName; + issueCookie = context.IssueCookie; + } + + if (issueCookie) + { + Cookies.Delete(key, options); + } + else + { + _logger.DeleteCookieSuppressed(key); + } + } + + private void ApplyPolicy(string key, CookieOptions options) + { + switch (Options.Secure) + { + case CookieSecurePolicy.Always: + if (!options.Secure) + { + options.Secure = true; + _logger.CookieUpgradedToSecure(key); + } + break; + case CookieSecurePolicy.SameAsRequest: + // Never downgrade a cookie + if (Context.Request.IsHttps && !options.Secure) + { + options.Secure = true; + _logger.CookieUpgradedToSecure(key); + } + break; + case CookieSecurePolicy.None: + break; + default: + throw new InvalidOperationException(); + } + switch (Options.MinimumSameSitePolicy) + { + case SameSiteMode.None: + break; + case SameSiteMode.Lax: + if (options.SameSite == SameSiteMode.None) + { + options.SameSite = SameSiteMode.Lax; + _logger.CookieSameSiteUpgraded(key, "lax"); + } + break; + case SameSiteMode.Strict: + if (options.SameSite != SameSiteMode.Strict) + { + options.SameSite = SameSiteMode.Strict; + _logger.CookieSameSiteUpgraded(key, "strict"); + } + break; + default: + throw new InvalidOperationException($"Unrecognized {nameof(SameSiteMode)} value {Options.MinimumSameSitePolicy.ToString()}"); + } + switch (Options.HttpOnly) + { + case HttpOnlyPolicy.Always: + if (!options.HttpOnly) + { + options.HttpOnly = true; + _logger.CookieUpgradedToHttpOnly(key); + } + break; + case HttpOnlyPolicy.None: + break; + default: + throw new InvalidOperationException($"Unrecognized {nameof(HttpOnlyPolicy)} value {Options.HttpOnly.ToString()}"); + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.CookiePolicy/baseline.net45.json b/src/Microsoft.AspNetCore.CookiePolicy/baseline.net45.json deleted file mode 100644 index 8eef347eb..000000000 --- a/src/Microsoft.AspNetCore.CookiePolicy/baseline.net45.json +++ /dev/null @@ -1,392 +0,0 @@ -{ - "AssemblyIdentity": "Microsoft.AspNetCore.CookiePolicy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", - "Types": [ - { - "Name": "Microsoft.AspNetCore.Builder.CookiePolicyAppBuilderExtensions", - "Visibility": "Public", - "Kind": "Class", - "Abstract": true, - "Static": true, - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "UseCookiePolicy", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "UseCookiePolicy", - "Parameters": [ - { - "Name": "app", - "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Builder.CookiePolicyOptions" - } - ], - "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder", - "Static": true, - "Extension": true, - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.Builder.CookiePolicyOptions", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_HttpOnly", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_HttpOnly", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_Secure", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.CookieSecurePolicy", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Secure", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Http.CookieSecurePolicy" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnAppendCookie", - "Parameters": [], - "ReturnType": "System.Action", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnAppendCookie", - "Parameters": [ - { - "Name": "value", - "Type": "System.Action" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_OnDeleteCookie", - "Parameters": [], - "ReturnType": "System.Action", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_OnDeleteCookie", - "Parameters": [ - { - "Name": "value", - "Type": "System.Action" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.CookiePolicy.AppendCookieContext", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Context", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpContext", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_CookieOptions", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.CookieOptions", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_CookieName", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_CookieName", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_CookieValue", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_CookieValue", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" - }, - { - "Name": "name", - "Type": "System.String" - }, - { - "Name": "value", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.CookiePolicy.CookiePolicyMiddleware", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Options", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Builder.CookiePolicyOptions", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_Options", - "Parameters": [ - { - "Name": "value", - "Type": "Microsoft.AspNetCore.Builder.CookiePolicyOptions" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "Invoke", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - } - ], - "ReturnType": "System.Threading.Tasks.Task", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "next", - "Type": "Microsoft.AspNetCore.Http.RequestDelegate" - }, - { - "Name": "options", - "Type": "Microsoft.Extensions.Options.IOptions" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.CookiePolicy.DeleteCookieContext", - "Visibility": "Public", - "Kind": "Class", - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Method", - "Name": "get_Context", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.HttpContext", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_CookieOptions", - "Parameters": [], - "ReturnType": "Microsoft.AspNetCore.Http.CookieOptions", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "get_CookieName", - "Parameters": [], - "ReturnType": "System.String", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Method", - "Name": "set_CookieName", - "Parameters": [ - { - "Name": "value", - "Type": "System.String" - } - ], - "ReturnType": "System.Void", - "Visibility": "Public", - "GenericParameter": [] - }, - { - "Kind": "Constructor", - "Name": ".ctor", - "Parameters": [ - { - "Name": "context", - "Type": "Microsoft.AspNetCore.Http.HttpContext" - }, - { - "Name": "options", - "Type": "Microsoft.AspNetCore.Http.CookieOptions" - }, - { - "Name": "name", - "Type": "System.String" - } - ], - "Visibility": "Public", - "GenericParameter": [] - } - ], - "GenericParameters": [] - }, - { - "Name": "Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy", - "Visibility": "Public", - "Kind": "Enumeration", - "Sealed": true, - "ImplementedInterfaces": [], - "Members": [ - { - "Kind": "Field", - "Name": "None", - "Parameters": [], - "GenericParameter": [], - "Literal": "0" - }, - { - "Kind": "Field", - "Name": "Always", - "Parameters": [], - "GenericParameter": [], - "Literal": "1" - } - ], - "GenericParameters": [] - } - ], - "SourceFilters": [] -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.CookiePolicy/baseline.netcore.json b/src/Microsoft.AspNetCore.CookiePolicy/baseline.netcore.json index 8eef347eb..01a16c57a 100644 --- a/src/Microsoft.AspNetCore.CookiePolicy/baseline.netcore.json +++ b/src/Microsoft.AspNetCore.CookiePolicy/baseline.netcore.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.AspNetCore.CookiePolicy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.AspNetCore.CookiePolicy, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.AspNetCore.Builder.CookiePolicyAppBuilderExtensions", @@ -53,6 +53,27 @@ "Kind": "Class", "ImplementedInterfaces": [], "Members": [ + { + "Kind": "Method", + "Name": "get_MinimumSameSitePolicy", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Http.SameSiteMode", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_MinimumSameSitePolicy", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Http.SameSiteMode" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Method", "Name": "get_HttpOnly", @@ -95,6 +116,48 @@ "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Method", + "Name": "get_ConsentCookie", + "Parameters": [], + "ReturnType": "Microsoft.AspNetCore.Http.CookieBuilder", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_ConsentCookie", + "Parameters": [ + { + "Name": "value", + "Type": "Microsoft.AspNetCore.Http.CookieBuilder" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_CheckConsentNeeded", + "Parameters": [], + "ReturnType": "System.Func", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_CheckConsentNeeded", + "Parameters": [ + { + "Name": "value", + "Type": "System.Func" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Method", "Name": "get_OnAppendCookie", @@ -211,6 +274,43 @@ "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Method", + "Name": "get_IsConsentNeeded", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_HasConsent", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_IssueCookie", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_IssueCookie", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Constructor", "Name": ".ctor", @@ -278,6 +378,26 @@ "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Constructor", + "Name": ".ctor", + "Parameters": [ + { + "Name": "next", + "Type": "Microsoft.AspNetCore.Http.RequestDelegate" + }, + { + "Name": "options", + "Type": "Microsoft.Extensions.Options.IOptions" + }, + { + "Name": "factory", + "Type": "Microsoft.Extensions.Logging.ILoggerFactory" + } + ], + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Constructor", "Name": ".ctor", @@ -340,6 +460,43 @@ "Visibility": "Public", "GenericParameter": [] }, + { + "Kind": "Method", + "Name": "get_IsConsentNeeded", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_HasConsent", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "get_IssueCookie", + "Parameters": [], + "ReturnType": "System.Boolean", + "Visibility": "Public", + "GenericParameter": [] + }, + { + "Kind": "Method", + "Name": "set_IssueCookie", + "Parameters": [ + { + "Name": "value", + "Type": "System.Boolean" + } + ], + "ReturnType": "System.Void", + "Visibility": "Public", + "GenericParameter": [] + }, { "Kind": "Constructor", "Name": ".ctor", @@ -387,6 +544,5 @@ ], "GenericParameters": [] } - ], - "SourceFilters": [] + ] } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.CookiePolicy/project.json b/src/Microsoft.AspNetCore.CookiePolicy/project.json deleted file mode 100644 index 95eede5db..000000000 --- a/src/Microsoft.AspNetCore.CookiePolicy/project.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "version": "1.2.0-*", - "description": "ASP.NET Core cookie policy classes to control the behavior of cookies.", - "packOptions": { - "repository": { - "type": "git", - "url": "git://github.com/aspnet/security" - }, - "tags": [ - "aspnetcore" - ] - }, - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "dependencies": { - "Microsoft.AspNetCore.Http": "1.2.0-*", - "Microsoft.Extensions.Options": "1.2.0-*", - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": {}, - "netstandard1.3": {} - } -} \ No newline at end of file diff --git a/src/Microsoft.Owin.Security.Interop/ChunkingCookieManager.cs b/src/Microsoft.Owin.Security.Interop/ChunkingCookieManager.cs index b323258d9..1ae4f00cd 100644 --- a/src/Microsoft.Owin.Security.Interop/ChunkingCookieManager.cs +++ b/src/Microsoft.Owin.Security.Interop/ChunkingCookieManager.cs @@ -25,7 +25,6 @@ public ChunkingCookieManager() // See http://browsercookielimits.x64.me/. // Leave at least 20 in case CookiePolicy tries to add 'secure' and/or 'httponly'. ChunkSize = 4070; - ThrowForPartialCookies = true; } /// diff --git a/src/Microsoft.Owin.Security.Interop/Microsoft.Owin.Security.Interop.csproj b/src/Microsoft.Owin.Security.Interop/Microsoft.Owin.Security.Interop.csproj new file mode 100644 index 000000000..a12bc6563 --- /dev/null +++ b/src/Microsoft.Owin.Security.Interop/Microsoft.Owin.Security.Interop.csproj @@ -0,0 +1,16 @@ + + + + A compatibility layer for sharing authentication tickets between Microsoft.Owin.Security and Microsoft.AspNetCore.Authentication. + net461 + $(NoWarn);CS1591 + true + aspnetcore;katana;owin;security + + + + + + + + diff --git a/src/Microsoft.Owin.Security.Interop/Microsoft.Owin.Security.Interop.xproj b/src/Microsoft.Owin.Security.Interop/Microsoft.Owin.Security.Interop.xproj deleted file mode 100644 index 052e99816..000000000 --- a/src/Microsoft.Owin.Security.Interop/Microsoft.Owin.Security.Interop.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - a7922dd8-09f1-43e4-938b-cc523ea08898 - .\obj - .\bin\ - - - 2.0 - - - \ No newline at end of file diff --git a/src/Microsoft.Owin.Security.Interop/Properties/AssemblyInfo.cs b/src/Microsoft.Owin.Security.Interop/Properties/AssemblyInfo.cs index 56cb77fdc..490fa7cb2 100644 --- a/src/Microsoft.Owin.Security.Interop/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Owin.Security.Interop/Properties/AssemblyInfo.cs @@ -1,15 +1,8 @@ // 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.Reflection; -using System.Resources; using System.Runtime.InteropServices; -[assembly: AssemblyMetadata("Serviceable", "True")] -[assembly: NeutralResourcesLanguage("en-us")] - // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("a7922dd8-09f1-43e4-938b-cc523ea08898")] -[assembly: AssemblyCompany("Microsoft Corporation.")] -[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] -[assembly: AssemblyProduct("Microsoft ASP.NET Core")] + diff --git a/src/Microsoft.Owin.Security.Interop/baseline.net45.json b/src/Microsoft.Owin.Security.Interop/baseline.netframework.json similarity index 99% rename from src/Microsoft.Owin.Security.Interop/baseline.net45.json rename to src/Microsoft.Owin.Security.Interop/baseline.netframework.json index 1fc242ec5..bfc0c0076 100644 --- a/src/Microsoft.Owin.Security.Interop/baseline.net45.json +++ b/src/Microsoft.Owin.Security.Interop/baseline.netframework.json @@ -1,5 +1,5 @@ { - "AssemblyIdentity": "Microsoft.Owin.Security.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", + "AssemblyIdentity": "Microsoft.Owin.Security.Interop, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "Types": [ { "Name": "Microsoft.Owin.Security.Interop.AspNetTicketDataFormat", @@ -368,6 +368,5 @@ ], "GenericParameters": [] } - ], - "SourceFilters": [] + ] } \ No newline at end of file diff --git a/src/Microsoft.Owin.Security.Interop/project.json b/src/Microsoft.Owin.Security.Interop/project.json deleted file mode 100644 index 54b4c97cc..000000000 --- a/src/Microsoft.Owin.Security.Interop/project.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "version": "1.2.0-*", - "buildOptions": { - "warningsAsErrors": true, - "keyFile": "../../tools/Key.snk", - "nowarn": [ - "CS1591" - ], - "xmlDoc": true - }, - "description": "A compatibility layer for sharing authentication tickets between Microsoft.Owin.Security and Microsoft.AspNetCore.Authentication.", - "packOptions": { - "tags": [ - "aspnetcore", - "katana", - "owin", - "security" - ] - }, - "dependencies": { - "Microsoft.AspNetCore.DataProtection.Extensions": "1.2.0-*", - "Microsoft.Owin.Security": "3.0.1", - "NETStandard.Library": "1.6.2-*" - }, - "frameworks": { - "net451": {} - } -} \ No newline at end of file diff --git a/test/Directory.Build.props b/test/Directory.Build.props new file mode 100644 index 000000000..c42d54465 --- /dev/null +++ b/test/Directory.Build.props @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Authentication.Test/AuthenticationHandlerFacts.cs b/test/Microsoft.AspNetCore.Authentication.Test/AuthenticationHandlerFacts.cs deleted file mode 100644 index fade43716..000000000 --- a/test/Microsoft.AspNetCore.Authentication.Test/AuthenticationHandlerFacts.cs +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.IO; -using System.Security.Claims; -using System.Text.Encodings.Web; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Http.Features.Authentication; -using Microsoft.Extensions.Logging; -using Xunit; - -namespace Microsoft.AspNetCore.Authentication -{ - public class AuthenticationHandlerFacts - { - [Fact] - public async Task ShouldHandleSchemeAreDeterminedOnlyByMatchingAuthenticationScheme() - { - var handler = await TestHandler.Create("Alpha"); - var passiveNoMatch = handler.ShouldHandleScheme("Beta", handleAutomatic: false); - - handler = await TestHandler.Create("Alpha"); - var passiveWithMatch = handler.ShouldHandleScheme("Alpha", handleAutomatic: false); - - Assert.False(passiveNoMatch); - Assert.True(passiveWithMatch); - } - - [Fact] - public async Task AutomaticHandlerInAutomaticModeHandlesEmptyChallenges() - { - var handler = await TestAutoHandler.Create("ignored", true); - Assert.True(handler.ShouldHandleScheme(AuthenticationManager.AutomaticScheme, handleAutomatic: true)); - } - - [Theory] - [InlineData(null)] - [InlineData("")] - [InlineData(" ")] - [InlineData("notmatched")] - public async Task AutomaticHandlerDoesNotHandleSchemes(string scheme) - { - var handler = await TestAutoHandler.Create("ignored", true); - Assert.False(handler.ShouldHandleScheme(scheme, handleAutomatic: true)); - } - - [Fact] - public async Task AutomaticHandlerShouldHandleSchemeWhenSchemeMatches() - { - var handler = await TestAutoHandler.Create("Alpha", true); - Assert.True(handler.ShouldHandleScheme("Alpha", handleAutomatic: true)); - } - - [Fact] - public async Task AutomaticHandlerShouldNotHandleChallengeWhenSchemesNotEmpty() - { - var handler = await TestAutoHandler.Create(null, true); - Assert.False(handler.ShouldHandleScheme("Alpha", handleAutomatic: true)); - } - - [Theory] - [InlineData("Alpha")] - [InlineData("Automatic")] - public async Task AuthHandlerAuthenticateCachesTicket(string scheme) - { - var handler = await CountHandler.Create(scheme); - var context = new AuthenticateContext(scheme); - await handler.AuthenticateAsync(context); - await handler.AuthenticateAsync(context); - Assert.Equal(1, handler.AuthCount); - } - - [Theory] - [InlineData("Alpha", false)] - [InlineData("Bravo", true)] - public async Task AuthHandlerChallengeCallsPriorHandlerIfNotHandled(string challenge, bool passedThrough) - { - var handler = await TestHandler.Create("Alpha"); - var previous = new PreviousHandler(); - - handler.PriorHandler = previous; - await handler.ChallengeAsync(new ChallengeContext(challenge)); - Assert.Equal(passedThrough, previous.ChallengeCalled); - } - - private class PreviousHandler : IAuthenticationHandler - { - public bool ChallengeCalled = false; - - public Task AuthenticateAsync(AuthenticateContext context) - { - throw new NotImplementedException(); - } - - public Task ChallengeAsync(ChallengeContext context) - { - ChallengeCalled = true; - return Task.FromResult(0); - } - - public void GetDescriptions(DescribeSchemesContext context) - { - throw new NotImplementedException(); - } - - public Task SignInAsync(SignInContext context) - { - throw new NotImplementedException(); - } - - public Task SignOutAsync(SignOutContext context) - { - throw new NotImplementedException(); - } - } - - private class CountOptions : AuthenticationOptions { } - - private class CountHandler : AuthenticationHandler - { - public int AuthCount = 0; - - private CountHandler() { } - - public static async Task Create(string scheme) - { - var handler = new CountHandler(); - var context = new DefaultHttpContext(); - context.Features.Set(new TestResponse()); - await handler.InitializeAsync( - new CountOptions(), context, - new LoggerFactory().CreateLogger("CountHandler"), - UrlEncoder.Default); - handler.Options.AuthenticationScheme = scheme; - handler.Options.AutomaticAuthenticate = true; - return handler; - } - - protected override Task HandleAuthenticateAsync() - { - AuthCount++; - return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(), new AuthenticationProperties(), "whatever"))); - } - - } - - private class TestHandler : AuthenticationHandler - { - private TestHandler() { } - - public AuthenticateResult Result = AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(), new AuthenticationProperties(), "whatever")); - - public static async Task Create(string scheme) - { - var handler = new TestHandler(); - var context = new DefaultHttpContext(); - context.Features.Set(new TestResponse()); - await handler.InitializeAsync( - new TestOptions(), context, - new LoggerFactory().CreateLogger("TestHandler"), - UrlEncoder.Default); - handler.Options.AuthenticationScheme = scheme; - return handler; - } - - protected override Task HandleAuthenticateAsync() - { - return Task.FromResult(Result); - } - } - - private class TestOptions : AuthenticationOptions { } - - private class TestAutoOptions : AuthenticationOptions - { - public TestAutoOptions() - { - AutomaticAuthenticate = true; - } - } - - private class TestAutoHandler : AuthenticationHandler - { - private TestAutoHandler() { } - - public static async Task Create(string scheme, bool auto) - { - var handler = new TestAutoHandler(); - var context = new DefaultHttpContext(); - context.Features.Set(new TestResponse()); - await handler.InitializeAsync( - new TestAutoOptions(), context, - new LoggerFactory().CreateLogger("TestAutoHandler"), - UrlEncoder.Default); - handler.Options.AuthenticationScheme = scheme; - handler.Options.AutomaticAuthenticate = auto; - return handler; - } - - protected override Task HandleAuthenticateAsync() - { - return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(), new AuthenticationProperties(), "whatever"))); - } - } - - private class TestResponse : IHttpResponseFeature - { - public Stream Body - { - get - { - throw new NotImplementedException(); - } - - set - { - throw new NotImplementedException(); - } - } - - public bool HasStarted - { - get - { - throw new NotImplementedException(); - } - } - - public IHeaderDictionary Headers - { - get - { - throw new NotImplementedException(); - } - - set - { - throw new NotImplementedException(); - } - } - - public string ReasonPhrase - { - get - { - throw new NotImplementedException(); - } - - set - { - throw new NotImplementedException(); - } - } - - public int StatusCode - { - get - { - throw new NotImplementedException(); - } - - set - { - } - } - - public void OnCompleted(Func callback, object state) - { - throw new NotImplementedException(); - } - - public void OnStarting(Func callback, object state) - { - } - } - } -} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/AuthenticationMiddlewareTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/AuthenticationMiddlewareTests.cs new file mode 100644 index 000000000..b09f13cab --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/AuthenticationMiddlewareTests.cs @@ -0,0 +1,196 @@ +// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Microsoft.AspNetCore.Authentication +{ + public class AuthenticationMiddlewareTests + { + [Fact] + public async Task OnlyInvokesCanHandleRequestHandlers() + { + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseAuthentication(); + }) + .ConfigureServices(services => services.AddAuthentication(o => + { + o.AddScheme("Skip", s => + { + s.HandlerType = typeof(SkipHandler); + }); + // Won't get hit since CanHandleRequests is false + o.AddScheme("throws", s => + { + s.HandlerType = typeof(ThrowsHandler); + }); + o.AddScheme("607", s => + { + s.HandlerType = typeof(SixOhSevenHandler); + }); + // Won't get run since 607 will finish + o.AddScheme("305", s => + { + s.HandlerType = typeof(ThreeOhFiveHandler); + }); + })); + var server = new TestServer(builder); + var response = await server.CreateClient().GetAsync("http://example.com/"); + Assert.Equal(607, (int)response.StatusCode); + } + + private class ThreeOhFiveHandler : StatusCodeHandler { + public ThreeOhFiveHandler() : base(305) { } + } + + private class SixOhSevenHandler : StatusCodeHandler + { + public SixOhSevenHandler() : base(607) { } + } + + private class SevenOhSevenHandler : StatusCodeHandler + { + public SevenOhSevenHandler() : base(707) { } + } + + private class StatusCodeHandler : IAuthenticationRequestHandler + { + private HttpContext _context; + private int _code; + + public StatusCodeHandler(int code) + { + _code = code; + } + + public Task AuthenticateAsync() + { + throw new NotImplementedException(); + } + + public Task ChallengeAsync(AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + + public Task ForbidAsync(AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + + public Task HandleRequestAsync() + { + _context.Response.StatusCode = _code; + return Task.FromResult(true); + } + + public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context) + { + _context = context; + return Task.FromResult(0); + } + + public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + + public Task SignOutAsync(AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + } + + private class ThrowsHandler : IAuthenticationHandler + { + private HttpContext _context; + + public Task AuthenticateAsync() + { + throw new NotImplementedException(); + } + + public Task ChallengeAsync(AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + + public Task ForbidAsync(AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + + public Task HandleRequestAsync() + { + throw new NotImplementedException(); + } + + public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context) + { + _context = context; + return Task.FromResult(0); + } + + public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + + public Task SignOutAsync(AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + } + + private class SkipHandler : IAuthenticationRequestHandler + { + private HttpContext _context; + + public Task AuthenticateAsync() + { + throw new NotImplementedException(); + } + + public Task ChallengeAsync(AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + + public Task ForbidAsync(AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + + public Task HandleRequestAsync() + { + return Task.FromResult(false); + } + + public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context) + { + _context = context; + return Task.FromResult(0); + } + + public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + + public Task SignOutAsync(AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + } + + } +} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/DataHandler/Base64UrlTextEncoderTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/Base64UrlTextEncoderTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Authentication.Test/DataHandler/Base64UrlTextEncoderTests.cs rename to test/Microsoft.AspNetCore.Authentication.Test/Base64UrlTextEncoderTests.cs diff --git a/test/Microsoft.AspNetCore.Authentication.Test/ClaimActionTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/ClaimActionTests.cs new file mode 100644 index 000000000..b083e9d76 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/ClaimActionTests.cs @@ -0,0 +1,112 @@ +// 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.IO; +using System.Linq; +using System.Security.Claims; +using Microsoft.AspNetCore.Testing.xunit; +using Xunit; +using Microsoft.AspNetCore.Authentication.OAuth.Claims; +using Newtonsoft.Json.Linq; + +namespace Microsoft.AspNetCore.Authentication +{ + public class ClaimActionTests + { + [Fact] + public void CanMapSingleValueUserDataToClaim() + { + var userData = new JObject + { + ["name"] = "test" + }; + + var identity = new ClaimsIdentity(); + + var action = new JsonKeyClaimAction("name", "name", "name"); + action.Run(userData, identity, "iss"); + + Assert.Equal("name", identity.FindFirst("name").Type); + Assert.Equal("test", identity.FindFirst("name").Value); + } + + [Fact] + public void CanMapArrayValueUserDataToClaims() + { + var userData = new JObject + { + ["role"] = new JArray { "role1", "role2" } + }; + + var identity = new ClaimsIdentity(); + + var action = new JsonKeyClaimAction("role", "role", "role"); + action.Run(userData, identity, "iss"); + + var roleClaims = identity.FindAll("role").ToList(); + Assert.Equal(2, roleClaims.Count); + Assert.Equal("role", roleClaims[0].Type); + Assert.Equal("role1", roleClaims[0].Value); + Assert.Equal("role", roleClaims[1].Type); + Assert.Equal("role2", roleClaims[1].Value); + } + + [Fact] + public void MapAllSucceeds() + { + var userData = new JObject + { + ["name0"] = "value0", + ["name1"] = "value1", + }; + + var identity = new ClaimsIdentity(); + var action = new MapAllClaimsAction(); + action.Run(userData, identity, "iss"); + + Assert.Equal("name0", identity.FindFirst("name0").Type); + Assert.Equal("value0", identity.FindFirst("name0").Value); + Assert.Equal("name1", identity.FindFirst("name1").Type); + Assert.Equal("value1", identity.FindFirst("name1").Value); + } + + [Fact] + public void MapAllAllowesDulicateKeysWithUniqueValues() + { + var userData = new JObject + { + ["name0"] = "value0", + ["name1"] = "value1", + }; + + var identity = new ClaimsIdentity(); + identity.AddClaim(new Claim("name0", "value2")); + identity.AddClaim(new Claim("name1", "value3")); + var action = new MapAllClaimsAction(); + action.Run(userData, identity, "iss"); + + Assert.Equal(2, identity.FindAll("name0").Count()); + Assert.Equal(2, identity.FindAll("name1").Count()); + } + + [Fact] + public void MapAllSkipsDuplicateValues() + { + var userData = new JObject + { + ["name0"] = "value0", + ["name1"] = "value1", + }; + + var identity = new ClaimsIdentity(); + identity.AddClaim(new Claim("name0", "value0")); + identity.AddClaim(new Claim("name1", "value1")); + var action = new MapAllClaimsAction(); + action.Run(userData, identity, "iss"); + + Assert.Single(identity.FindAll("name0")); + Assert.Single(identity.FindAll("name1")); + } + } +} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/Cookies/CookieMiddlewareTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/CookieTests.cs similarity index 60% rename from test/Microsoft.AspNetCore.Authentication.Test/Cookies/CookieMiddlewareTests.cs rename to test/Microsoft.AspNetCore.Authentication.Test/CookieTests.cs index e6f881fef..107fc5db1 100644 --- a/test/Microsoft.AspNetCore.Authentication.Test/Cookies/CookieMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Authentication.Test/CookieTests.cs @@ -14,20 +14,29 @@ using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.AspNetCore.TestHost; +using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.DependencyInjection; using Xunit; namespace Microsoft.AspNetCore.Authentication.Cookies { - public class CookieMiddlewareTests + public class CookieTests : SharedAuthenticationTests { + private TestClock _clock = new TestClock(); + + protected override string DefaultScheme => CookieAuthenticationDefaults.AuthenticationScheme; + protected override Type HandlerType => typeof(CookieAuthenticationHandler); + + protected override void RegisterAuth(AuthenticationBuilder services, Action configure) + { + services.AddCookie(configure); + } + [Fact] public async Task NormalRequestPassesThrough() { - var server = CreateServer(new CookieAuthenticationOptions()); + var server = CreateServer(s => { }); var response = await server.CreateClient().GetAsync("http://example.com/normal"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } @@ -35,90 +44,51 @@ public async Task NormalRequestPassesThrough() [Fact] public async Task AjaxLoginRedirectToReturnUrlTurnsInto200WithLocationHeader() { - var server = CreateServer(new CookieAuthenticationOptions - { - AutomaticChallenge = true, - LoginPath = "/login" - }); - - var transaction = await SendAsync(server, "http://example.com/protected?X-Requested-With=XMLHttpRequest"); + var server = CreateServer(o => o.LoginPath = "/login"); + var transaction = await SendAsync(server, "http://example.com/challenge?X-Requested-With=XMLHttpRequest"); Assert.Equal(HttpStatusCode.Unauthorized, transaction.Response.StatusCode); var responded = transaction.Response.Headers.GetValues("Location"); - Assert.Equal(1, responded.Count()); - Assert.True(responded.Single().StartsWith("http://example.com/login")); + Assert.Single(responded); + Assert.StartsWith("http://example.com/login", responded.Single()); } [Fact] public async Task AjaxForbidTurnsInto403WithLocationHeader() { - var server = CreateServer(new CookieAuthenticationOptions - { - AccessDeniedPath = "/denied" - }); - + var server = CreateServer(o => o.AccessDeniedPath = "/denied"); var transaction = await SendAsync(server, "http://example.com/forbid?X-Requested-With=XMLHttpRequest"); Assert.Equal(HttpStatusCode.Forbidden, transaction.Response.StatusCode); var responded = transaction.Response.Headers.GetValues("Location"); - Assert.Equal(1, responded.Count()); - Assert.True(responded.Single().StartsWith("http://example.com/denied")); + Assert.Single(responded); + Assert.StartsWith("http://example.com/denied", responded.Single()); } [Fact] public async Task AjaxLogoutRedirectToReturnUrlTurnsInto200WithLocationHeader() { - var server = CreateServer(new CookieAuthenticationOptions - { - LogoutPath = "/signout" - }); - + var server = CreateServer(o => o.LogoutPath = "/signout"); var transaction = await SendAsync(server, "http://example.com/signout?X-Requested-With=XMLHttpRequest&ReturnUrl=/"); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); var responded = transaction.Response.Headers.GetValues("Location"); - Assert.Equal(1, responded.Count()); - Assert.True(responded.Single().StartsWith("/")); + Assert.Single(responded); + Assert.StartsWith("/", responded.Single()); } [Fact] public async Task AjaxChallengeRedirectTurnsInto200WithLocationHeader() { - var server = CreateServer(new CookieAuthenticationOptions()); - + var server = CreateServer(s => { }); var transaction = await SendAsync(server, "http://example.com/challenge?X-Requested-With=XMLHttpRequest&ReturnUrl=/"); Assert.Equal(HttpStatusCode.Unauthorized, transaction.Response.StatusCode); var responded = transaction.Response.Headers.GetValues("Location"); - Assert.Equal(1, responded.Count()); - Assert.True(responded.Single().StartsWith("http://example.com/Account/Login")); - } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task ProtectedRequestShouldRedirectToLoginOnlyWhenAutomatic(bool auto) - { - var server = CreateServer(new CookieAuthenticationOptions - { - LoginPath = new PathString("/login"), - AutomaticChallenge = auto - }); - - var transaction = await SendAsync(server, "http://example.com/protected"); - - Assert.Equal(auto ? HttpStatusCode.Redirect : HttpStatusCode.Unauthorized, transaction.Response.StatusCode); - if (auto) - { - var location = transaction.Response.Headers.Location; - Assert.Equal("/login", location.LocalPath); - Assert.Equal("?ReturnUrl=%2Fprotected", location.Query); - } + Assert.Single(responded); + Assert.StartsWith("http://example.com/Account/Login", responded.Single()); } [Fact] public async Task ProtectedCustomRequestShouldRedirectToCustomRedirectUri() { - var server = CreateServer(new CookieAuthenticationOptions - { - AutomaticChallenge = true - }); + var server = CreateServer(s => { }); var transaction = await SendAsync(server, "http://example.com/protected/CustomRedirect"); @@ -129,31 +99,33 @@ public async Task ProtectedCustomRequestShouldRedirectToCustomRedirectUri() private Task SignInAsAlice(HttpContext context) { - return context.Authentication.SignInAsync("Cookies", - new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))), + var user = new ClaimsIdentity(new GenericIdentity("Alice", "Cookies")); + user.AddClaim(new Claim("marker", "true")); + return context.SignInAsync("Cookies", + new ClaimsPrincipal(user), new AuthenticationProperties()); } private Task SignInAsWrong(HttpContext context) { - return context.Authentication.SignInAsync("Oops", + return context.SignInAsync("Oops", new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))), new AuthenticationProperties()); } private Task SignOutAsWrong(HttpContext context) { - return context.Authentication.SignOutAsync("Oops"); + return context.SignOutAsync("Oops"); } [Fact] public async Task SignInCausesDefaultCookieToBeCreated() { - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServerWithServices(s => s.AddAuthentication().AddCookie(o => { - LoginPath = new PathString("/login"), - CookieName = "TestCookie" - }, SignInAsAlice); + o.LoginPath = new PathString("/login"); + o.Cookie.Name = "TestCookie"; + }), SignInAsAlice); var transaction = await SendAsync(server, "http://example.com/testpath"); @@ -161,18 +133,36 @@ public async Task SignInCausesDefaultCookieToBeCreated() Assert.StartsWith("TestCookie=", setCookie); Assert.Contains("; path=/", setCookie); Assert.Contains("; httponly", setCookie); + Assert.Contains("; samesite=", setCookie); Assert.DoesNotContain("; expires=", setCookie); Assert.DoesNotContain("; domain=", setCookie); Assert.DoesNotContain("; secure", setCookie); } + [Fact] + public async Task CookieExpirationOptionIsIgnored() + { + var server = CreateServerWithServices(s => s.AddAuthentication().AddCookie(o => + { + o.Cookie.Name = "TestCookie"; + // this is currently ignored. Users should set o.ExpireTimeSpan instead + o.Cookie.Expiration = TimeSpan.FromDays(10); + }), SignInAsAlice); + + var transaction = await SendAsync(server, "http://example.com/testpath"); + + var setCookie = transaction.SetCookie; + Assert.StartsWith("TestCookie=", setCookie); + Assert.DoesNotContain("; expires=", setCookie); + } + [Fact] public async Task SignInWrongAuthTypeThrows() { - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - LoginPath = new PathString("/login"), - CookieName = "TestCookie" + o.LoginPath = new PathString("/login"); + o.Cookie.Name = "TestCookie"; }, SignInAsWrong); await Assert.ThrowsAsync(async () => await SendAsync(server, "http://example.com/testpath")); @@ -181,10 +171,10 @@ public async Task SignInWrongAuthTypeThrows() [Fact] public async Task SignOutWrongAuthTypeThrows() { - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - LoginPath = new PathString("/login"), - CookieName = "TestCookie" + o.LoginPath = new PathString("/login"); + o.Cookie.Name = "TestCookie"; }, SignOutAsWrong); await Assert.ThrowsAsync(async () => await SendAsync(server, "http://example.com/testpath")); @@ -202,11 +192,11 @@ public async Task SecureSignInCausesSecureOnlyCookieByDefault( string requestUri, bool shouldBeSecureOnly) { - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - LoginPath = new PathString("/login"), - CookieName = "TestCookie", - CookieSecure = cookieSecurePolicy + o.LoginPath = new PathString("/login"); + o.Cookie.Name = "TestCookie"; + o.Cookie.SecurePolicy = cookieSecurePolicy; }, SignInAsAlice); var transaction = await SendAsync(server, requestUri); @@ -225,14 +215,15 @@ public async Task SecureSignInCausesSecureOnlyCookieByDefault( [Fact] public async Task CookieOptionsAlterSetCookieHeader() { - TestServer server1 = CreateServer(new CookieAuthenticationOptions + var server1 = CreateServer(o => { - CookieName = "TestCookie", - CookiePath = "/foo", - CookieDomain = "another.com", - CookieSecure = CookieSecurePolicy.Always, - CookieHttpOnly = true - }, SignInAsAlice, new Uri("http://example.com/base")); + o.Cookie.Name = "TestCookie"; + o.Cookie.Path = "/foo"; + o.Cookie.Domain = "another.com"; + o.Cookie.SecurePolicy = CookieSecurePolicy.Always; + o.Cookie.SameSite = SameSiteMode.None; + o.Cookie.HttpOnly = true; + }, SignInAsAlice, baseAddress: new Uri("http://example.com/base")); var transaction1 = await SendAsync(server1, "http://example.com/base/testpath"); @@ -242,14 +233,16 @@ public async Task CookieOptionsAlterSetCookieHeader() Assert.Contains(" path=/foo", setCookie1); Assert.Contains(" domain=another.com", setCookie1); Assert.Contains(" secure", setCookie1); + Assert.DoesNotContain(" samesite", setCookie1); Assert.Contains(" httponly", setCookie1); - var server2 = CreateServer(new CookieAuthenticationOptions + var server2 = CreateServer(o => { - CookieName = "SecondCookie", - CookieSecure = CookieSecurePolicy.None, - CookieHttpOnly = false - }, SignInAsAlice, new Uri("http://example.com/base")); + o.Cookie.Name = "SecondCookie"; + o.Cookie.SecurePolicy = CookieSecurePolicy.None; + o.Cookie.SameSite = SameSiteMode.Strict; + o.Cookie.HttpOnly = false; + }, SignInAsAlice, baseAddress: new Uri("http://example.com/base")); var transaction2 = await SendAsync(server2, "http://example.com/base/testpath"); @@ -257,6 +250,7 @@ public async Task CookieOptionsAlterSetCookieHeader() Assert.Contains("SecondCookie=", setCookie2); Assert.Contains(" path=/base", setCookie2); + Assert.Contains(" samesite=strict", setCookie2); Assert.DoesNotContain(" domain=", setCookie2); Assert.DoesNotContain(" secure", setCookie2); Assert.DoesNotContain(" httponly", setCookie2); @@ -265,11 +259,7 @@ public async Task CookieOptionsAlterSetCookieHeader() [Fact] public async Task CookieContainsIdentity() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions - { - SystemClock = clock - }, SignInAsAlice); + var server = CreateServer(o => { }, SignInAsAlice); var transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -281,30 +271,10 @@ public async Task CookieContainsIdentity() [Fact] public async Task CookieAppliesClaimsTransform() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions - { - SystemClock = clock - }, + var server = CreateServer(o => { }, SignInAsAlice, baseAddress: null, - claimsTransform: new ClaimsTransformationOptions - { - Transformer = new ClaimsTransformer - { - OnTransform = context => - { - if (!context.Principal.Identities.Any(i => i.AuthenticationType == "xform")) - { - // REVIEW: Xform runs twice, once on Authenticate, and then once from the middleware - var id = new ClaimsIdentity("xform"); - id.AddClaim(new Claim("xform", "yup")); - context.Principal.AddIdentity(id); - } - return Task.FromResult(context.Principal); - } - } - }); + claimsTransform: true); var transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -318,23 +288,21 @@ public async Task CookieAppliesClaimsTransform() [Fact] public async Task CookieStopsWorkingAfterExpiration() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - SlidingExpiration = false + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.SlidingExpiration = false; }, SignInAsAlice); var transaction1 = await SendAsync(server, "http://example.com/testpath"); var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); - clock.Add(TimeSpan.FromMinutes(7)); + _clock.Add(TimeSpan.FromMinutes(7)); var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); - clock.Add(TimeSpan.FromMinutes(7)); + _clock.Add(TimeSpan.FromMinutes(7)); var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); @@ -349,27 +317,25 @@ public async Task CookieStopsWorkingAfterExpiration() [Fact] public async Task CookieExpirationCanBeOverridenInSignin() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - SlidingExpiration = false + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.SlidingExpiration = false; }, context => - context.Authentication.SignInAsync("Cookies", + context.SignInAsync("Cookies", new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))), - new AuthenticationProperties() { ExpiresUtc = clock.UtcNow.Add(TimeSpan.FromMinutes(5)) })); + new AuthenticationProperties() { ExpiresUtc = _clock.UtcNow.Add(TimeSpan.FromMinutes(5)) })); var transaction1 = await SendAsync(server, "http://example.com/testpath"); var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); - clock.Add(TimeSpan.FromMinutes(3)); + _clock.Add(TimeSpan.FromMinutes(3)); var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); - clock.Add(TimeSpan.FromMinutes(3)); + _clock.Add(TimeSpan.FromMinutes(3)); var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); @@ -384,27 +350,25 @@ public async Task CookieExpirationCanBeOverridenInSignin() [Fact] public async Task ExpiredCookieWithValidatorStillExpired() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - Events = new CookieAuthenticationEvents + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.Events = new CookieAuthenticationEvents { OnValidatePrincipal = ctx => { ctx.ShouldRenew = true; return Task.FromResult(0); } - } + }; }, context => - context.Authentication.SignInAsync("Cookies", + context.SignInAsync("Cookies", new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))))); var transaction1 = await SendAsync(server, "http://example.com/testpath"); - clock.Add(TimeSpan.FromMinutes(11)); + _clock.Add(TimeSpan.FromMinutes(11)); var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); Assert.Null(transaction2.SetCookie); @@ -414,24 +378,22 @@ public async Task ExpiredCookieWithValidatorStillExpired() [Fact] public async Task CookieCanBeRejectedAndSignedOutByValidator() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - SlidingExpiration = false, - Events = new CookieAuthenticationEvents + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.SlidingExpiration = false; + o.Events = new CookieAuthenticationEvents { OnValidatePrincipal = ctx => { ctx.RejectPrincipal(); - ctx.HttpContext.Authentication.SignOutAsync("Cookies"); + ctx.HttpContext.SignOutAsync("Cookies"); return Task.FromResult(0); } - } + }; }, context => - context.Authentication.SignInAsync("Cookies", + context.SignInAsync("Cookies", new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))))); var transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -441,26 +403,60 @@ public async Task CookieCanBeRejectedAndSignedOutByValidator() Assert.Null(FindClaimValue(transaction2, ClaimTypes.Name)); } + [Fact] + public async Task CookieNotRenewedAfterSignOut() + { + var server = CreateServer(o => + { + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.SlidingExpiration = false; + o.Events = new CookieAuthenticationEvents + { + OnValidatePrincipal = ctx => + { + ctx.ShouldRenew = true; + return Task.FromResult(0); + } + }; + }, + context => + context.SignInAsync("Cookies", + new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))))); + + var transaction1 = await SendAsync(server, "http://example.com/testpath"); + + // renews on every request + var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); + Assert.NotNull(transaction2.SetCookie); + Assert.Equal("Alice", FindClaimValue(transaction2, ClaimTypes.Name)); + + var transaction3 = await server.SendAsync("http://example.com/normal", transaction1.CookieNameValue); + Assert.NotNull(transaction3.SetCookie[0]); + + // signout wins over renew + var transaction4 = await server.SendAsync("http://example.com/signout", transaction3.SetCookie[0]); + Assert.Single(transaction4.SetCookie); + Assert.Contains(".AspNetCore.Cookies=; expires=", transaction4.SetCookie[0]); + } + [Fact] public async Task CookieCanBeRenewedByValidator() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - SlidingExpiration = false, - Events = new CookieAuthenticationEvents + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.SlidingExpiration = false; + o.Events = new CookieAuthenticationEvents { OnValidatePrincipal = ctx => { ctx.ShouldRenew = true; return Task.FromResult(0); } - } + }; }, context => - context.Authentication.SignInAsync("Cookies", + context.SignInAsync("Cookies", new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))))); var transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -469,44 +465,116 @@ public async Task CookieCanBeRenewedByValidator() Assert.NotNull(transaction2.SetCookie); Assert.Equal("Alice", FindClaimValue(transaction2, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(5)); + _clock.Add(TimeSpan.FromMinutes(5)); var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction2.CookieNameValue); Assert.NotNull(transaction3.SetCookie); Assert.Equal("Alice", FindClaimValue(transaction3, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(6)); + _clock.Add(TimeSpan.FromMinutes(6)); var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); Assert.Null(transaction4.SetCookie); Assert.Null(FindClaimValue(transaction4, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(5)); + _clock.Add(TimeSpan.FromMinutes(5)); var transaction5 = await SendAsync(server, "http://example.com/me/Cookies", transaction2.CookieNameValue); Assert.Null(transaction5.SetCookie); Assert.Null(FindClaimValue(transaction5, ClaimTypes.Name)); } + [Fact] + public async Task CookieCanBeReplacedByValidator() + { + var server = CreateServer(o => + { + o.Events = new CookieAuthenticationEvents + { + OnValidatePrincipal = ctx => + { + ctx.ShouldRenew = true; + ctx.ReplacePrincipal(new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice2", "Cookies2")))); + return Task.FromResult(0); + } + }; + }, + context => + context.SignInAsync("Cookies", + new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))))); + + var transaction1 = await SendAsync(server, "http://example.com/testpath"); + + var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); + Assert.NotNull(transaction2.SetCookie); + Assert.Equal("Alice2", FindClaimValue(transaction2, ClaimTypes.Name)); + } + + [Fact] + public async Task CookieCanBeUpdatedByValidatorDuringRefresh() + { + var replace = false; + var server = CreateServer(o => + { + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.Events = new CookieAuthenticationEvents + { + OnValidatePrincipal = ctx => + { + if (replace) + { + ctx.ShouldRenew = true; + ctx.ReplacePrincipal(new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice2", "Cookies2")))); + ctx.Properties.Items["updated"] = "yes"; + } + return Task.FromResult(0); + } + }; + }, + context => + context.SignInAsync("Cookies", + new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))))); + + var transaction1 = await SendAsync(server, "http://example.com/testpath"); + + var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); + Assert.Equal("Alice", FindClaimValue(transaction2, ClaimTypes.Name)); + + var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); + Assert.Equal("Alice", FindClaimValue(transaction2, ClaimTypes.Name)); + Assert.Null(FindPropertiesValue(transaction3, "updated")); + + replace = true; + + var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); + Assert.NotNull(transaction4.SetCookie); + Assert.Equal("Alice2", FindClaimValue(transaction4, ClaimTypes.Name)); + Assert.Equal("yes", FindPropertiesValue(transaction4, "updated")); + + replace = false; + + var transaction5 = await SendAsync(server, "http://example.com/me/Cookies", transaction4.CookieNameValue); + Assert.Equal("Alice2", FindClaimValue(transaction5, ClaimTypes.Name)); + Assert.Equal("yes", FindPropertiesValue(transaction4, "updated")); + } + [Fact] public async Task CookieCanBeRenewedByValidatorWithSlidingExpiry() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - Events = new CookieAuthenticationEvents + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.Events = new CookieAuthenticationEvents { OnValidatePrincipal = ctx => { ctx.ShouldRenew = true; return Task.FromResult(0); } - } + }; }, context => - context.Authentication.SignInAsync("Cookies", + context.SignInAsync("Cookies", new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))))); var transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -515,45 +583,98 @@ public async Task CookieCanBeRenewedByValidatorWithSlidingExpiry() Assert.NotNull(transaction2.SetCookie); Assert.Equal("Alice", FindClaimValue(transaction2, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(5)); + _clock.Add(TimeSpan.FromMinutes(5)); var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction2.CookieNameValue); Assert.NotNull(transaction3.SetCookie); Assert.Equal("Alice", FindClaimValue(transaction3, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(6)); + _clock.Add(TimeSpan.FromMinutes(6)); var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction3.CookieNameValue); Assert.NotNull(transaction4.SetCookie); Assert.Equal("Alice", FindClaimValue(transaction4, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(11)); + _clock.Add(TimeSpan.FromMinutes(11)); var transaction5 = await SendAsync(server, "http://example.com/me/Cookies", transaction4.CookieNameValue); Assert.Null(transaction5.SetCookie); Assert.Null(FindClaimValue(transaction5, ClaimTypes.Name)); } + [Fact] + public async Task CookieCanBeRenewedByValidatorWithModifiedProperties() + { + var server = CreateServer(o => + { + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.Events = new CookieAuthenticationEvents + { + OnValidatePrincipal = ctx => + { + ctx.ShouldRenew = true; + var id = ctx.Principal.Identities.First(); + var claim = id.FindFirst("counter"); + if (claim == null) + { + id.AddClaim(new Claim("counter", "1")); + } + else + { + id.RemoveClaim(claim); + id.AddClaim(new Claim("counter", claim.Value + "1")); + } + return Task.FromResult(0); + } + }; + }, + context => + context.SignInAsync("Cookies", + new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))))); + + var transaction1 = await SendAsync(server, "http://example.com/testpath"); + + var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); + Assert.NotNull(transaction2.SetCookie); + Assert.Equal("1", FindClaimValue(transaction2, "counter")); + + _clock.Add(TimeSpan.FromMinutes(5)); + + var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction2.CookieNameValue); + Assert.NotNull(transaction3.SetCookie); + Assert.Equal("11", FindClaimValue(transaction3, "counter")); + + _clock.Add(TimeSpan.FromMinutes(6)); + + var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction3.CookieNameValue); + Assert.NotNull(transaction4.SetCookie); + Assert.Equal("111", FindClaimValue(transaction4, "counter")); + + _clock.Add(TimeSpan.FromMinutes(11)); + + var transaction5 = await SendAsync(server, "http://example.com/me/Cookies", transaction4.CookieNameValue); + Assert.Null(transaction5.SetCookie); + Assert.Null(FindClaimValue(transaction5, "counter")); + } + [Fact] public async Task CookieValidatorOnlyCalledOnce() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - SlidingExpiration = false, - Events = new CookieAuthenticationEvents + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.SlidingExpiration = false; + o.Events = new CookieAuthenticationEvents { OnValidatePrincipal = ctx => { ctx.ShouldRenew = true; return Task.FromResult(0); } - } + }; }, context => - context.Authentication.SignInAsync("Cookies", + context.SignInAsync("Cookies", new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))))); var transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -562,19 +683,19 @@ public async Task CookieValidatorOnlyCalledOnce() Assert.NotNull(transaction2.SetCookie); Assert.Equal("Alice", FindClaimValue(transaction2, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(5)); + _clock.Add(TimeSpan.FromMinutes(5)); var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction2.CookieNameValue); Assert.NotNull(transaction3.SetCookie); Assert.Equal("Alice", FindClaimValue(transaction3, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(6)); + _clock.Add(TimeSpan.FromMinutes(6)); var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); Assert.Null(transaction4.SetCookie); Assert.Null(FindClaimValue(transaction4, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(5)); + _clock.Add(TimeSpan.FromMinutes(5)); var transaction5 = await SendAsync(server, "http://example.com/me/Cookies", transaction2.CookieNameValue); Assert.Null(transaction5.SetCookie); @@ -586,15 +707,13 @@ public async Task CookieValidatorOnlyCalledOnce() [InlineData(false)] public async Task ShouldRenewUpdatesIssuedExpiredUtc(bool sliding) { - var clock = new TestClock(); DateTimeOffset? lastValidateIssuedDate = null; DateTimeOffset? lastExpiresDate = null; - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - SlidingExpiration = sliding, - Events = new CookieAuthenticationEvents + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.SlidingExpiration = sliding; + o.Events = new CookieAuthenticationEvents { OnValidatePrincipal = ctx => { @@ -603,10 +722,10 @@ public async Task ShouldRenewUpdatesIssuedExpiredUtc(bool sliding) ctx.ShouldRenew = true; return Task.FromResult(0); } - } + }; }, context => - context.Authentication.SignInAsync("Cookies", + context.SignInAsync("Cookies", new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))))); var transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -621,13 +740,13 @@ public async Task ShouldRenewUpdatesIssuedExpiredUtc(bool sliding) var firstIssueDate = lastValidateIssuedDate; var firstExpiresDate = lastExpiresDate; - clock.Add(TimeSpan.FromMinutes(1)); + _clock.Add(TimeSpan.FromMinutes(1)); var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction2.CookieNameValue); Assert.NotNull(transaction3.SetCookie); Assert.Equal("Alice", FindClaimValue(transaction3, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(2)); + _clock.Add(TimeSpan.FromMinutes(2)); var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction3.CookieNameValue); Assert.NotNull(transaction4.SetCookie); @@ -640,21 +759,20 @@ public async Task ShouldRenewUpdatesIssuedExpiredUtc(bool sliding) [Fact] public async Task CookieExpirationCanBeOverridenInEvent() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - SlidingExpiration = false, - Events = new CookieAuthenticationEvents() + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.SlidingExpiration = false; + o.Events = new CookieAuthenticationEvents() { OnSigningIn = context => { - context.Properties.ExpiresUtc = clock.UtcNow.Add(TimeSpan.FromMinutes(5)); + context.Properties.ExpiresUtc = _clock.UtcNow.Add(TimeSpan.FromMinutes(5)); return Task.FromResult(0); } - } - }, SignInAsAlice); + }; + }, + SignInAsAlice); var transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -662,13 +780,13 @@ public async Task CookieExpirationCanBeOverridenInEvent() Assert.Null(transaction2.SetCookie); Assert.Equal("Alice", FindClaimValue(transaction2, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(3)); + _clock.Add(TimeSpan.FromMinutes(3)); var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); Assert.Null(transaction3.SetCookie); Assert.Equal("Alice", FindClaimValue(transaction3, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(3)); + _clock.Add(TimeSpan.FromMinutes(3)); var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); Assert.Null(transaction4.SetCookie); @@ -678,13 +796,12 @@ public async Task CookieExpirationCanBeOverridenInEvent() [Fact] public async Task CookieIsRenewedWithSlidingExpiration() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - SlidingExpiration = true - }, SignInAsAlice); + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.SlidingExpiration = true; + }, + SignInAsAlice); var transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -692,20 +809,20 @@ public async Task CookieIsRenewedWithSlidingExpiration() Assert.Null(transaction2.SetCookie); Assert.Equal("Alice", FindClaimValue(transaction2, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(4)); + _clock.Add(TimeSpan.FromMinutes(4)); var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); Assert.Null(transaction3.SetCookie); Assert.Equal("Alice", FindClaimValue(transaction3, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(4)); + _clock.Add(TimeSpan.FromMinutes(4)); // transaction4 should arrive with a new SetCookie value var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); Assert.NotNull(transaction4.SetCookie); Assert.Equal("Alice", FindClaimValue(transaction4, ClaimTypes.Name)); - clock.Add(TimeSpan.FromMinutes(4)); + _clock.Add(TimeSpan.FromMinutes(4)); var transaction5 = await SendAsync(server, "http://example.com/me/Cookies", transaction4.CookieNameValue); Assert.Null(transaction5.SetCookie); @@ -713,58 +830,70 @@ public async Task CookieIsRenewedWithSlidingExpiration() } [Fact] - public async Task CookieUsesPathBaseByDefault() + public async Task CookieIsRenewedWithSlidingExpirationWithoutTransformations() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions(), - context => + var server = CreateServer(o => { - Assert.Equal(new PathString("/base"), context.Request.PathBase); - return context.Authentication.SignInAsync("Cookies", - new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies")))); + o.ExpireTimeSpan = TimeSpan.FromMinutes(10); + o.SlidingExpiration = true; + o.Events.OnValidatePrincipal = c => + { + // https://github.com/aspnet/Security/issues/1607 + // On sliding refresh the transformed principal should not be serialized into the cookie, only the original principal. + Assert.Single(c.Principal.Identities); + Assert.True(c.Principal.Identities.First().HasClaim("marker", "true")); + return Task.CompletedTask; + }; }, - new Uri("http://example.com/base")); + SignInAsAlice, + claimsTransform: true); - var transaction1 = await SendAsync(server, "http://example.com/base/testpath"); - Assert.True(transaction1.SetCookie.Contains("path=/base")); - } + var transaction1 = await SendAsync(server, "http://example.com/testpath"); - [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task CookieTurnsChallengeIntoForbidWithCookie(bool automatic) - { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions - { - AutomaticAuthenticate = automatic, - SystemClock = clock - }, - SignInAsAlice); + var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); + Assert.Null(transaction2.SetCookie); + Assert.Equal("Alice", FindClaimValue(transaction2, ClaimTypes.Name)); - var transaction1 = await SendAsync(server, "http://example.com/testpath"); + _clock.Add(TimeSpan.FromMinutes(4)); - var url = "http://example.com/challenge"; - var transaction2 = await SendAsync(server, url, transaction1.CookieNameValue); + var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); + Assert.Null(transaction3.SetCookie); + Assert.Equal("Alice", FindClaimValue(transaction3, ClaimTypes.Name)); - Assert.Equal(HttpStatusCode.Redirect, transaction2.Response.StatusCode); - var location = transaction2.Response.Headers.Location; - Assert.Equal("/Account/AccessDenied", location.LocalPath); - Assert.Equal("?ReturnUrl=%2Fchallenge", location.Query); + _clock.Add(TimeSpan.FromMinutes(4)); + + // transaction4 should arrive with a new SetCookie value + var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); + Assert.NotNull(transaction4.SetCookie); + Assert.Equal("Alice", FindClaimValue(transaction4, ClaimTypes.Name)); + + _clock.Add(TimeSpan.FromMinutes(4)); + + var transaction5 = await SendAsync(server, "http://example.com/me/Cookies", transaction4.CookieNameValue); + Assert.Null(transaction5.SetCookie); + Assert.Equal("Alice", FindClaimValue(transaction5, ClaimTypes.Name)); } - [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task CookieChallengeRedirectsToLoginWithoutCookie(bool automatic) + [Fact] + public async Task CookieUsesPathBaseByDefault() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { }, + context => { - AutomaticAuthenticate = automatic, - SystemClock = clock + Assert.Equal(new PathString("/base"), context.Request.PathBase); + return context.SignInAsync("Cookies", + new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies")))); }, - SignInAsAlice); + new Uri("http://example.com/base")); + + var transaction1 = await SendAsync(server, "http://example.com/base/testpath"); + Assert.Contains("path=/base", transaction1.SetCookie); + } + + [Fact] + public async Task CookieChallengeRedirectsToLoginWithoutCookie() + { + var server = CreateServer(o => { }, SignInAsAlice); var url = "http://example.com/challenge"; var transaction = await SendAsync(server, url); @@ -774,18 +903,10 @@ public async Task CookieChallengeRedirectsToLoginWithoutCookie(bool automatic) Assert.Equal("/Account/Login", location.LocalPath); } - [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task CookieForbidRedirectsWithoutCookie(bool automatic) + [Fact] + public async Task CookieForbidRedirectsWithoutCookie() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions - { - AutomaticAuthenticate = automatic, - SystemClock = clock - }, - SignInAsAlice); + var server = CreateServer(o => { }, SignInAsAlice); var url = "http://example.com/forbid"; var transaction = await SendAsync(server, url); @@ -795,35 +916,12 @@ public async Task CookieForbidRedirectsWithoutCookie(bool automatic) Assert.Equal("/Account/AccessDenied", location.LocalPath); } - [Fact] - public async Task CookieTurns401ToAccessDeniedWhenSetWithCookie() - { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions - { - SystemClock = clock, - AccessDeniedPath = new PathString("/accessdenied") - }, - SignInAsAlice); - - var transaction1 = await SendAsync(server, "http://example.com/testpath"); - - var transaction2 = await SendAsync(server, "http://example.com/challenge", transaction1.CookieNameValue); - - Assert.Equal(HttpStatusCode.Redirect, transaction2.Response.StatusCode); - - var location = transaction2.Response.Headers.Location; - Assert.Equal("/accessdenied", location.LocalPath); - } - [Fact] public async Task CookieChallengeRedirectsWithLoginPath() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - SystemClock = clock, - LoginPath = new PathString("/page") + o.LoginPath = new PathString("/page"); }); var transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -836,11 +934,9 @@ public async Task CookieChallengeRedirectsWithLoginPath() [Fact] public async Task CookieChallengeWithUnauthorizedRedirectsToLoginIfNotAuthenticated() { - var clock = new TestClock(); - var server = CreateServer(new CookieAuthenticationOptions + var server = CreateServer(o => { - SystemClock = clock, - LoginPath = new PathString("/page") + o.LoginPath = new PathString("/page"); }); var transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -850,19 +946,21 @@ public async Task CookieChallengeWithUnauthorizedRedirectsToLoginIfNotAuthentica Assert.Equal(HttpStatusCode.Redirect, transaction2.Response.StatusCode); } - [Fact] - public async Task MapWillNotAffectChallenge() + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task MapWillAffectChallengeOnlyWithUseAuth(bool useAuth) { var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new CookieAuthenticationOptions + if (useAuth) { - LoginPath = new PathString("/page") - }); - app.Map("/login", signoutApp => signoutApp.Run(context => context.Authentication.ChallengeAsync("Cookies", new AuthenticationProperties() { RedirectUri = "/" }))); + app.UseAuthentication(); + } + app.Map("/login", signoutApp => signoutApp.Run(context => context.ChallengeAsync("Cookies", new AuthenticationProperties() { RedirectUri = "/" }))); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(s => s.AddAuthentication().AddCookie(o => o.LoginPath = new PathString("/page"))); var server = new TestServer(builder); var transaction = await server.SendAsync("http://example.com/login"); @@ -870,23 +968,30 @@ public async Task MapWillNotAffectChallenge() Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); var location = transaction.Response.Headers.Location; - Assert.Equal("/page", location.LocalPath); + if (useAuth) + { + Assert.Equal("/page", location.LocalPath); + } + else + { + Assert.Equal("/login/page", location.LocalPath); + } Assert.Equal("?ReturnUrl=%2F", location.Query); } - [Fact] + [ConditionalFact(Skip = "Revisit, exception no longer thrown")] public async Task ChallengeDoesNotSet401OnUnauthorized() { var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(); + app.UseAuthentication(); app.Run(async context => { - await Assert.ThrowsAsync(() => context.Authentication.ChallengeAsync()); + await Assert.ThrowsAsync(() => context.ChallengeAsync(CookieAuthenticationDefaults.AuthenticationScheme)); }); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie()); var server = new TestServer(builder); var transaction = await server.SendAsync("http://example.com"); @@ -894,25 +999,49 @@ public async Task ChallengeDoesNotSet401OnUnauthorized() } [Fact] - public async Task UseCookieWithInstanceDoesntUseSharedOptions() + public async Task CanConfigureDefaultCookieInstance() { var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - CookieName = "One" - }); - app.UseCookieAuthentication(); - app.Run(context => context.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity()))); + app.UseAuthentication(); + app.Run(context => context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity()))); + }) + .ConfigureServices(services => + { + services.AddAuthentication().AddCookie(); + services.Configure(CookieAuthenticationDefaults.AuthenticationScheme, + o => o.Cookie.Name = "One"); + }); + var server = new TestServer(builder); + + var transaction = await server.SendAsync("http://example.com"); + + Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); + Assert.StartsWith("One=", transaction.SetCookie[0]); + } + + [Fact] + public async Task CanConfigureNamedCookieInstance() + { + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseAuthentication(); + app.Run(context => context.SignInAsync("Cookie1", new ClaimsPrincipal(new ClaimsIdentity()))); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => + { + services.AddAuthentication().AddCookie("Cookie1"); + services.Configure("Cookie1", + o => o.Cookie.Name = "One"); + }); var server = new TestServer(builder); var transaction = await server.SendAsync("http://example.com"); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); - Assert.True(transaction.SetCookie[0].StartsWith(".AspNetCore.Cookies=")); + Assert.StartsWith("One=", transaction.SetCookie[0]); } [Fact] @@ -921,14 +1050,11 @@ public async Task MapWithSignInOnlyRedirectToReturnUrlOnLoginPath() var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - LoginPath = new PathString("/login") - }); - app.Map("/notlogin", signoutApp => signoutApp.Run(context => context.Authentication.SignInAsync("Cookies", + app.UseAuthentication(); + app.Map("/notlogin", signoutApp => signoutApp.Run(context => context.SignInAsync("Cookies", new ClaimsPrincipal()))); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie(o => o.LoginPath = new PathString("/login"))); var server = new TestServer(builder); var transaction = await server.SendAsync("http://example.com/notlogin?ReturnUrl=%2Fpage"); @@ -942,14 +1068,11 @@ public async Task MapWillNotAffectSignInRedirectToReturnUrl() var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - LoginPath = new PathString("/login") - }); - app.Map("/login", signoutApp => signoutApp.Run(context => context.Authentication.SignInAsync("Cookies", - new ClaimsPrincipal()))); + app.UseAuthentication(); + app.Map("/login", signoutApp => signoutApp.Run(context => context.SignInAsync("Cookies", new ClaimsPrincipal()))); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie(o => o.LoginPath = new PathString("/login"))); + var server = new TestServer(builder); var transaction = await server.SendAsync("http://example.com/login?ReturnUrl=%2Fpage"); @@ -967,13 +1090,10 @@ public async Task MapWithSignOutOnlyRedirectToReturnUrlOnLogoutPath() var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - LogoutPath = new PathString("/logout") - }); - app.Map("/notlogout", signoutApp => signoutApp.Run(context => context.Authentication.SignOutAsync("Cookies"))); + app.UseAuthentication(); + app.Map("/notlogout", signoutApp => signoutApp.Run(context => context.SignOutAsync("Cookies"))); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie(o => o.LogoutPath = new PathString("/logout"))); var server = new TestServer(builder); var transaction = await server.SendAsync("http://example.com/notlogout?ReturnUrl=%2Fpage"); @@ -987,13 +1107,10 @@ public async Task MapWillNotAffectSignOutRedirectToReturnUrl() var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - LogoutPath = new PathString("/logout") - }); - app.Map("/logout", signoutApp => signoutApp.Run(context => context.Authentication.SignOutAsync("Cookies"))); + app.UseAuthentication(); + app.Map("/logout", signoutApp => signoutApp.Run(context => context.SignOutAsync("Cookies"))); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie(o => o.LogoutPath = new PathString("/logout"))); var server = new TestServer(builder); var transaction = await server.SendAsync("http://example.com/logout?ReturnUrl=%2Fpage"); @@ -1011,13 +1128,10 @@ public async Task MapWillNotAffectAccessDenied() var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - AccessDeniedPath = new PathString("/denied") - }); - app.Map("/forbid", signoutApp => signoutApp.Run(context => context.Authentication.ForbidAsync("Cookies"))); + app.UseAuthentication(); + app.Map("/forbid", signoutApp => signoutApp.Run(context => context.ForbidAsync("Cookies"))); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie(o => o.AccessDeniedPath = new PathString("/denied"))); var server = new TestServer(builder); var transaction = await server.SendAsync("http://example.com/forbid"); @@ -1034,13 +1148,10 @@ public async Task NestedMapWillNotAffectLogin() .Configure(app => app.Map("/base", map => { - map.UseCookieAuthentication(new CookieAuthenticationOptions - { - LoginPath = new PathString("/page") - }); - map.Map("/login", signoutApp => signoutApp.Run(context => context.Authentication.ChallengeAsync("Cookies", new AuthenticationProperties() { RedirectUri = "/" }))); + map.UseAuthentication(); + map.Map("/login", signoutApp => signoutApp.Run(context => context.ChallengeAsync("Cookies", new AuthenticationProperties() { RedirectUri = "/" }))); })) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie(o => o.LoginPath = new PathString("/page"))); var server = new TestServer(builder); var transaction = await server.SendAsync("http://example.com/base/login"); @@ -1056,19 +1167,17 @@ public async Task NestedMapWillNotAffectLogin() [InlineData("http://example.com/redirect_to")] public async Task RedirectUriIsHoneredAfterSignin(string redirectUrl) { - var options = new CookieAuthenticationOptions + var server = CreateServer(o => { - LoginPath = "/testpath", - CookieName = "TestCookie" - }; - - var server = CreateServer(options, async context => - { - await context.Authentication.SignInAsync( + o.LoginPath = "/testpath"; + o.Cookie.Name = "TestCookie"; + }, + async context => + await context.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", CookieAuthenticationDefaults.AuthenticationScheme))), - new AuthenticationProperties { RedirectUri = redirectUrl }); - }); + new AuthenticationProperties { RedirectUri = redirectUrl }) + ); var transaction = await SendAsync(server, "http://example.com/testpath"); Assert.NotEmpty(transaction.SetCookie); @@ -1079,16 +1188,15 @@ await context.Authentication.SignInAsync( [Fact] public async Task RedirectUriInQueryIsHoneredAfterSignin() { - var options = new CookieAuthenticationOptions + var server = CreateServer(o => { - LoginPath = "/testpath", - ReturnUrlParameter = "return", - CookieName = "TestCookie" - }; - - var server = CreateServer(options, async context => + o.LoginPath = "/testpath"; + o.ReturnUrlParameter = "return"; + o.Cookie.Name = "TestCookie"; + }, + async context => { - await context.Authentication.SignInAsync( + await context.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", CookieAuthenticationDefaults.AuthenticationScheme)))); }); @@ -1102,16 +1210,15 @@ await context.Authentication.SignInAsync( [Fact] public async Task AbsoluteRedirectUriInQueryStringIsRejected() { - var options = new CookieAuthenticationOptions + var server = CreateServer(o => { - LoginPath = "/testpath", - ReturnUrlParameter = "return", - CookieName = "TestCookie" - }; - - var server = CreateServer(options, async context => + o.LoginPath = "/testpath"; + o.ReturnUrlParameter = "return"; + o.Cookie.Name = "TestCookie"; + }, + async context => { - await context.Authentication.SignInAsync( + await context.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", CookieAuthenticationDefaults.AuthenticationScheme)))); }); @@ -1124,16 +1231,15 @@ await context.Authentication.SignInAsync( [Fact] public async Task EnsurePrecedenceOfRedirectUriAfterSignin() { - var options = new CookieAuthenticationOptions + var server = CreateServer(o => { - LoginPath = "/testpath", - ReturnUrlParameter = "return", - CookieName = "TestCookie" - }; - - var server = CreateServer(options, async context => + o.LoginPath = "/testpath"; + o.ReturnUrlParameter = "return"; + o.Cookie.Name = "TestCookie"; + }, + async context => { - await context.Authentication.SignInAsync( + await context.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", CookieAuthenticationDefaults.AuthenticationScheme))), new AuthenticationProperties { RedirectUri = "/redirect_test" }); @@ -1152,13 +1258,10 @@ public async Task NestedMapWillNotAffectAccessDenied() .Configure(app => app.Map("/base", map => { - map.UseCookieAuthentication(new CookieAuthenticationOptions - { - AccessDeniedPath = new PathString("/denied") - }); - map.Map("/forbid", signoutApp => signoutApp.Run(context => context.Authentication.ForbidAsync("Cookies"))); + map.UseAuthentication(); + map.Map("/forbid", signoutApp => signoutApp.Run(context => context.ForbidAsync("Cookies"))); })) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie(o => o.AccessDeniedPath = new PathString("/denied"))); var server = new TestServer(builder); var transaction = await server.SendAsync("http://example.com/base/forbid"); @@ -1176,17 +1279,17 @@ public async Task CanSpecifyAndShareDataProtector() var builder1 = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - TicketDataFormat = new TicketDataFormat(dp), - CookieName = "Cookie" - }); + app.UseAuthentication(); app.Use((context, next) => - context.Authentication.SignInAsync("Cookies", + context.SignInAsync("Cookies", new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))), new AuthenticationProperties())); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie(o => + { + o.TicketDataFormat = new TicketDataFormat(dp); + o.Cookie.Name = "Cookie"; + })); var server1 = new TestServer(builder1); var transaction = await SendAsync(server1, "http://example.com/stuff"); @@ -1195,20 +1298,18 @@ public async Task CanSpecifyAndShareDataProtector() var builder2 = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - AuthenticationScheme = "Cookies", - CookieName = "Cookie", - TicketDataFormat = new TicketDataFormat(dp) - }); + app.UseAuthentication(); app.Use(async (context, next) => { - var authContext = new AuthenticateContext("Cookies"); - await context.Authentication.AuthenticateAsync(authContext); - Describe(context.Response, authContext); + var result = await context.AuthenticateAsync("Cookies"); + Describe(context.Response, result); }); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie("Cookies", o => + { + o.Cookie.Name = "Cookie"; + o.TicketDataFormat = new TicketDataFormat(dp); + })); var server2 = new TestServer(builder2); var transaction2 = await SendAsync(server2, "http://example.com/stuff", transaction.CookieNameValue); Assert.Equal("Alice", FindClaimValue(transaction2, ClaimTypes.Name)); @@ -1219,27 +1320,27 @@ public async Task CanSpecifyAndShareDataProtector() public async Task NullExpiresUtcPropertyIsGuarded() { var builder = new WebHostBuilder() - .ConfigureServices(services => services.AddAuthentication()) - .Configure(app => + .ConfigureServices(services => services.AddAuthentication().AddCookie(o => { - app.UseCookieAuthentication(new CookieAuthenticationOptions + o.Events = new CookieAuthenticationEvents { - Events = new CookieAuthenticationEvents + OnValidatePrincipal = context => { - OnValidatePrincipal = context => - { - context.Properties.ExpiresUtc = null; - context.ShouldRenew = true; - return Task.FromResult(0); - } + context.Properties.ExpiresUtc = null; + context.ShouldRenew = true; + return Task.FromResult(0); } - }); + }; + })) + .Configure(app => + { + app.UseAuthentication(); app.Run(async context => { if (context.Request.Path == "/signin") { - await context.Authentication.SignInAsync( + await context.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies")))); } @@ -1287,6 +1388,16 @@ private static string FindClaimValue(Transaction transaction, string claimType) return claim.Attribute("value").Value; } + private static string FindPropertiesValue(Transaction transaction, string key) + { + var property = transaction.ResponseElement.Elements("extra").SingleOrDefault(elt => elt.Attribute("type").Value == key); + if (property == null) + { + return null; + } + return property.Attribute("value").Value; + } + private static async Task GetAuthData(TestServer server, string url, string cookie) { var request = new HttpRequestMessage(HttpMethod.Get, url); @@ -1298,18 +1409,44 @@ private static async Task GetAuthData(TestServer server, string url, s return me; } - private static TestServer CreateServer(CookieAuthenticationOptions options, Func testpath = null, Uri baseAddress = null, ClaimsTransformationOptions claimsTransform = null) + private class ClaimsTransformer : IClaimsTransformation + { + public Task TransformAsync(ClaimsPrincipal p) + { + var firstId = p.Identities.First(); + if (firstId.HasClaim("marker", "true")) + { + firstId.RemoveClaim(firstId.FindFirst("marker")); + } + // TransformAsync could be called twice on one request if you have a default scheme and also + // call AuthenticateAsync. + if (!p.Identities.Any(i => i.AuthenticationType == "xform")) + { + var id = new ClaimsIdentity("xform"); + id.AddClaim(new Claim("xform", "yup")); + p.AddIdentity(id); + } + return Task.FromResult(p); + } + } + + private TestServer CreateServer(Action configureOptions, Func testpath = null, Uri baseAddress = null, bool claimsTransform = false) + => CreateServerWithServices(s => + { + s.AddSingleton(_clock); + s.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(configureOptions); + if (claimsTransform) + { + s.AddSingleton(); + } + }, testpath, baseAddress); + + private static TestServer CreateServerWithServices(Action configureServices, Func testpath = null, Uri baseAddress = null) { var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(options); - // app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationScheme = "Cookie2" }); - - if (claimsTransform != null) - { - app.UseClaimsTransformation(claimsTransform); - } + app.UseAuthentication(); app.Use(async (context, next) => { var req = context.Request; @@ -1319,70 +1456,72 @@ private static TestServer CreateServer(CookieAuthenticationOptions options, Func { res.StatusCode = 200; } - else if (req.Path == new PathString("/protected")) - { - res.StatusCode = 401; - } else if (req.Path == new PathString("/forbid")) // Simulate forbidden { - await context.Authentication.ForbidAsync(CookieAuthenticationDefaults.AuthenticationScheme); + await context.ForbidAsync(CookieAuthenticationDefaults.AuthenticationScheme); } else if (req.Path == new PathString("/challenge")) { - await context.Authentication.ChallengeAsync(CookieAuthenticationDefaults.AuthenticationScheme); + await context.ChallengeAsync(CookieAuthenticationDefaults.AuthenticationScheme); } else if (req.Path == new PathString("/signout")) { - await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); } else if (req.Path == new PathString("/unauthorized")) { - await context.Authentication.ChallengeAsync(CookieAuthenticationDefaults.AuthenticationScheme, new AuthenticationProperties(), ChallengeBehavior.Unauthorized); + await context.ChallengeAsync(CookieAuthenticationDefaults.AuthenticationScheme, new AuthenticationProperties()); } else if (req.Path == new PathString("/protected/CustomRedirect")) { - await context.Authentication.ChallengeAsync(new AuthenticationProperties() { RedirectUri = "/CustomRedirect" }); + await context.ChallengeAsync(CookieAuthenticationDefaults.AuthenticationScheme, new AuthenticationProperties() { RedirectUri = "/CustomRedirect" }); } else if (req.Path == new PathString("/me")) { - var authContext = new AuthenticateContext(CookieAuthenticationDefaults.AuthenticationScheme); - authContext.Authenticated(context.User, properties: null, description: null); - Describe(res, authContext); + Describe(res, AuthenticateResult.Success(new AuthenticationTicket(context.User, new AuthenticationProperties(), CookieAuthenticationDefaults.AuthenticationScheme))); } else if (req.Path.StartsWithSegments(new PathString("/me"), out remainder)) { - var authContext = new AuthenticateContext(remainder.Value.Substring(1)); - await context.Authentication.AuthenticateAsync(authContext); - Describe(res, authContext); + var ticket = await context.AuthenticateAsync(remainder.Value.Substring(1)); + Describe(res, ticket); } else if (req.Path == new PathString("/testpath") && testpath != null) { await testpath(context); } + else if (req.Path == new PathString("/checkforerrors")) + { + var result = await context.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme); // this used to be "Automatic" + if (result.Failure != null) + { + throw new Exception("Failed to authenticate", result.Failure); + } + return; + } else { await next(); } }); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(configureServices); var server = new TestServer(builder); server.BaseAddress = baseAddress; return server; } - private static void Describe(HttpResponse res, AuthenticateContext result) + private static void Describe(HttpResponse res, AuthenticateResult result) { res.StatusCode = 200; res.ContentType = "text/xml"; var xml = new XElement("xml"); - if (result != null && result.Principal != null) + if (result?.Ticket?.Principal != null) { - xml.Add(result.Principal.Claims.Select(claim => new XElement("claim", new XAttribute("type", claim.Type), new XAttribute("value", claim.Value)))); + xml.Add(result.Ticket.Principal.Claims.Select(claim => new XElement("claim", new XAttribute("type", claim.Type), new XAttribute("value", claim.Value)))); } - if (result != null && result.Properties != null) + if (result?.Ticket?.Properties != null) { - xml.Add(result.Properties.Select(extra => new XElement("extra", new XAttribute("type", extra.Key), new XAttribute("value", extra.Value)))); + xml.Add(result.Ticket.Properties.Items.Select(extra => new XElement("extra", new XAttribute("type", extra.Key), new XAttribute("value", extra.Value)))); } var xmlBytes = Encoding.UTF8.GetBytes(xml.ToString()); res.Body.Write(xmlBytes, 0, xmlBytes.Length); diff --git a/test/Microsoft.AspNetCore.Authentication.Test/DynamicSchemeTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/DynamicSchemeTests.cs new file mode 100644 index 000000000..d658609b0 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/DynamicSchemeTests.cs @@ -0,0 +1,170 @@ +// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Net; +using System.Security.Claims; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Xunit; + +namespace Microsoft.AspNetCore.Authentication +{ + public class DynamicSchemeTests + { + [Fact] + public async Task OptionsAreConfiguredOnce() + { + var server = CreateServer(s => + { + s.Configure("One", o => o.Instance = new Singleton()); + s.Configure("Two", o => o.Instance = new Singleton()); + }); + // Add One scheme + var response = await server.CreateClient().GetAsync("http://example.com/add/One"); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var transaction = await server.SendAsync("http://example.com/auth/One"); + Assert.Equal("One", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "One")); + Assert.Equal("1", transaction.FindClaimValue("Count")); + + // Verify option is not recreated + transaction = await server.SendAsync("http://example.com/auth/One"); + Assert.Equal("One", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "One")); + Assert.Equal("1", transaction.FindClaimValue("Count")); + + // Add Two scheme + response = await server.CreateClient().GetAsync("http://example.com/add/Two"); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + transaction = await server.SendAsync("http://example.com/auth/Two"); + Assert.Equal("Two", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "Two")); + Assert.Equal("2", transaction.FindClaimValue("Count")); + + // Verify options are not recreated + transaction = await server.SendAsync("http://example.com/auth/One"); + Assert.Equal("One", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "One")); + Assert.Equal("1", transaction.FindClaimValue("Count")); + transaction = await server.SendAsync("http://example.com/auth/Two"); + Assert.Equal("Two", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "Two")); + Assert.Equal("2", transaction.FindClaimValue("Count")); + } + + [Fact] + public async Task CanAddAndRemoveSchemes() + { + var server = CreateServer(); + await Assert.ThrowsAsync(() => server.SendAsync("http://example.com/auth/One")); + + // Add One scheme + var response = await server.CreateClient().GetAsync("http://example.com/add/One"); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var transaction = await server.SendAsync("http://example.com/auth/One"); + Assert.Equal("One", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "One")); + + // Add Two scheme + response = await server.CreateClient().GetAsync("http://example.com/add/Two"); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + transaction = await server.SendAsync("http://example.com/auth/Two"); + Assert.Equal("Two", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "Two")); + + // Remove Two + response = await server.CreateClient().GetAsync("http://example.com/remove/Two"); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + await Assert.ThrowsAsync(() => server.SendAsync("http://example.com/auth/Two")); + transaction = await server.SendAsync("http://example.com/auth/One"); + Assert.Equal("One", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "One")); + + // Remove One + response = await server.CreateClient().GetAsync("http://example.com/remove/One"); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + await Assert.ThrowsAsync(() => server.SendAsync("http://example.com/auth/Two")); + await Assert.ThrowsAsync(() => server.SendAsync("http://example.com/auth/One")); + } + + public class TestOptions : AuthenticationSchemeOptions + { + public Singleton Instance { get; set; } + } + + public class Singleton + { + public static int _count; + + public Singleton() + { + _count++; + Count = _count; + } + + public int Count { get; } + } + + private class TestHandler : AuthenticationHandler + { + public TestHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) + { + } + + protected override Task HandleAuthenticateAsync() + { + var principal = new ClaimsPrincipal(); + var id = new ClaimsIdentity(); + id.AddClaim(new Claim(ClaimTypes.NameIdentifier, Scheme.Name, ClaimValueTypes.String, Scheme.Name)); + if (Options.Instance != null) + { + id.AddClaim(new Claim("Count", Options.Instance.Count.ToString())); + } + principal.AddIdentity(id); + return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name))); + } + } + + private static TestServer CreateServer(Action configureServices = null) + { + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseAuthentication(); + app.Use(async (context, next) => + { + var req = context.Request; + var res = context.Response; + if (req.Path.StartsWithSegments(new PathString("/add"), out var remainder)) + { + var name = remainder.Value.Substring(1); + var auth = context.RequestServices.GetRequiredService(); + var scheme = new AuthenticationScheme(name, name, typeof(TestHandler)); + auth.AddScheme(scheme); + } + else if (req.Path.StartsWithSegments(new PathString("/auth"), out remainder)) + { + var name = (remainder.Value.Length > 0) ? remainder.Value.Substring(1) : null; + var result = await context.AuthenticateAsync(name); + res.Describe(result?.Ticket?.Principal); + } + else if (req.Path.StartsWithSegments(new PathString("/remove"), out remainder)) + { + var name = remainder.Value.Substring(1); + var auth = context.RequestServices.GetRequiredService(); + auth.RemoveScheme(name); + } + else + { + await next(); + } + }); + }) + .ConfigureServices(services => + { + configureServices?.Invoke(services); + services.AddAuthentication(); + }); + return new TestServer(builder); + } + } +} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/Facebook/FacebookMiddlewareTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/Facebook/FacebookMiddlewareTests.cs deleted file mode 100644 index f38ca8afc..000000000 --- a/test/Microsoft.AspNetCore.Authentication.Test/Facebook/FacebookMiddlewareTests.cs +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Text.Encodings.Web; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Authentication.OAuth; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.DataProtection; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.Authentication.Facebook -{ - public class FacebookMiddlewareTests - { - [Fact] - public async Task ChallengeWillTriggerApplyRedirectEvent() - { - var server = CreateServer( - app => - { - app.UseFacebookAuthentication(new FacebookOptions - { - AppId = "Test App Id", - AppSecret = "Test App Secret", - Events = new OAuthEvents - { - OnRedirectToAuthorizationEndpoint = context => - { - context.Response.Redirect(context.RedirectUri + "&custom=test"); - return Task.FromResult(0); - } - } - }); - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - AuthenticationScheme = "External", - AutomaticAuthenticate = true - }); - }, - services => - { - services.AddAuthentication(options => - { - options.SignInScheme = "External"; - }); - }, - context => - { - // REVIEW: Gross. - context.Authentication.ChallengeAsync("Facebook").GetAwaiter().GetResult(); - return true; - }); - var transaction = await server.SendAsync("http://example.com/challenge"); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - var query = transaction.Response.Headers.Location.Query; - Assert.Contains("custom=test", query); - } - - [Fact] - public async Task NestedMapWillNotAffectRedirect() - { - var server = CreateServer(app => - app.Map("/base", map => { - map.UseFacebookAuthentication(new FacebookOptions - { - AppId = "Test App Id", - AppSecret = "Test App Secret", - SignInScheme = "External" - }); - map.Map("/login", signoutApp => signoutApp.Run(context => context.Authentication.ChallengeAsync("Facebook", new AuthenticationProperties() { RedirectUri = "/" }))); - }), - services => services.AddAuthentication(), - handler: null); - var transaction = await server.SendAsync("http://example.com/base/login"); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - var location = transaction.Response.Headers.Location.AbsoluteUri; - Assert.Contains("https://www.facebook.com/v2.6/dialog/oauth", location); - Assert.Contains("response_type=code", location); - Assert.Contains("client_id=", location); - Assert.Contains("redirect_uri=" + UrlEncoder.Default.Encode("http://example.com/base/signin-facebook"), location); - Assert.Contains("scope=", location); - Assert.Contains("state=", location); - } - - [Fact] - public async Task MapWillNotAffectRedirect() - { - var server = CreateServer( - app => - { - app.UseFacebookAuthentication(new FacebookOptions - { - AppId = "Test App Id", - AppSecret = "Test App Secret", - SignInScheme = "External" - }); - app.Map("/login", signoutApp => signoutApp.Run(context => context.Authentication.ChallengeAsync("Facebook", new AuthenticationProperties() { RedirectUri = "/" }))); - }, - services => services.AddAuthentication(), - handler: null); - var transaction = await server.SendAsync("http://example.com/login"); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - var location = transaction.Response.Headers.Location.AbsoluteUri; - Assert.Contains("https://www.facebook.com/v2.6/dialog/oauth", location); - Assert.Contains("response_type=code", location); - Assert.Contains("client_id=", location); - Assert.Contains("redirect_uri="+ UrlEncoder.Default.Encode("http://example.com/signin-facebook"), location); - Assert.Contains("scope=", location); - Assert.Contains("state=", location); - } - - [Fact] - public async Task ChallengeWillTriggerRedirection() - { - var server = CreateServer( - app => - { - app.UseFacebookAuthentication(new FacebookOptions - { - AppId = "Test App Id", - AppSecret = "Test App Secret" - }); - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - AuthenticationScheme = "External" - }); - }, - services => - { - services.AddAuthentication(options => options.SignInScheme = "External"); - }, - context => - { - // REVIEW: gross - context.Authentication.ChallengeAsync("Facebook").GetAwaiter().GetResult(); - return true; - }); - var transaction = await server.SendAsync("http://example.com/challenge"); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - var location = transaction.Response.Headers.Location.AbsoluteUri; - Assert.Contains("https://www.facebook.com/v2.6/dialog/oauth", location); - Assert.Contains("response_type=code", location); - Assert.Contains("client_id=", location); - Assert.Contains("redirect_uri=", location); - Assert.Contains("scope=", location); - Assert.Contains("state=", location); - } - - [Fact] - public async Task CustomUserInfoEndpointHasValidGraphQuery() - { - var customUserInfoEndpoint = "https://graph.facebook.com/me?fields=email,timezone,picture"; - var finalUserInfoEndpoint = string.Empty; - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("FacebookTest")); - var server = CreateServer( - app => - { - app.UseCookieAuthentication(); - app.UseFacebookAuthentication(new FacebookOptions - { - AppId = "Test App Id", - AppSecret = "Test App Secret", - StateDataFormat = stateFormat, - UserInformationEndpoint = customUserInfoEndpoint, - BackchannelHttpHandler = new TestHttpMessageHandler - { - Sender = req => - { - if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == FacebookDefaults.TokenEndpoint) - { - var res = new HttpResponseMessage(HttpStatusCode.OK); - var graphResponse = JsonConvert.SerializeObject(new - { - access_token = "TestAuthToken" - }); - res.Content = new StringContent(graphResponse, Encoding.UTF8); - return res; - } - if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == - new Uri(customUserInfoEndpoint).GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped)) - { - finalUserInfoEndpoint = req.RequestUri.ToString(); - var res = new HttpResponseMessage(HttpStatusCode.OK); - var graphResponse = JsonConvert.SerializeObject(new - { - id = "TestProfileId", - name = "TestName" - }); - res.Content = new StringContent(graphResponse, Encoding.UTF8); - return res; - } - return null; - } - } - }); - }, - services => - { - services.AddAuthentication(options => options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme); - }, handler: null); - - var properties = new AuthenticationProperties(); - var correlationKey = ".xsrf"; - var correlationValue = "TestCorrelationId"; - properties.Items.Add(correlationKey, correlationValue); - properties.RedirectUri = "/me"; - var state = stateFormat.Protect(properties); - var transaction = await server.SendAsync( - "https://example.com/signin-facebook?code=TestCode&state=" + UrlEncoder.Default.Encode(state), - $".AspNetCore.Correlation.Facebook.{correlationValue}=N"); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); - Assert.Equal(1, finalUserInfoEndpoint.Count(c => c == '?')); - Assert.Contains("fields=email,timezone,picture", finalUserInfoEndpoint); - Assert.Contains("&access_token=", finalUserInfoEndpoint); - } - - private static TestServer CreateServer(Action configure, Action configureServices, Func handler) - { - var builder = new WebHostBuilder() - .Configure(app => - { - if (configure != null) - { - configure(app); - } - app.Use(async (context, next) => - { - if (handler == null || !handler(context)) - { - await next(); - } - }); - }) - .ConfigureServices(configureServices); - return new TestServer(builder); - } - } -} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/FacebookTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/FacebookTests.cs new file mode 100644 index 000000000..964af2ce7 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/FacebookTests.cs @@ -0,0 +1,389 @@ +// 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.Authentication.Cookies; +using Microsoft.AspNetCore.Authentication.OAuth; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging.Abstractions; +using Newtonsoft.Json; +using System; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Authentication.Facebook +{ + public class FacebookTests : RemoteAuthenticationTests + { + protected override string DefaultScheme => FacebookDefaults.AuthenticationScheme; + protected override Type HandlerType => typeof(FacebookHandler); + protected override bool SupportsSignIn { get => false; } + protected override bool SupportsSignOut { get => false; } + + protected override void RegisterAuth(AuthenticationBuilder services, Action configure) + { + services.AddFacebook(o => + { + ConfigureDefaults(o); + configure.Invoke(o); + }); + } + + protected override void ConfigureDefaults(FacebookOptions o) + { + o.AppId = "whatever"; + o.AppSecret = "whatever"; + o.SignInScheme = "auth1"; + } + + [Fact] + public async Task ThrowsIfAppIdMissing() + { + var server = CreateServer( + app => { }, + services => services.AddAuthentication().AddFacebook(o => o.SignInScheme = "Whatever"), + async context => + { + await Assert.ThrowsAsync("AppId", () => context.ChallengeAsync("Facebook")); + return true; + }); + var transaction = await server.SendAsync("http://example.com/challenge"); + Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); + } + + [Fact] + public async Task ThrowsIfAppSecretMissing() + { + var server = CreateServer( + app => { }, + services => services.AddAuthentication().AddFacebook(o => o.AppId = "Whatever"), + async context => + { + await Assert.ThrowsAsync("AppSecret", () => context.ChallengeAsync("Facebook")); + return true; + }); + var transaction = await server.SendAsync("http://example.com/challenge"); + Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); + } + + [Fact] + public async Task ChallengeWillTriggerApplyRedirectEvent() + { + var server = CreateServer( + app => + { + app.UseAuthentication(); + }, + services => + { + services.AddAuthentication("External") + .AddCookie("External", o => { }) + .AddFacebook(o => + { + o.AppId = "Test App Id"; + o.AppSecret = "Test App Secret"; + o.Events = new OAuthEvents + { + OnRedirectToAuthorizationEndpoint = context => + { + context.Response.Redirect(context.RedirectUri + "&custom=test"); + return Task.FromResult(0); + } + }; + }); + }, + async context => + { + await context.ChallengeAsync("Facebook"); + return true; + }); + var transaction = await server.SendAsync("http://example.com/challenge"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + var query = transaction.Response.Headers.Location.Query; + Assert.Contains("custom=test", query); + } + + [Fact] + public async Task ChallengeWillIncludeScopeAsConfigured() + { + var server = CreateServer( + app => app.UseAuthentication(), + services => + { + services.AddAuthentication().AddFacebook(o => + { + o.AppId = "Test App Id"; + o.AppSecret = "Test App Secret"; + o.Scope.Clear(); + o.Scope.Add("foo"); + o.Scope.Add("bar"); + }); + }, + async context => + { + await context.ChallengeAsync(FacebookDefaults.AuthenticationScheme); + return true; + }); + + var transaction = await server.SendAsync("http://example.com/challenge"); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.Contains("scope=foo,bar", res.Headers.Location.Query); + } + + [Fact] + public async Task ChallengeWillIncludeScopeAsOverwritten() + { + var server = CreateServer( + app => app.UseAuthentication(), + services => + { + services.AddAuthentication().AddFacebook(o => + { + o.AppId = "Test App Id"; + o.AppSecret = "Test App Secret"; + o.Scope.Clear(); + o.Scope.Add("foo"); + o.Scope.Add("bar"); + }); + }, + async context => + { + var properties = new OAuthChallengeProperties(); + properties.SetScope("baz", "qux"); + await context.ChallengeAsync(FacebookDefaults.AuthenticationScheme, properties); + return true; + }); + + var transaction = await server.SendAsync("http://example.com/challenge"); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.Contains("scope=baz,qux", res.Headers.Location.Query); + } + + [Fact] + public async Task ChallengeWillIncludeScopeAsOverwrittenWithBaseAuthenticationProperties() + { + var server = CreateServer( + app => app.UseAuthentication(), + services => + { + services.AddAuthentication().AddFacebook(o => + { + o.AppId = "Test App Id"; + o.AppSecret = "Test App Secret"; + o.Scope.Clear(); + o.Scope.Add("foo"); + o.Scope.Add("bar"); + }); + }, + async context => + { + var properties = new AuthenticationProperties(); + properties.SetParameter(OAuthChallengeProperties.ScopeKey, new string[] { "baz", "qux" }); + await context.ChallengeAsync(FacebookDefaults.AuthenticationScheme, properties); + return true; + }); + + var transaction = await server.SendAsync("http://example.com/challenge"); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.Contains("scope=baz,qux", res.Headers.Location.Query); + } + + [Fact] + public async Task NestedMapWillNotAffectRedirect() + { + var server = CreateServer(app => app.Map("/base", map => + { + map.UseAuthentication(); + map.Map("/login", signoutApp => signoutApp.Run(context => context.ChallengeAsync("Facebook", new AuthenticationProperties() { RedirectUri = "/" }))); + }), + services => + { + services.AddAuthentication() + .AddCookie("External", o => { }) + .AddFacebook(o => + { + o.AppId = "Test App Id"; + o.AppSecret = "Test App Secret"; + }); + }, + handler: null); + + var transaction = await server.SendAsync("http://example.com/base/login"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + var location = transaction.Response.Headers.Location.AbsoluteUri; + Assert.Contains("https://www.facebook.com/v3.1/dialog/oauth", location); + Assert.Contains("response_type=code", location); + Assert.Contains("client_id=", location); + Assert.Contains("redirect_uri=" + UrlEncoder.Default.Encode("http://example.com/base/signin-facebook"), location); + Assert.Contains("scope=", location); + Assert.Contains("state=", location); + } + + [Fact] + public async Task MapWillNotAffectRedirect() + { + var server = CreateServer( + app => + { + app.UseAuthentication(); + app.Map("/login", signoutApp => signoutApp.Run(context => context.ChallengeAsync("Facebook", new AuthenticationProperties() { RedirectUri = "/" }))); + }, + services => + { + services.AddAuthentication() + .AddCookie("External", o => { }) + .AddFacebook(o => + { + o.AppId = "Test App Id"; + o.AppSecret = "Test App Secret"; + o.SignInScheme = "External"; + }); + }, + handler: null); + var transaction = await server.SendAsync("http://example.com/login"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + var location = transaction.Response.Headers.Location.AbsoluteUri; + Assert.Contains("https://www.facebook.com/v3.1/dialog/oauth", location); + Assert.Contains("response_type=code", location); + Assert.Contains("client_id=", location); + Assert.Contains("redirect_uri=" + UrlEncoder.Default.Encode("http://example.com/signin-facebook"), location); + Assert.Contains("scope=", location); + Assert.Contains("state=", location); + } + + [Fact] + public async Task ChallengeWillTriggerRedirection() + { + var server = CreateServer( + app => app.UseAuthentication(), + services => + { + services.AddAuthentication(options => + { + options.DefaultSignInScheme = "External"; + }) + .AddCookie() + .AddFacebook(o => + { + o.AppId = "Test App Id"; + o.AppSecret = "Test App Secret"; + }); + }, + async context => + { + await context.ChallengeAsync("Facebook"); + return true; + }); + var transaction = await server.SendAsync("http://example.com/challenge"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + var location = transaction.Response.Headers.Location.AbsoluteUri; + Assert.Contains("https://www.facebook.com/v3.1/dialog/oauth", location); + Assert.Contains("response_type=code", location); + Assert.Contains("client_id=", location); + Assert.Contains("redirect_uri=", location); + Assert.Contains("scope=", location); + Assert.Contains("state=", location); + } + + [Fact] + public async Task CustomUserInfoEndpointHasValidGraphQuery() + { + var customUserInfoEndpoint = "https://graph.facebook.com/me?fields=email,timezone,picture"; + var finalUserInfoEndpoint = string.Empty; + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("FacebookTest")); + var server = CreateServer( + app => app.UseAuthentication(), + services => + { + services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) + .AddCookie() + .AddFacebook(o => + { + o.AppId = "Test App Id"; + o.AppSecret = "Test App Secret"; + o.StateDataFormat = stateFormat; + o.UserInformationEndpoint = customUserInfoEndpoint; + o.BackchannelHttpHandler = new TestHttpMessageHandler + { + Sender = req => + { + if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == FacebookDefaults.TokenEndpoint) + { + var res = new HttpResponseMessage(HttpStatusCode.OK); + var graphResponse = JsonConvert.SerializeObject(new + { + access_token = "TestAuthToken" + }); + res.Content = new StringContent(graphResponse, Encoding.UTF8); + return res; + } + if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == + new Uri(customUserInfoEndpoint).GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped)) + { + finalUserInfoEndpoint = req.RequestUri.ToString(); + var res = new HttpResponseMessage(HttpStatusCode.OK); + var graphResponse = JsonConvert.SerializeObject(new + { + id = "TestProfileId", + name = "TestName" + }); + res.Content = new StringContent(graphResponse, Encoding.UTF8); + return res; + } + return null; + } + }; + }); + }, + handler: null); + + var properties = new AuthenticationProperties(); + var correlationKey = ".xsrf"; + var correlationValue = "TestCorrelationId"; + properties.Items.Add(correlationKey, correlationValue); + properties.RedirectUri = "/me"; + var state = stateFormat.Protect(properties); + var transaction = await server.SendAsync( + "https://example.com/signin-facebook?code=TestCode&state=" + UrlEncoder.Default.Encode(state), + $".AspNetCore.Correlation.Facebook.{correlationValue}=N"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); + Assert.Equal(1, finalUserInfoEndpoint.Count(c => c == '?')); + Assert.Contains("fields=email,timezone,picture", finalUserInfoEndpoint); + Assert.Contains("&access_token=", finalUserInfoEndpoint); + } + + private static TestServer CreateServer(Action configure, Action configureServices, Func> handler) + { + var builder = new WebHostBuilder() + .Configure(app => + { + configure?.Invoke(app); + app.Use(async (context, next) => + { + if (handler == null || !await handler(context)) + { + await next(); + } + }); + }) + .ConfigureServices(configureServices); + return new TestServer(builder); + } + } +} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/Google/GoogleMiddlewareTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/GoogleTests.cs similarity index 63% rename from test/Microsoft.AspNetCore.Authentication.Test/Google/GoogleMiddlewareTests.cs rename to test/Microsoft.AspNetCore.Authentication.Test/GoogleTests.cs index 944c322ad..ce158eaf2 100644 --- a/test/Microsoft.AspNetCore.Authentication.Test/Google/GoogleMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Authentication.Test/GoogleTests.cs @@ -1,5 +1,15 @@ // Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information. +using Microsoft.AspNetCore.Authentication.OAuth; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging.Abstractions; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; @@ -9,34 +19,45 @@ using System.Text; using System.Text.Encodings.Web; using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication.OAuth; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.DataProtection; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.Http.Features.Authentication; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; using Xunit; namespace Microsoft.AspNetCore.Authentication.Google { - public class GoogleMiddlewareTests + public class GoogleTests : RemoteAuthenticationTests { + protected override string DefaultScheme => GoogleDefaults.AuthenticationScheme; + protected override Type HandlerType => typeof(GoogleHandler); + protected override bool SupportsSignIn { get => false; } + protected override bool SupportsSignOut { get => false; } + + protected override void RegisterAuth(AuthenticationBuilder services, Action configure) + { + services.AddGoogle(o => + { + ConfigureDefaults(o); + configure.Invoke(o); + }); + } + + protected override void ConfigureDefaults(GoogleOptions o) + { + o.ClientId = "whatever"; + o.ClientSecret = "whatever"; + o.SignInScheme = "auth1"; + } + [Fact] public async Task ChallengeWillTriggerRedirection() { - var server = CreateServer(new GoogleOptions + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret" + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; }); var transaction = await server.SendAsync("https://example.com/challenge"); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); var location = transaction.Response.Headers.Location.ToString(); - Assert.Contains("https://accounts.google.com/o/oauth2/auth?response_type=code", location); + Assert.Contains("https://accounts.google.com/o/oauth2/v2/auth?response_type=code", location); Assert.Contains("&client_id=", location); Assert.Contains("&redirect_uri=", location); Assert.Contains("&scope=", location); @@ -52,10 +73,10 @@ public async Task ChallengeWillTriggerRedirection() [Fact] public async Task SignInThrows() { - var server = CreateServer(new GoogleOptions + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret" + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; }); var transaction = await server.SendAsync("https://example.com/signIn"); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); @@ -64,10 +85,10 @@ public async Task SignInThrows() [Fact] public async Task SignOutThrows() { - var server = CreateServer(new GoogleOptions + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret" + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; }); var transaction = await server.SendAsync("https://example.com/signOut"); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); @@ -76,143 +97,225 @@ public async Task SignOutThrows() [Fact] public async Task ForbidThrows() { - var server = CreateServer(new GoogleOptions + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret" + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; }); var transaction = await server.SendAsync("https://example.com/signOut"); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); } [Fact] - public async Task Challenge401WillTriggerRedirection() + public async Task Challenge401WillNotTriggerRedirection() { - var server = CreateServer(new GoogleOptions + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - AutomaticChallenge = true + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; }); var transaction = await server.SendAsync("https://example.com/401"); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - var location = transaction.Response.Headers.Location.ToString(); - Assert.Contains("https://accounts.google.com/o/oauth2/auth?response_type=code", location); - Assert.Contains("&client_id=", location); - Assert.Contains("&redirect_uri=", location); - Assert.Contains("&scope=", location); - Assert.Contains("&state=", location); + Assert.Equal(HttpStatusCode.Unauthorized, transaction.Response.StatusCode); } [Fact] public async Task ChallengeWillSetCorrelationCookie() { - var server = CreateServer(new GoogleOptions + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret" + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; }); var transaction = await server.SendAsync("https://example.com/challenge"); Assert.Contains(transaction.SetCookie, cookie => cookie.StartsWith(".AspNetCore.Correlation.Google.")); } [Fact] - public async Task Challenge401WillSetCorrelationCookie() + public async Task ChallengeWillSetDefaultScope() { - var server = CreateServer(new GoogleOptions + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - AutomaticChallenge = true + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; }); - var transaction = await server.SendAsync("https://example.com/401"); - Assert.Contains(transaction.SetCookie, cookie => cookie.StartsWith(".AspNetCore.Correlation.Google.")); + var transaction = await server.SendAsync("https://example.com/challenge"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + var query = transaction.Response.Headers.Location.Query; + Assert.Contains("&scope=" + UrlEncoder.Default.Encode("openid profile email"), query); } [Fact] - public async Task ChallengeWillSetDefaultScope() + public async Task ChallengeWillUseAuthenticationPropertiesParametersAsQueryArguments() { - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret" + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = stateFormat; + }, + context => + { + var req = context.Request; + var res = context.Response; + if (req.Path == new PathString("/challenge2")) + { + return context.ChallengeAsync("Google", new GoogleChallengeProperties + { + Scope = new string[] { "openid", "https://www.googleapis.com/auth/plus.login" }, + AccessType = "offline", + ApprovalPrompt = "force", + Prompt = "consent", + LoginHint = "test@example.com", + IncludeGrantedScopes = false, + }); + } + + return Task.FromResult(null); }); - var transaction = await server.SendAsync("https://example.com/challenge"); + var transaction = await server.SendAsync("https://example.com/challenge2"); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - var query = transaction.Response.Headers.Location.Query; - Assert.Contains("&scope=" + UrlEncoder.Default.Encode("openid profile email"), query); + + // verify query arguments + var query = QueryHelpers.ParseQuery(transaction.Response.Headers.Location.Query); + Assert.Equal("openid https://www.googleapis.com/auth/plus.login", query["scope"]); + Assert.Equal("offline", query["access_type"]); + Assert.Equal("force", query["approval_prompt"]); + Assert.Equal("consent", query["prompt"]); + Assert.Equal("false", query["include_granted_scopes"]); + Assert.Equal("test@example.com", query["login_hint"]); + + // verify that the passed items were not serialized + var stateProperties = stateFormat.Unprotect(query["state"]); + Assert.DoesNotContain("scope", stateProperties.Items.Keys); + Assert.DoesNotContain("access_type", stateProperties.Items.Keys); + Assert.DoesNotContain("include_granted_scopes", stateProperties.Items.Keys); + Assert.DoesNotContain("approval_prompt", stateProperties.Items.Keys); + Assert.DoesNotContain("prompt", stateProperties.Items.Keys); + Assert.DoesNotContain("login_hint", stateProperties.Items.Keys); } [Fact] - public async Task Challenge401WillSetDefaultScope() + public async Task ChallengeWillUseAuthenticationPropertiesItemsAsParameters() { - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => + { + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = stateFormat; + }, + context => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - AutomaticChallenge = true + var req = context.Request; + var res = context.Response; + if (req.Path == new PathString("/challenge2")) + { + return context.ChallengeAsync("Google", new AuthenticationProperties(new Dictionary() + { + { "scope", "https://www.googleapis.com/auth/plus.login" }, + { "access_type", "offline" }, + { "approval_prompt", "force" }, + { "prompt", "consent" }, + { "login_hint", "test@example.com" }, + { "include_granted_scopes", "false" } + })); + } + + return Task.FromResult(null); }); - var transaction = await server.SendAsync("https://example.com/401"); + var transaction = await server.SendAsync("https://example.com/challenge2"); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - var query = transaction.Response.Headers.Location.Query; - Assert.Contains("&scope=" + UrlEncoder.Default.Encode("openid profile email"), query); + + // verify query arguments + var query = QueryHelpers.ParseQuery(transaction.Response.Headers.Location.Query); + Assert.Equal("https://www.googleapis.com/auth/plus.login", query["scope"]); + Assert.Equal("offline", query["access_type"]); + Assert.Equal("force", query["approval_prompt"]); + Assert.Equal("consent", query["prompt"]); + Assert.Equal("false", query["include_granted_scopes"]); + Assert.Equal("test@example.com", query["login_hint"]); + + // verify that the passed items were not serialized + var stateProperties = stateFormat.Unprotect(query["state"]); + Assert.DoesNotContain("scope", stateProperties.Items.Keys); + Assert.DoesNotContain("access_type", stateProperties.Items.Keys); + Assert.DoesNotContain("include_granted_scopes", stateProperties.Items.Keys); + Assert.DoesNotContain("approval_prompt", stateProperties.Items.Keys); + Assert.DoesNotContain("prompt", stateProperties.Items.Keys); + Assert.DoesNotContain("login_hint", stateProperties.Items.Keys); } [Fact] - public async Task ChallengeWillUseAuthenticationPropertiesAsParameters() + public async Task ChallengeWillUseAuthenticationPropertiesItemsAsQueryArgumentsButParametersWillOverwrite() { - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - AutomaticChallenge = true + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = stateFormat; }, context => + { + var req = context.Request; + var res = context.Response; + if (req.Path == new PathString("/challenge2")) { - var req = context.Request; - var res = context.Response; - if (req.Path == new PathString("/challenge2")) + return context.ChallengeAsync("Google", new GoogleChallengeProperties(new Dictionary { - return context.Authentication.ChallengeAsync("Google", new AuthenticationProperties( - new Dictionary() - { - { "scope", "https://www.googleapis.com/auth/plus.login" }, - { "access_type", "offline" }, - { "approval_prompt", "force" }, - { "prompt", "consent" }, - { "login_hint", "test@example.com" }, - { "include_granted_scopes", "false" } - })); - } + ["scope"] = "https://www.googleapis.com/auth/plus.login", + ["access_type"] = "offline", + ["include_granted_scopes"] = "false", + ["approval_prompt"] = "force", + ["prompt"] = "login", + ["login_hint"] = "this-will-be-overwritten@example.com", + }) + { + Prompt = "consent", + LoginHint = "test@example.com", + }); + } - return Task.FromResult(null); - }); + return Task.FromResult(null); + }); var transaction = await server.SendAsync("https://example.com/challenge2"); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - var query = transaction.Response.Headers.Location.Query; - Assert.Contains("scope=" + UrlEncoder.Default.Encode("https://www.googleapis.com/auth/plus.login"), query); - Assert.Contains("access_type=offline", query); - Assert.Contains("approval_prompt=force", query); - Assert.Contains("prompt=consent", query); - Assert.Contains("include_granted_scopes=false", query); - Assert.Contains("login_hint=" + UrlEncoder.Default.Encode("test@example.com"), query); + + // verify query arguments + var query = QueryHelpers.ParseQuery(transaction.Response.Headers.Location.Query); + Assert.Equal("https://www.googleapis.com/auth/plus.login", query["scope"]); + Assert.Equal("offline", query["access_type"]); + Assert.Equal("force", query["approval_prompt"]); + Assert.Equal("consent", query["prompt"]); + Assert.Equal("false", query["include_granted_scopes"]); + Assert.Equal("test@example.com", query["login_hint"]); + + // verify that the passed items were not serialized + var stateProperties = stateFormat.Unprotect(query["state"]); + Assert.DoesNotContain("scope", stateProperties.Items.Keys); + Assert.DoesNotContain("access_type", stateProperties.Items.Keys); + Assert.DoesNotContain("include_granted_scopes", stateProperties.Items.Keys); + Assert.DoesNotContain("approval_prompt", stateProperties.Items.Keys); + Assert.DoesNotContain("prompt", stateProperties.Items.Keys); + Assert.DoesNotContain("login_hint", stateProperties.Items.Keys); } [Fact] public async Task ChallengeWillTriggerApplyRedirectEvent() { - var server = CreateServer(new GoogleOptions + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - Events = new OAuthEvents + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.Events = new OAuthEvents { OnRedirectToAuthorizationEndpoint = context => { context.Response.Redirect(context.RedirectUri + "&custom=test"); return Task.FromResult(0); } - } + }; }); var transaction = await server.SendAsync("https://example.com/challenge"); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); @@ -223,10 +326,10 @@ public async Task ChallengeWillTriggerApplyRedirectEvent() [Fact] public async Task AuthenticateWithoutCookieWillFail() { - var server = CreateServer(new GoogleOptions + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret" + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; }, async context => { @@ -234,9 +337,8 @@ public async Task AuthenticateWithoutCookieWillFail() var res = context.Response; if (req.Path == new PathString("/auth")) { - var auth = new AuthenticateContext("Google"); - await context.Authentication.AuthenticateAsync(auth); - Assert.NotNull(auth.Error); + var result = await context.AuthenticateAsync("Google"); + Assert.NotNull(result.Failure); } }); var transaction = await server.SendAsync("https://example.com/auth"); @@ -246,25 +348,90 @@ public async Task AuthenticateWithoutCookieWillFail() [Fact] public async Task ReplyPathWithoutStateQueryStringWillBeRejected() { - var server = CreateServer(new GoogleOptions + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret" + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; }); var error = await Assert.ThrowsAnyAsync(() => server.SendAsync("https://example.com/signin-google?code=TestCode")); Assert.Equal("The oauth state was missing or invalid.", error.GetBaseException().Message); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task ReplyPathWithAccessDeniedErrorFails(bool redirect) + { + var server = CreateServer(o => + { + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = new TestStateDataFormat(); + o.Events = redirect ? new OAuthEvents() + { + OnAccessDenied = ctx => + { + ctx.Response.Redirect("/error?FailureMessage=AccessDenied"); + ctx.HandleResponse(); + return Task.FromResult(0); + } + } : new OAuthEvents(); + }); + var sendTask = server.SendAsync("https://example.com/signin-google?error=access_denied&error_description=SoBad&error_uri=foobar&state=protected_state", + ".AspNetCore.Correlation.Google.correlationId=N"); + if (redirect) + { + var transaction = await sendTask; + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + Assert.Equal("/error?FailureMessage=AccessDenied", transaction.Response.Headers.GetValues("Location").First()); + } + else + { + var error = await Assert.ThrowsAnyAsync(() => sendTask); + Assert.Equal("Access was denied by the resource owner or by the remote server.", error.GetBaseException().Message); + } + } + + [Fact] + public async Task ReplyPathWithAccessDeniedError_AllowsCustomizingPath() + { + var server = CreateServer(o => + { + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = new TestStateDataFormat(); + o.AccessDeniedPath = "/access-denied"; + o.Events = new OAuthEvents() + { + OnAccessDenied = ctx => + { + Assert.Equal("/access-denied", ctx.AccessDeniedPath.Value); + Assert.Equal("http://testhost/redirect", ctx.ReturnUrl); + Assert.Equal("ReturnUrl", ctx.ReturnUrlParameter); + ctx.AccessDeniedPath = "/custom-denied-page"; + ctx.ReturnUrl = "http://www.google.com/"; + ctx.ReturnUrlParameter = "rurl"; + return Task.FromResult(0); + } + }; + }); + var transaction = await server.SendAsync("https://example.com/signin-google?error=access_denied&error_description=SoBad&error_uri=foobar&state=protected_state", + ".AspNetCore.Correlation.Google.correlationId=N"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + Assert.Equal("/custom-denied-page?rurl=http%3A%2F%2Fwww.google.com%2F", transaction.Response.Headers.GetValues("Location").First()); + } + [Theory] [InlineData(true)] [InlineData(false)] public async Task ReplyPathWithErrorFails(bool redirect) { - var server = CreateServer(new GoogleOptions + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - Events = redirect ? new OAuthEvents() + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = new TestStateDataFormat(); + o.Events = redirect ? new OAuthEvents() { OnRemoteFailure = ctx => { @@ -272,9 +439,10 @@ public async Task ReplyPathWithErrorFails(bool redirect) ctx.HandleResponse(); return Task.FromResult(0); } - } : new OAuthEvents() + } : new OAuthEvents(); }); - var sendTask = server.SendAsync("https://example.com/signin-google?error=OMG&error_description=SoBad&error_uri=foobar"); + var sendTask = server.SendAsync("https://example.com/signin-google?error=OMG&error_description=SoBad&error_uri=foobar&state=protected_state", + ".AspNetCore.Correlation.Google.correlationId=N"); if (redirect) { var transaction = await sendTask; @@ -293,15 +461,18 @@ public async Task ReplyPathWithErrorFails(bool redirect) [InlineData("CustomIssuer")] public async Task ReplyPathWillAuthenticateValidAuthorizeCodeAndState(string claimsIssuer) { - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - SaveTokens = true, - StateDataFormat = stateFormat, - ClaimsIssuer = claimsIssuer, - BackchannelHttpHandler = new TestHttpMessageHandler + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.SaveTokens = true; + o.StateDataFormat = stateFormat; + if (claimsIssuer != null) + { + o.ClaimsIssuer = claimsIssuer; + } + o.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { @@ -339,7 +510,7 @@ public async Task ReplyPathWillAuthenticateValidAuthorizeCodeAndState(string cla throw new NotImplementedException(req.RequestUri.AbsoluteUri); } - } + }; }); var properties = new AuthenticationProperties(); @@ -367,7 +538,7 @@ public async Task ReplyPathWillAuthenticateValidAuthorizeCodeAndState(string cla Assert.Equal("Test Family Name", transaction.FindClaimValue(ClaimTypes.Surname, expectedIssuer)); Assert.Equal("Test email", transaction.FindClaimValue(ClaimTypes.Email, expectedIssuer)); - // Ensure claims transformation + // Ensure claims transformation Assert.Equal("yup", transaction.FindClaimValue("xform")); transaction = await server.SendAsync("https://example.com/tokens", authCookie); @@ -383,21 +554,21 @@ public async Task ReplyPathWillAuthenticateValidAuthorizeCodeAndState(string cla [InlineData(false)] public async Task ReplyPathWillThrowIfCodeIsInvalid(bool redirect) { - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - StateDataFormat = stateFormat, - BackchannelHttpHandler = new TestHttpMessageHandler + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = stateFormat; + o.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { return ReturnJsonResponse(new { Error = "Error" }, HttpStatusCode.BadRequest); } - }, - Events = redirect ? new OAuthEvents() + }; + o.Events = redirect ? new OAuthEvents() { OnRemoteFailure = ctx => { @@ -405,7 +576,7 @@ public async Task ReplyPathWillThrowIfCodeIsInvalid(bool redirect) ctx.HandleResponse(); return Task.FromResult(0); } - } : new OAuthEvents() + } : new OAuthEvents(); }); var properties = new AuthenticationProperties(); var correlationKey = ".xsrf"; @@ -436,20 +607,20 @@ public async Task ReplyPathWillThrowIfCodeIsInvalid(bool redirect) [InlineData(false)] public async Task ReplyPathWillRejectIfAccessTokenIsMissing(bool redirect) { - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - StateDataFormat = stateFormat, - BackchannelHttpHandler = new TestHttpMessageHandler + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = stateFormat; + o.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { return ReturnJsonResponse(new object()); } - }, - Events = redirect ? new OAuthEvents() + }; + o.Events = redirect ? new OAuthEvents() { OnRemoteFailure = ctx => { @@ -457,7 +628,7 @@ public async Task ReplyPathWillRejectIfAccessTokenIsMissing(bool redirect) ctx.HandleResponse(); return Task.FromResult(0); } - } : new OAuthEvents() + } : new OAuthEvents(); }); var properties = new AuthenticationProperties(); var correlationKey = ".xsrf"; @@ -485,13 +656,13 @@ public async Task ReplyPathWillRejectIfAccessTokenIsMissing(bool redirect) [Fact] public async Task AuthenticatedEventCanGetRefreshToken() { - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - StateDataFormat = stateFormat, - BackchannelHttpHandler = new TestHttpMessageHandler + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = stateFormat; + o.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { @@ -530,16 +701,16 @@ public async Task AuthenticatedEventCanGetRefreshToken() throw new NotImplementedException(req.RequestUri.AbsoluteUri); } - }, - Events = new OAuthEvents + }; + o.Events = new OAuthEvents { OnCreatingTicket = context => { var refreshToken = context.RefreshToken; - context.Ticket.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken, ClaimValueTypes.String, "Google") }, "Google")); + context.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken, ClaimValueTypes.String, "Google") }, "Google")); return Task.FromResult(0); } - } + }; }); var properties = new AuthenticationProperties(); var correlationKey = ".xsrf"; @@ -565,13 +736,13 @@ public async Task AuthenticatedEventCanGetRefreshToken() [Fact] public async Task NullRedirectUriWillRedirectToSlash() { - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - StateDataFormat = stateFormat, - BackchannelHttpHandler = new TestHttpMessageHandler + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = stateFormat; + o.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { @@ -610,15 +781,15 @@ public async Task NullRedirectUriWillRedirectToSlash() throw new NotImplementedException(req.RequestUri.AbsoluteUri); } - }, - Events = new OAuthEvents + }; + o.Events = new OAuthEvents { OnTicketReceived = context => { - context.Ticket.Properties.RedirectUri = null; + context.Properties.RedirectUri = null; return Task.FromResult(0); } - } + }; }); var properties = new AuthenticationProperties(); var correlationKey = ".xsrf"; @@ -638,30 +809,30 @@ public async Task NullRedirectUriWillRedirectToSlash() [Fact] public async Task ValidateAuthenticatedContext() { - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - StateDataFormat = stateFormat, - AccessType = "offline", - Events = new OAuthEvents() + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = stateFormat; + o.AccessType = "offline"; + o.Events = new OAuthEvents() { OnCreatingTicket = context => { Assert.NotNull(context.User); - Assert.Equal(context.AccessToken, "Test Access Token"); - Assert.Equal(context.RefreshToken, "Test Refresh Token"); - Assert.Equal(context.ExpiresIn, TimeSpan.FromSeconds(3600)); - Assert.Equal(GoogleHelper.GetEmail(context.User), "Test email"); - Assert.Equal(GoogleHelper.GetId(context.User), "Test User ID"); - Assert.Equal(GoogleHelper.GetName(context.User), "Test Name"); - Assert.Equal(GoogleHelper.GetFamilyName(context.User), "Test Family Name"); - Assert.Equal(GoogleHelper.GetGivenName(context.User), "Test Given Name"); + Assert.Equal("Test Access Token", context.AccessToken); + Assert.Equal("Test Refresh Token", context.RefreshToken); + Assert.Equal(TimeSpan.FromSeconds(3600), context.ExpiresIn); + Assert.Equal("Test email", context.Identity.FindFirst(ClaimTypes.Email)?.Value); + Assert.Equal("Test User ID", context.Identity.FindFirst(ClaimTypes.NameIdentifier)?.Value); + Assert.Equal("Test Name", context.Identity.FindFirst(ClaimTypes.Name)?.Value); + Assert.Equal("Test Family Name", context.Identity.FindFirst(ClaimTypes.Surname)?.Value); + Assert.Equal("Test Given Name", context.Identity.FindFirst(ClaimTypes.GivenName)?.Value); return Task.FromResult(0); } - }, - BackchannelHttpHandler = new TestHttpMessageHandler + }; + o.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { @@ -700,7 +871,7 @@ public async Task ValidateAuthenticatedContext() throw new NotImplementedException(req.RequestUri.AbsoluteUri); } - } + }; }); var properties = new AuthenticationProperties(); @@ -722,10 +893,10 @@ public async Task ValidateAuthenticatedContext() [Fact] public async Task NoStateCausesException() { - var server = CreateServer(new GoogleOptions + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret" + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; }); //Post a message to the Google middleware @@ -736,12 +907,12 @@ public async Task NoStateCausesException() [Fact] public async Task CanRedirectOnError() { - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - Events = new OAuthEvents() + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.Events = new OAuthEvents() { OnRemoteFailure = ctx => { @@ -749,7 +920,7 @@ public async Task CanRedirectOnError() ctx.HandleResponse(); return Task.FromResult(0); } - } + }; }); //Post a message to the Google middleware @@ -764,14 +935,14 @@ public async Task CanRedirectOnError() [Fact] public async Task AuthenticateAutomaticWhenAlreadySignedInSucceeds() { - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - SaveTokens = true, - StateDataFormat = stateFormat, - BackchannelHttpHandler = CreateBackchannel() + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = stateFormat; + o.SaveTokens = true; + o.BackchannelHttpHandler = CreateBackchannel(); }); // Skip the challenge step, go directly to the callback path @@ -807,14 +978,14 @@ public async Task AuthenticateAutomaticWhenAlreadySignedInSucceeds() [Fact] public async Task AuthenticateGoogleWhenAlreadySignedInSucceeds() { - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - SaveTokens = true, - StateDataFormat = stateFormat, - BackchannelHttpHandler = CreateBackchannel() + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = stateFormat; + o.SaveTokens = true; + o.BackchannelHttpHandler = CreateBackchannel(); }); // Skip the challenge step, go directly to the callback path @@ -847,53 +1018,17 @@ public async Task AuthenticateGoogleWhenAlreadySignedInSucceeds() Assert.Equal("yup", transaction.FindClaimValue("xform")); } - [Fact] - public async Task ChallengeGoogleWhenAlreadySignedInReturnsForbidden() - { - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); - var server = CreateServer(new GoogleOptions - { - ClientId = "Test Id", - ClientSecret = "Test Secret", - SaveTokens = true, - StateDataFormat = stateFormat, - BackchannelHttpHandler = CreateBackchannel() - }); - - // Skip the challenge step, go directly to the callback path - - var properties = new AuthenticationProperties(); - var correlationKey = ".xsrf"; - var correlationValue = "TestCorrelationId"; - properties.Items.Add(correlationKey, correlationValue); - properties.RedirectUri = "/me"; - var state = stateFormat.Protect(properties); - var transaction = await server.SendAsync( - "https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state), - $".AspNetCore.Correlation.Google.{correlationValue}=N"); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); - Assert.Equal(2, transaction.SetCookie.Count); - Assert.Contains($".AspNetCore.Correlation.Google.{correlationValue}", transaction.SetCookie[0]); // Delete - Assert.Contains(".AspNetCore." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]); - - var authCookie = transaction.AuthenticationCookieValue; - transaction = await server.SendAsync("https://example.com/challenge", authCookie); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - Assert.StartsWith("https://example.com/Account/AccessDenied?", transaction.Response.Headers.Location.OriginalString); - } - [Fact] public async Task AuthenticateFacebookWhenAlreadySignedWithGoogleReturnsNull() { - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - SaveTokens = true, - StateDataFormat = stateFormat, - BackchannelHttpHandler = CreateBackchannel() + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = stateFormat; + o.SaveTokens = true; + o.BackchannelHttpHandler = CreateBackchannel(); }); // Skip the challenge step, go directly to the callback path @@ -916,20 +1051,20 @@ public async Task AuthenticateFacebookWhenAlreadySignedWithGoogleReturnsNull() var authCookie = transaction.AuthenticationCookieValue; transaction = await server.SendAsync("https://example.com/authenticateFacebook", authCookie); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); - Assert.Equal(null, transaction.FindClaimValue(ClaimTypes.Name)); + Assert.Null(transaction.FindClaimValue(ClaimTypes.Name)); } [Fact] public async Task ChallengeFacebookWhenAlreadySignedWithGoogleSucceeds() { - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest")); - var server = CreateServer(new GoogleOptions + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest")); + var server = CreateServer(o => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - SaveTokens = true, - StateDataFormat = stateFormat, - BackchannelHttpHandler = CreateBackchannel() + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.StateDataFormat = stateFormat; + o.SaveTokens = true; + o.BackchannelHttpHandler = CreateBackchannel(); }); // Skip the challenge step, go directly to the callback path @@ -1006,46 +1141,42 @@ private static HttpResponseMessage ReturnJsonResponse(object content, HttpStatus return res; } - private static TestServer CreateServer(GoogleOptions options, Func testpath = null) + private class ClaimsTransformer : IClaimsTransformation + { + public Task TransformAsync(ClaimsPrincipal p) + { + if (!p.Identities.Any(i => i.AuthenticationType == "xform")) + { + var id = new ClaimsIdentity("xform"); + id.AddClaim(new Claim("xform", "yup")); + p.AddIdentity(id); + } + return Task.FromResult(p); + } + } + + private static TestServer CreateServer(Action configureOptions, Func testpath = null) { var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - AuthenticationScheme = TestExtensions.CookieAuthenticationScheme, - AutomaticAuthenticate = true - }); - app.UseGoogleAuthentication(options); - app.UseFacebookAuthentication(new FacebookOptions() - { - AppId = "Test AppId", - AppSecret = "Test AppSecrent", - }); - app.UseClaimsTransformation(context => - { - var id = new ClaimsIdentity("xform"); - id.AddClaim(new Claim("xform", "yup")); - context.Principal.AddIdentity(id); - return Task.FromResult(context.Principal); - }); + app.UseAuthentication(); app.Use(async (context, next) => { var req = context.Request; var res = context.Response; if (req.Path == new PathString("/challenge")) { - await context.Authentication.ChallengeAsync("Google"); + await context.ChallengeAsync(); } else if (req.Path == new PathString("/challengeFacebook")) { - await context.Authentication.ChallengeAsync("Facebook"); + await context.ChallengeAsync("Facebook"); } else if (req.Path == new PathString("/tokens")) { - var authContext = new AuthenticateContext(TestExtensions.CookieAuthenticationScheme); - await context.Authentication.AuthenticateAsync(authContext); - var tokens = new AuthenticationProperties(authContext.Properties).GetTokens(); + var result = await context.AuthenticateAsync(TestExtensions.CookieAuthenticationScheme); + var tokens = result.Properties.GetTokens(); res.Describe(tokens); } else if (req.Path == new PathString("/me")) @@ -1054,29 +1185,29 @@ private static TestServer CreateServer(GoogleOptions options, Func(() => context.Authentication.SignInAsync("Google", new ClaimsPrincipal())); + await Assert.ThrowsAsync(() => context.SignInAsync("Google", new ClaimsPrincipal())); } else if (req.Path == new PathString("/signOut")) { - await Assert.ThrowsAsync(() => context.Authentication.SignOutAsync("Google")); + await Assert.ThrowsAsync(() => context.SignOutAsync("Google")); } else if (req.Path == new PathString("/forbid")) { - await Assert.ThrowsAsync(() => context.Authentication.ForbidAsync("Google")); + await Assert.ThrowsAsync(() => context.ForbidAsync("Google")); } else if (testpath != null) { @@ -1106,9 +1237,49 @@ private static TestServer CreateServer(GoogleOptions options, Func { - services.AddAuthentication(authOptions => authOptions.SignInScheme = TestExtensions.CookieAuthenticationScheme); + services.AddTransient(); + services.AddAuthentication(TestExtensions.CookieAuthenticationScheme) + .AddCookie(TestExtensions.CookieAuthenticationScheme, o => o.ForwardChallenge = GoogleDefaults.AuthenticationScheme) + .AddGoogle(configureOptions) + .AddFacebook(o => + { + o.ClientId = "Test ClientId"; + o.ClientSecret = "Test AppSecrent"; + }); }); return new TestServer(builder); } + + private class TestStateDataFormat : ISecureDataFormat + { + private AuthenticationProperties Data { get; set; } + + public string Protect(AuthenticationProperties data) + { + return "protected_state"; + } + + public string Protect(AuthenticationProperties data, string purpose) + { + throw new NotImplementedException(); + } + + public AuthenticationProperties Unprotect(string protectedText) + { + Assert.Equal("protected_state", protectedText); + var properties = new AuthenticationProperties(new Dictionary() + { + { ".xsrf", "correlationId" }, + { "testkey", "testvalue" } + }); + properties.RedirectUri = "http://testhost/redirect"; + return properties; + } + + public AuthenticationProperties Unprotect(string protectedText, string purpose) + { + throw new NotImplementedException(); + } + } } } diff --git a/test/Microsoft.AspNetCore.Authentication.Test/JwtBearer/JwtBearerMiddlewareTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/JwtBearerTests.cs similarity index 67% rename from test/Microsoft.AspNetCore.Authentication.Test/JwtBearer/JwtBearerMiddlewareTests.cs rename to test/Microsoft.AspNetCore.Authentication.Test/JwtBearerTests.cs index c0d2ddba5..ad77803cd 100644 --- a/test/Microsoft.AspNetCore.Authentication.Test/JwtBearer/JwtBearerMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Authentication.Test/JwtBearerTests.cs @@ -1,7 +1,14 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; using System; +using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Net; using System.Net.Http; @@ -10,43 +17,106 @@ using System.Text; using System.Threading.Tasks; using System.Xml.Linq; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.Http.Features.Authentication; -using Microsoft.AspNetCore.TestHost; -using Microsoft.AspNetCore.Testing.xunit; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.IdentityModel.Tokens; using Xunit; namespace Microsoft.AspNetCore.Authentication.JwtBearer { - public class JwtBearerMiddlewareTests + public class JwtBearerTests : SharedAuthenticationTests { - [ConditionalFact(Skip = "Need to remove dependency on AAD since the generated tokens will expire")] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - // https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/179 + protected override string DefaultScheme => JwtBearerDefaults.AuthenticationScheme; + protected override Type HandlerType => typeof(JwtBearerHandler); + protected override bool SupportsSignIn { get => false; } + protected override bool SupportsSignOut { get => false; } + + protected override void RegisterAuth(AuthenticationBuilder services, Action configure) + { + services.AddJwtBearer(o => + { + ConfigureDefaults(o); + configure.Invoke(o); + }); + } + + private void ConfigureDefaults(JwtBearerOptions o) + { + } + + [Fact] public async Task BearerTokenValidation() { - var options = new JwtBearerOptions + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(new string('a', 128))); + var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); + + var claims = new[] { - Authority = "https://login.windows.net/tushartest.onmicrosoft.com", - Audience = "https://TusharTest.onmicrosoft.com/TodoListService-ManualJwt" + new Claim(ClaimTypes.NameIdentifier, "Bob") }; - options.TokenValidationParameters.ValidateLifetime = false; - var server = CreateServer(options); - var newBearerToken = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImtyaU1QZG1Cdng2OHNrVDgtbVBBQjNCc2VlQSJ9.eyJhdWQiOiJodHRwczovL1R1c2hhclRlc3Qub25taWNyb3NvZnQuY29tL1RvZG9MaXN0U2VydmljZS1NYW51YWxKd3QiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9hZmJlY2UwMy1hZWFhLTRmM2YtODVlNy1jZTA4ZGQyMGNlNTAvIiwiaWF0IjoxNDE4MzMwNjE0LCJuYmYiOjE0MTgzMzA2MTQsImV4cCI6MTQxODMzNDUxNCwidmVyIjoiMS4wIiwidGlkIjoiYWZiZWNlMDMtYWVhYS00ZjNmLTg1ZTctY2UwOGRkMjBjZTUwIiwiYW1yIjpbInB3ZCJdLCJvaWQiOiI1Mzk3OTdjMi00MDE5LTQ2NTktOWRiNS03MmM0Yzc3NzhhMzMiLCJ1cG4iOiJWaWN0b3JAVHVzaGFyVGVzdC5vbm1pY3Jvc29mdC5jb20iLCJ1bmlxdWVfbmFtZSI6IlZpY3RvckBUdXNoYXJUZXN0Lm9ubWljcm9zb2Z0LmNvbSIsInN1YiI6IkQyMm9aMW9VTzEzTUFiQXZrdnFyd2REVE80WXZJdjlzMV9GNWlVOVUwYnciLCJmYW1pbHlfbmFtZSI6Ikd1cHRhIiwiZ2l2ZW5fbmFtZSI6IlZpY3RvciIsImFwcGlkIjoiNjEzYjVhZjgtZjJjMy00MWI2LWExZGMtNDE2Yzk3ODAzMGI3IiwiYXBwaWRhY3IiOiIwIiwic2NwIjoidXNlcl9pbXBlcnNvbmF0aW9uIiwiYWNyIjoiMSJ9.N_Kw1EhoVGrHbE6hOcm7ERdZ7paBQiNdObvp2c6T6n5CE8p0fZqmUd-ya_EqwElcD6SiKSiP7gj0gpNUnOJcBl_H2X8GseaeeMxBrZdsnDL8qecc6_ygHruwlPltnLTdka67s1Ow4fDSHaqhVTEk6lzGmNEcbNAyb0CxQxU6o7Fh0yHRiWoLsT8yqYk8nKzsHXfZBNby4aRo3_hXaa4i0SZLYfDGGYPdttG4vT_u54QGGd4Wzbonv2gjDlllOVGOwoJS6kfl1h8mk0qxdiIaT_ChbDWgkWvTB7bTvBE-EgHgV0XmAo0WtJeSxgjsG3KhhEPsONmqrSjhIUV4IVnF2w"; + var token = new JwtSecurityToken( + issuer: "issuer.contoso.com", + audience: "audience.contoso.com", + claims: claims, + expires: DateTime.Now.AddMinutes(30), + signingCredentials: creds); + + var tokenText = new JwtSecurityTokenHandler().WriteToken(token); + + var server = CreateServer(o => + { + o.TokenValidationParameters = new TokenValidationParameters() + { + ValidIssuer = "issuer.contoso.com", + ValidAudience = "audience.contoso.com", + IssuerSigningKey = key, + }; + }); + + var newBearerToken = "Bearer " + tokenText; var response = await SendAsync(server, "http://example.com/oauth", newBearerToken); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); } + [Fact] + public async Task SaveBearerToken() + { + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(new string('a', 128))); + var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); + + var claims = new[] + { + new Claim(ClaimTypes.NameIdentifier, "Bob") + }; + + var token = new JwtSecurityToken( + issuer: "issuer.contoso.com", + audience: "audience.contoso.com", + claims: claims, + expires: DateTime.Now.AddMinutes(30), + signingCredentials: creds); + + var tokenText = new JwtSecurityTokenHandler().WriteToken(token); + + var server = CreateServer(o => + { + o.SaveToken = true; + o.TokenValidationParameters = new TokenValidationParameters() + { + ValidIssuer = "issuer.contoso.com", + ValidAudience = "audience.contoso.com", + IssuerSigningKey = key, + }; + }); + + var newBearerToken = "Bearer " + tokenText; + var response = await SendAsync(server, "http://example.com/token", newBearerToken); + Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); + Assert.Equal(tokenText, await response.Response.Content.ReadAsStringAsync()); + } + [Fact] public async Task SignInThrows() { - var server = CreateServer(new JwtBearerOptions()); + var server = CreateServer(); var transaction = await server.SendAsync("https://example.com/signIn"); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); } @@ -54,7 +124,7 @@ public async Task SignInThrows() [Fact] public async Task SignOutThrows() { - var server = CreateServer(new JwtBearerOptions()); + var server = CreateServer(); var transaction = await server.SendAsync("https://example.com/signOut"); Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); } @@ -62,9 +132,9 @@ public async Task SignOutThrows() [Fact] public async Task ThrowAtAuthenticationFailedEvent() { - var options = new JwtBearerOptions + var server = CreateServer(o => { - Events = new JwtBearerEvents + o.Events = new JwtBearerEvents { OnAuthenticationFailed = context => { @@ -76,12 +146,11 @@ public async Task ThrowAtAuthenticationFailedEvent() context.Token = "something"; return Task.FromResult(0); } - } - }; - options.SecurityTokenValidators.Clear(); - options.SecurityTokenValidators.Insert(0, new InvalidTokenValidator()); - - var server = CreateServer(options, async (context, next) => + }; + o.SecurityTokenValidators.Clear(); + o.SecurityTokenValidators.Insert(0, new InvalidTokenValidator()); + }, + async (context, next) => { try { @@ -103,9 +172,9 @@ public async Task ThrowAtAuthenticationFailedEvent() [Fact] public async Task CustomHeaderReceived() { - var server = CreateServer(new JwtBearerOptions + var server = CreateServer(o => { - Events = new JwtBearerEvents() + o.Events = new JwtBearerEvents() { OnMessageReceived = context => { @@ -116,15 +185,12 @@ public async Task CustomHeaderReceived() new Claim(ClaimsIdentity.DefaultNameClaimType, "bob") }; - context.Ticket = new AuthenticationTicket( - new ClaimsPrincipal(new ClaimsIdentity(claims, context.Options.AuthenticationScheme)), - new AuthenticationProperties(), context.Options.AuthenticationScheme); - - context.HandleResponse(); + context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name)); + context.Success(); return Task.FromResult(null); } - } + }; }); var response = await SendAsync(server, "http://example.com/oauth", "someHeader someblob"); @@ -135,7 +201,7 @@ public async Task CustomHeaderReceived() [Fact] public async Task NoHeaderReceived() { - var server = CreateServer(new JwtBearerOptions()); + var server = CreateServer(); var response = await SendAsync(server, "http://example.com/oauth"); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); } @@ -143,7 +209,7 @@ public async Task NoHeaderReceived() [Fact] public async Task HeaderWithoutBearerReceived() { - var server = CreateServer(new JwtBearerOptions()); + var server = CreateServer(); var response = await SendAsync(server, "http://example.com/oauth", "Token"); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); } @@ -151,8 +217,7 @@ public async Task HeaderWithoutBearerReceived() [Fact] public async Task UnrecognizedTokenReceived() { - var server = CreateServer(new JwtBearerOptions()); - + var server = CreateServer(); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); Assert.Equal("", response.ResponseText); @@ -161,10 +226,11 @@ public async Task UnrecognizedTokenReceived() [Fact] public async Task InvalidTokenReceived() { - var options = new JwtBearerOptions(); - options.SecurityTokenValidators.Clear(); - options.SecurityTokenValidators.Add(new InvalidTokenValidator()); - var server = CreateServer(options); + var server = CreateServer(options => + { + options.SecurityTokenValidators.Clear(); + options.SecurityTokenValidators.Add(new InvalidTokenValidator()); + }); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); @@ -183,10 +249,11 @@ public async Task InvalidTokenReceived() [InlineData(typeof(SecurityTokenSignatureKeyNotFoundException), "The signature key was not found")] public async Task ExceptionReportedInHeaderForAuthenticationFailures(Type errorType, string message) { - var options = new JwtBearerOptions(); - options.SecurityTokenValidators.Clear(); - options.SecurityTokenValidators.Add(new InvalidTokenValidator(errorType)); - var server = CreateServer(options); + var server = CreateServer(options => + { + options.SecurityTokenValidators.Clear(); + options.SecurityTokenValidators.Add(new InvalidTokenValidator(errorType)); + }); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); @@ -198,10 +265,11 @@ public async Task ExceptionReportedInHeaderForAuthenticationFailures(Type errorT [InlineData(typeof(ArgumentException))] public async Task ExceptionNotReportedInHeaderForOtherFailures(Type errorType) { - var options = new JwtBearerOptions(); - options.SecurityTokenValidators.Clear(); - options.SecurityTokenValidators.Add(new InvalidTokenValidator(errorType)); - var server = CreateServer(options); + var server = CreateServer(options => + { + options.SecurityTokenValidators.Clear(); + options.SecurityTokenValidators.Add(new InvalidTokenValidator(errorType)); + }); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); @@ -212,11 +280,12 @@ public async Task ExceptionNotReportedInHeaderForOtherFailures(Type errorType) [Fact] public async Task ExceptionsReportedInHeaderForMultipleAuthenticationFailures() { - var options = new JwtBearerOptions(); - options.SecurityTokenValidators.Clear(); - options.SecurityTokenValidators.Add(new InvalidTokenValidator(typeof(SecurityTokenInvalidAudienceException))); - options.SecurityTokenValidators.Add(new InvalidTokenValidator(typeof(SecurityTokenSignatureKeyNotFoundException))); - var server = CreateServer(options); + var server = CreateServer(options => + { + options.SecurityTokenValidators.Clear(); + options.SecurityTokenValidators.Add(new InvalidTokenValidator(typeof(SecurityTokenInvalidAudienceException))); + options.SecurityTokenValidators.Add(new InvalidTokenValidator(typeof(SecurityTokenSignatureKeyNotFoundException))); + }); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); @@ -234,9 +303,9 @@ public async Task ExceptionsReportedInHeaderForMultipleAuthenticationFailures() [InlineData(null, null, "custom_uri")] public async Task ExceptionsReportedInHeaderExposesUserDefinedError(string error, string description, string uri) { - var options = new JwtBearerOptions + var server = CreateServer(options => { - Events = new JwtBearerEvents + options.Events = new JwtBearerEvents { OnChallenge = context => { @@ -246,15 +315,14 @@ public async Task ExceptionsReportedInHeaderExposesUserDefinedError(string error return Task.FromResult(0); } - } - }; - var server = CreateServer(options); + }; + }); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); Assert.Equal("", response.ResponseText); - var builder = new StringBuilder(options.Challenge); + var builder = new StringBuilder(JwtBearerDefaults.AuthenticationScheme); if (!string.IsNullOrEmpty(error)) { @@ -292,9 +360,9 @@ public async Task ExceptionsReportedInHeaderExposesUserDefinedError(string error [Fact] public async Task ExceptionNotReportedInHeaderWhenIncludeErrorDetailsIsFalse() { - var server = CreateServer(new JwtBearerOptions + var server = CreateServer(o => { - IncludeErrorDetails = false + o.IncludeErrorDetails = false; }); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); @@ -306,7 +374,7 @@ public async Task ExceptionNotReportedInHeaderWhenIncludeErrorDetailsIsFalse() [Fact] public async Task ExceptionNotReportedInHeaderWhenTokenWasMissing() { - var server = CreateServer(new JwtBearerOptions()); + var server = CreateServer(); var response = await SendAsync(server, "http://example.com/oauth"); Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); @@ -317,15 +385,15 @@ public async Task ExceptionNotReportedInHeaderWhenTokenWasMissing() [Fact] public async Task CustomTokenValidated() { - var options = new JwtBearerOptions + var server = CreateServer(options => { - Events = new JwtBearerEvents() + options.Events = new JwtBearerEvents() { OnTokenValidated = context => { // Retrieve the NameIdentifier claim from the identity // returned by the custom security token validator. - var identity = (ClaimsIdentity)context.Ticket.Principal.Identity; + var identity = (ClaimsIdentity)context.Principal.Identity; var identifier = identity.FindFirst(ClaimTypes.NameIdentifier); Assert.Equal("Bob le Tout Puissant", identifier.Value); @@ -339,11 +407,10 @@ public async Task CustomTokenValidated() return Task.FromResult(null); } - } - }; - options.SecurityTokenValidators.Clear(); - options.SecurityTokenValidators.Add(new BlobTokenValidator(options.AuthenticationScheme)); - var server = CreateServer(options); + }; + options.SecurityTokenValidators.Clear(); + options.SecurityTokenValidators.Add(new BlobTokenValidator(JwtBearerDefaults.AuthenticationScheme)); + }); var response = await SendAsync(server, "http://example.com/oauth", "Bearer someblob"); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); @@ -353,23 +420,22 @@ public async Task CustomTokenValidated() [Fact] public async Task RetrievingTokenFromAlternateLocation() { - var options = new JwtBearerOptions() + var server = CreateServer(options => { - Events = new JwtBearerEvents() + options.Events = new JwtBearerEvents() { OnMessageReceived = context => { context.Token = "CustomToken"; return Task.FromResult(null); } - } - }; - options.SecurityTokenValidators.Clear(); - options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT", token => - { - Assert.Equal("CustomToken", token); - })); - var server = CreateServer(options); + }; + options.SecurityTokenValidators.Clear(); + options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT", token => + { + Assert.Equal("CustomToken", token); + })); + }); var response = await SendAsync(server, "http://example.com/oauth", "Bearer Token"); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); @@ -377,36 +443,15 @@ public async Task RetrievingTokenFromAlternateLocation() } [Fact] - public async Task BearerTurns401To403IfAuthenticated() + public async Task EventOnMessageReceivedSkip_NoMoreEventsExecuted() { - var options = new JwtBearerOptions(); - options.SecurityTokenValidators.Clear(); - options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT")); - var server = CreateServer(options); - - var response = await SendAsync(server, "http://example.com/unauthorized", "Bearer Token"); - Assert.Equal(HttpStatusCode.Forbidden, response.Response.StatusCode); - } - - [Fact] - public async Task BearerDoesNothingTo401IfNotAuthenticated() - { - var server = CreateServer(new JwtBearerOptions()); - - var response = await SendAsync(server, "http://example.com/unauthorized"); - Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode); - } - - [Fact] - public async Task EventOnMessageReceivedSkipped_NoMoreEventsExecuted() - { - var server = CreateServer(new JwtBearerOptions + var server = CreateServer(options => { - Events = new JwtBearerEvents() + options.Events = new JwtBearerEvents() { OnMessageReceived = context => { - context.SkipToNextMiddleware(); + context.NoResult(); return Task.FromResult(0); }, OnTokenValidated = context => @@ -421,7 +466,7 @@ public async Task EventOnMessageReceivedSkipped_NoMoreEventsExecuted() { throw new NotImplementedException(); }, - } + }; }); var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); @@ -430,15 +475,15 @@ public async Task EventOnMessageReceivedSkipped_NoMoreEventsExecuted() } [Fact] - public async Task EventOnMessageReceivedHandled_NoMoreEventsExecuted() + public async Task EventOnMessageReceivedReject_NoMoreEventsExecuted() { - var server = CreateServer(new JwtBearerOptions + var server = CreateServer(options => { - Events = new JwtBearerEvents() + options.Events = new JwtBearerEvents() { OnMessageReceived = context => { - context.HandleResponse(); + context.Fail("Authentication was aborted from user code."); context.Response.StatusCode = StatusCodes.Status202Accepted; return Task.FromResult(0); }, @@ -454,24 +499,27 @@ public async Task EventOnMessageReceivedHandled_NoMoreEventsExecuted() { throw new NotImplementedException(); }, - } + }; }); - var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); - Assert.Equal(HttpStatusCode.Accepted, response.Response.StatusCode); - Assert.Equal(string.Empty, response.ResponseText); + var exception = await Assert.ThrowsAsync(delegate + { + return SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); + }); + + Assert.Equal("Authentication was aborted from user code.", exception.InnerException.Message); } [Fact] - public async Task EventOnTokenValidatedSkipped_NoMoreEventsExecuted() + public async Task EventOnTokenValidatedSkip_NoMoreEventsExecuted() { - var options = new JwtBearerOptions + var server = CreateServer(options => { - Events = new JwtBearerEvents() + options.Events = new JwtBearerEvents() { OnTokenValidated = context => { - context.SkipToNextMiddleware(); + context.NoResult(); return Task.FromResult(0); }, OnAuthenticationFailed = context => @@ -482,11 +530,10 @@ public async Task EventOnTokenValidatedSkipped_NoMoreEventsExecuted() { throw new NotImplementedException(); }, - } - }; - options.SecurityTokenValidators.Clear(); - options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT")); - var server = CreateServer(options); + }; + options.SecurityTokenValidators.Clear(); + options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT")); + }); var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); @@ -494,15 +541,15 @@ public async Task EventOnTokenValidatedSkipped_NoMoreEventsExecuted() } [Fact] - public async Task EventOnTokenValidatedHandled_NoMoreEventsExecuted() + public async Task EventOnTokenValidatedReject_NoMoreEventsExecuted() { - var options = new JwtBearerOptions + var server = CreateServer(options => { - Events = new JwtBearerEvents() + options.Events = new JwtBearerEvents() { OnTokenValidated = context => { - context.HandleResponse(); + context.Fail("Authentication was aborted from user code."); context.Response.StatusCode = StatusCodes.Status202Accepted; return Task.FromResult(0); }, @@ -514,23 +561,25 @@ public async Task EventOnTokenValidatedHandled_NoMoreEventsExecuted() { throw new NotImplementedException(); }, - } - }; - options.SecurityTokenValidators.Clear(); - options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT")); - var server = CreateServer(options); + }; + options.SecurityTokenValidators.Clear(); + options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT")); + }); - var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); - Assert.Equal(HttpStatusCode.Accepted, response.Response.StatusCode); - Assert.Equal(string.Empty, response.ResponseText); + var exception = await Assert.ThrowsAsync(delegate + { + return SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); + }); + + Assert.Equal("Authentication was aborted from user code.", exception.InnerException.Message); } [Fact] - public async Task EventOnAuthenticationFailedSkipped_NoMoreEventsExecuted() + public async Task EventOnAuthenticationFailedSkip_NoMoreEventsExecuted() { - var options = new JwtBearerOptions + var server = CreateServer(options => { - Events = new JwtBearerEvents() + options.Events = new JwtBearerEvents() { OnTokenValidated = context => { @@ -538,18 +587,17 @@ public async Task EventOnAuthenticationFailedSkipped_NoMoreEventsExecuted() }, OnAuthenticationFailed = context => { - context.SkipToNextMiddleware(); + context.NoResult(); return Task.FromResult(0); }, OnChallenge = context => { throw new NotImplementedException(); }, - } - }; - options.SecurityTokenValidators.Clear(); - options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT")); - var server = CreateServer(options); + }; + options.SecurityTokenValidators.Clear(); + options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT")); + }); var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); @@ -557,11 +605,11 @@ public async Task EventOnAuthenticationFailedSkipped_NoMoreEventsExecuted() } [Fact] - public async Task EventOnAuthenticationFailedHandled_NoMoreEventsExecuted() + public async Task EventOnAuthenticationFailedReject_NoMoreEventsExecuted() { - var options = new JwtBearerOptions + var server = CreateServer(options => { - Events = new JwtBearerEvents() + options.Events = new JwtBearerEvents() { OnTokenValidated = context => { @@ -569,7 +617,7 @@ public async Task EventOnAuthenticationFailedHandled_NoMoreEventsExecuted() }, OnAuthenticationFailed = context => { - context.HandleResponse(); + context.Fail("Authentication was aborted from user code."); context.Response.StatusCode = StatusCodes.Status202Accepted; return Task.FromResult(0); }, @@ -577,56 +625,36 @@ public async Task EventOnAuthenticationFailedHandled_NoMoreEventsExecuted() { throw new NotImplementedException(); }, - } - }; - options.SecurityTokenValidators.Clear(); - options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT")); - var server = CreateServer(options); - - var response = await SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); - Assert.Equal(HttpStatusCode.Accepted, response.Response.StatusCode); - Assert.Equal(string.Empty, response.ResponseText); - } + }; + options.SecurityTokenValidators.Clear(); + options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT")); + }); - [Fact] - public async Task EventOnChallengeSkipped_ResponseNotModified() - { - var server = CreateServer(new JwtBearerOptions + var exception = await Assert.ThrowsAsync(delegate { - Events = new JwtBearerEvents() - { - OnChallenge = context => - { - context.SkipToNextMiddleware(); - return Task.FromResult(0); - }, - } + return SendAsync(server, "http://example.com/checkforerrors", "Bearer Token"); }); - var response = await SendAsync(server, "http://example.com/unauthorized", "Bearer Token"); - Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); - Assert.Empty(response.Response.Headers.WwwAuthenticate); - Assert.Equal(string.Empty, response.ResponseText); + Assert.Equal("Authentication was aborted from user code.", exception.InnerException.Message); } [Fact] - public async Task EventOnChallengeHandled_ResponseNotModified() + public async Task EventOnChallengeSkip_ResponseNotModified() { - var server = CreateServer(new JwtBearerOptions + var server = CreateServer(o => { - Events = new JwtBearerEvents() + o.Events = new JwtBearerEvents() { OnChallenge = context => { context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; return Task.FromResult(0); }, - } + }; }); var response = await SendAsync(server, "http://example.com/unauthorized", "Bearer Token"); - Assert.Equal(HttpStatusCode.Accepted, response.Response.StatusCode); + Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode); Assert.Empty(response.Response.Headers.WwwAuthenticate); Assert.Equal(string.Empty, response.ResponseText); } @@ -699,10 +727,7 @@ public int MaximumTokenSizeInBytes public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken) { validatedToken = null; - if (_tokenValidator != null) - { - _tokenValidator(securityToken); - } + _tokenValidator?.Invoke(securityToken); var claims = new[] { @@ -717,12 +742,7 @@ public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParame } } - private static TestServer CreateServer(JwtBearerOptions options) - { - return CreateServer(options, handlerBeforeAuth: null); - } - - private static TestServer CreateServer(JwtBearerOptions options, Func, Task> handlerBeforeAuth) + private static TestServer CreateServer(Action options = null, Func, Task> handlerBeforeAuth = null) { var builder = new WebHostBuilder() .Configure(app => @@ -732,20 +752,15 @@ private static TestServer CreateServer(JwtBearerOptions options, Func { if (context.Request.Path == new PathString("/checkforerrors")) { - var authContext = new AuthenticateContext(Http.Authentication.AuthenticationManager.AutomaticScheme); - await context.Authentication.AuthenticateAsync(authContext); - if (authContext.Error != null) + var result = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme); // this used to be "Automatic" + if (result.Failure != null) { - throw new Exception("Failed to authenticate", authContext.Error); + throw new Exception("Failed to authenticate", result.Failure); } return; } @@ -756,7 +771,8 @@ private static TestServer CreateServer(JwtBearerOptions options, Func(() => context.Authentication.SignInAsync(JwtBearerDefaults.AuthenticationScheme, new ClaimsPrincipal())); + await Assert.ThrowsAsync(() => context.SignInAsync(JwtBearerDefaults.AuthenticationScheme, new ClaimsPrincipal())); } else if (context.Request.Path == new PathString("/signOut")) { - await Assert.ThrowsAsync(() => context.Authentication.SignOutAsync(JwtBearerDefaults.AuthenticationScheme)); + await Assert.ThrowsAsync(() => context.SignOutAsync(JwtBearerDefaults.AuthenticationScheme)); } else { @@ -790,7 +810,7 @@ private static TestServer CreateServer(JwtBearerOptions options, Func services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options)); return new TestServer(builder); } diff --git a/test/Microsoft.AspNetCore.Authentication.Test/Microsoft.AspNetCore.Authentication.Test.csproj b/test/Microsoft.AspNetCore.Authentication.Test/Microsoft.AspNetCore.Authentication.Test.csproj new file mode 100644 index 000000000..c7a380868 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/Microsoft.AspNetCore.Authentication.Test.csproj @@ -0,0 +1,47 @@ + + + + netcoreapp3.0 + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Authentication.Test/Microsoft.AspNetCore.Authentication.Test.xproj b/test/Microsoft.AspNetCore.Authentication.Test/Microsoft.AspNetCore.Authentication.Test.xproj deleted file mode 100644 index 1050a47ad..000000000 --- a/test/Microsoft.AspNetCore.Authentication.Test/Microsoft.AspNetCore.Authentication.Test.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 8da26cd1-1302-4cfd-9270-9fa1b7c6138b - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authentication.Test/MicrosoftAccount/MicrosoftAccountMiddlewareTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/MicrosoftAccount/MicrosoftAccountMiddlewareTests.cs deleted file mode 100644 index 0ddfb5a3c..000000000 --- a/test/Microsoft.AspNetCore.Authentication.Test/MicrosoftAccount/MicrosoftAccountMiddlewareTests.cs +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Security.Claims; -using System.Text; -using System.Text.Encodings.Web; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication.OAuth; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.DataProtection; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; -using Xunit; - -namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount -{ - public class MicrosoftAccountMiddlewareTests - { - [Fact] - public async Task ChallengeWillTriggerApplyRedirectEvent() - { - var server = CreateServer(new MicrosoftAccountOptions - { - ClientId = "Test Client Id", - ClientSecret = "Test Client Secret", - Events = new OAuthEvents - { - OnRedirectToAuthorizationEndpoint = context => - { - context.Response.Redirect(context.RedirectUri + "&custom=test"); - return Task.FromResult(0); - } - } - }); - var transaction = await server.SendAsync("http://example.com/challenge"); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - var query = transaction.Response.Headers.Location.Query; - Assert.Contains("custom=test", query); - } - - [Fact] - public async Task SignInThrows() - { - var server = CreateServer(new MicrosoftAccountOptions - { - ClientId = "Test Id", - ClientSecret = "Test Secret" - }); - var transaction = await server.SendAsync("https://example.com/signIn"); - Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); - } - - [Fact] - public async Task SignOutThrows() - { - var server = CreateServer(new MicrosoftAccountOptions - { - ClientId = "Test Id", - ClientSecret = "Test Secret" - }); - var transaction = await server.SendAsync("https://example.com/signOut"); - Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); - } - - [Fact] - public async Task ForbidThrows() - { - var server = CreateServer(new MicrosoftAccountOptions - { - ClientId = "Test Id", - ClientSecret = "Test Secret" - }); - var transaction = await server.SendAsync("https://example.com/signOut"); - Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); - } - - [Fact] - public async Task ChallengeWillTriggerRedirection() - { - var server = CreateServer(new MicrosoftAccountOptions - { - ClientId = "Test Client Id", - ClientSecret = "Test Client Secret" - }); - var transaction = await server.SendAsync("http://example.com/challenge"); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - var location = transaction.Response.Headers.Location.AbsoluteUri; - Assert.Contains("https://login.microsoftonline.com/common/oauth2/v2.0/authorize", location); - Assert.Contains("response_type=code", location); - Assert.Contains("client_id=", location); - Assert.Contains("redirect_uri=", location); - Assert.Contains("scope=", location); - Assert.Contains("state=", location); - } - - [Fact] - public async Task AuthenticatedEventCanGetRefreshToken() - { - var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("MsftTest")); - var server = CreateServer(new MicrosoftAccountOptions - { - ClientId = "Test Client Id", - ClientSecret = "Test Client Secret", - StateDataFormat = stateFormat, - BackchannelHttpHandler = new TestHttpMessageHandler - { - Sender = req => - { - if (req.RequestUri.AbsoluteUri == "https://login.microsoftonline.com/common/oauth2/v2.0/token") - { - return ReturnJsonResponse(new - { - access_token = "Test Access Token", - expire_in = 3600, - token_type = "Bearer", - refresh_token = "Test Refresh Token" - }); - } - else if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == "https://graph.microsoft.com/v1.0/me") - { - return ReturnJsonResponse(new - { - id = "Test User ID", - displayName = "Test Name", - givenName = "Test Given Name", - surname = "Test Family Name", - mail = "Test email" - }); - } - - return null; - } - }, - Events = new OAuthEvents - { - OnCreatingTicket = context => - { - var refreshToken = context.RefreshToken; - context.Ticket.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken, ClaimValueTypes.String, "Microsoft") }, "Microsoft")); - return Task.FromResult(null); - } - } - }); - var properties = new AuthenticationProperties(); - var correlationKey = ".xsrf"; - var correlationValue = "TestCorrelationId"; - properties.Items.Add(correlationKey, correlationValue); - properties.RedirectUri = "/me"; - var state = stateFormat.Protect(properties); - var transaction = await server.SendAsync( - "https://example.com/signin-microsoft?code=TestCode&state=" + UrlEncoder.Default.Encode(state), - $".AspNetCore.Correlation.Microsoft.{correlationValue}=N"); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); - Assert.Equal(2, transaction.SetCookie.Count); - Assert.Contains($".AspNetCore.Correlation.Microsoft.{correlationValue}", transaction.SetCookie[0]); - Assert.Contains(".AspNetCore." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]); - - var authCookie = transaction.AuthenticationCookieValue; - transaction = await server.SendAsync("https://example.com/me", authCookie); - Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); - Assert.Equal("Test Refresh Token", transaction.FindClaimValue("RefreshToken")); - } - - private static TestServer CreateServer(MicrosoftAccountOptions options) - { - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - AuthenticationScheme = TestExtensions.CookieAuthenticationScheme, - AutomaticAuthenticate = true - }); - app.UseMicrosoftAccountAuthentication(options); - - app.Use(async (context, next) => - { - var req = context.Request; - var res = context.Response; - if (req.Path == new PathString("/challenge")) - { - await context.Authentication.ChallengeAsync("Microsoft"); - } - else if (req.Path == new PathString("/me")) - { - res.Describe(context.User); - } - else if (req.Path == new PathString("/signIn")) - { - await Assert.ThrowsAsync(() => context.Authentication.SignInAsync("Microsoft", new ClaimsPrincipal())); - } - else if (req.Path == new PathString("/signOut")) - { - await Assert.ThrowsAsync(() => context.Authentication.SignOutAsync("Microsoft")); - } - else if (req.Path == new PathString("/forbid")) - { - await Assert.ThrowsAsync(() => context.Authentication.ForbidAsync("Microsoft")); - } - else - { - await next(); - } - }); - }) - .ConfigureServices(services => - { - services.AddAuthentication(); - services.Configure(authOptions => - { - authOptions.SignInScheme = TestExtensions.CookieAuthenticationScheme; - }); - }); - return new TestServer(builder); - } - - private static HttpResponseMessage ReturnJsonResponse(object content) - { - var res = new HttpResponseMessage(HttpStatusCode.OK); - var text = JsonConvert.SerializeObject(content); - res.Content = new StringContent(text, Encoding.UTF8, "application/json"); - return res; - } - } -} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/MicrosoftAccountTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/MicrosoftAccountTests.cs new file mode 100644 index 000000000..26a5484c8 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/MicrosoftAccountTests.cs @@ -0,0 +1,310 @@ +// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Authentication.MicrosoftAccount; +using Microsoft.AspNetCore.Authentication.OAuth; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging.Abstractions; +using Newtonsoft.Json; +using System; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Security.Claims; +using System.Text; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount +{ + public class MicrosoftAccountTests : RemoteAuthenticationTests + { + protected override string DefaultScheme => MicrosoftAccountDefaults.AuthenticationScheme; + protected override Type HandlerType => typeof(MicrosoftAccountHandler); + protected override bool SupportsSignIn { get => false; } + protected override bool SupportsSignOut { get => false; } + + protected override void RegisterAuth(AuthenticationBuilder services, Action configure) + { + services.AddMicrosoftAccount(o => + { + ConfigureDefaults(o); + configure.Invoke(o); + }); + } + + protected override void ConfigureDefaults(MicrosoftAccountOptions o) + { + o.ClientId = "whatever"; + o.ClientSecret = "whatever"; + o.SignInScheme = "auth1"; + } + + [Fact] + public async Task ChallengeWillTriggerApplyRedirectEvent() + { + var server = CreateServer(o => + { + o.ClientId = "Test Client Id"; + o.ClientSecret = "Test Client Secret"; + o.Events = new OAuthEvents + { + OnRedirectToAuthorizationEndpoint = context => + { + context.Response.Redirect(context.RedirectUri + "&custom=test"); + return Task.FromResult(0); + } + }; + }); + var transaction = await server.SendAsync("http://example.com/challenge"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + var query = transaction.Response.Headers.Location.Query; + Assert.Contains("custom=test", query); + } + + [Fact] + public async Task SignInThrows() + { + var server = CreateServer(o => + { + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + }); + var transaction = await server.SendAsync("https://example.com/signIn"); + Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); + } + + [Fact] + public async Task SignOutThrows() + { + var server = CreateServer(o => + { + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + }); + var transaction = await server.SendAsync("https://example.com/signOut"); + Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); + } + + [Fact] + public async Task ForbidThrows() + { + var server = CreateServer(o => + { + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + }); + var transaction = await server.SendAsync("https://example.com/signOut"); + Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); + } + + [Fact] + public async Task ChallengeWillTriggerRedirection() + { + var server = CreateServer(o => + { + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + }); + var transaction = await server.SendAsync("http://example.com/challenge"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + var location = transaction.Response.Headers.Location.AbsoluteUri; + Assert.Contains("https://login.microsoftonline.com/common/oauth2/v2.0/authorize", location); + Assert.Contains("response_type=code", location); + Assert.Contains("client_id=", location); + Assert.Contains("redirect_uri=", location); + Assert.Contains("scope=", location); + Assert.Contains("state=", location); + } + + [Fact] + public async Task ChallengeWillIncludeScopeAsConfigured() + { + var server = CreateServer(o => + { + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.Scope.Clear(); + o.Scope.Add("foo"); + o.Scope.Add("bar"); + }); + var transaction = await server.SendAsync("http://example.com/challenge"); + var res = transaction.Response; + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.Contains("scope=foo%20bar", res.Headers.Location.Query); + } + + [Fact] + public async Task ChallengeWillIncludeScopeAsOverwritten() + { + var server = CreateServer(o => + { + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.Scope.Clear(); + o.Scope.Add("foo"); + o.Scope.Add("bar"); + }); + var transaction = await server.SendAsync("http://example.com/challengeWithOtherScope"); + var res = transaction.Response; + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.Contains("scope=baz%20qux", res.Headers.Location.Query); + } + + [Fact] + public async Task ChallengeWillIncludeScopeAsOverwrittenWithBaseAuthenticationProperties() + { + var server = CreateServer(o => + { + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.Scope.Clear(); + o.Scope.Add("foo"); + o.Scope.Add("bar"); + }); + var transaction = await server.SendAsync("http://example.com/challengeWithOtherScopeWithBaseAuthenticationProperties"); + var res = transaction.Response; + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.Contains("scope=baz%20qux", res.Headers.Location.Query); + } + + [Fact] + public async Task AuthenticatedEventCanGetRefreshToken() + { + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("MsftTest")); + var server = CreateServer(o => + { + o.ClientId = "Test Client Id"; + o.ClientSecret = "Test Client Secret"; + o.StateDataFormat = stateFormat; + o.BackchannelHttpHandler = new TestHttpMessageHandler + { + Sender = req => + { + if (req.RequestUri.AbsoluteUri == "https://login.microsoftonline.com/common/oauth2/v2.0/token") + { + return ReturnJsonResponse(new + { + access_token = "Test Access Token", + expire_in = 3600, + token_type = "Bearer", + refresh_token = "Test Refresh Token" + }); + } + else if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == "https://graph.microsoft.com/v1.0/me") + { + return ReturnJsonResponse(new + { + id = "Test User ID", + displayName = "Test Name", + givenName = "Test Given Name", + surname = "Test Family Name", + mail = "Test email" + }); + } + + return null; + } + }; + o.Events = new OAuthEvents + { + OnCreatingTicket = context => + { + var refreshToken = context.RefreshToken; + context.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken, ClaimValueTypes.String, "Microsoft") }, "Microsoft")); + return Task.FromResult(null); + } + }; + }); + var properties = new AuthenticationProperties(); + var correlationKey = ".xsrf"; + var correlationValue = "TestCorrelationId"; + properties.Items.Add(correlationKey, correlationValue); + properties.RedirectUri = "/me"; + var state = stateFormat.Protect(properties); + var transaction = await server.SendAsync( + "https://example.com/signin-microsoft?code=TestCode&state=" + UrlEncoder.Default.Encode(state), + $".AspNetCore.Correlation.Microsoft.{correlationValue}=N"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First()); + Assert.Equal(2, transaction.SetCookie.Count); + Assert.Contains($".AspNetCore.Correlation.Microsoft.{correlationValue}", transaction.SetCookie[0]); + Assert.Contains(".AspNetCore." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]); + + var authCookie = transaction.AuthenticationCookieValue; + transaction = await server.SendAsync("https://example.com/me", authCookie); + Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); + Assert.Equal("Test Refresh Token", transaction.FindClaimValue("RefreshToken")); + } + + private static TestServer CreateServer(Action configureOptions) + { + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseAuthentication(); + app.Use(async (context, next) => + { + var req = context.Request; + var res = context.Response; + if (req.Path == new PathString("/challenge")) + { + await context.ChallengeAsync("Microsoft"); + } + else if (req.Path == new PathString("/challengeWithOtherScope")) + { + var properties = new OAuthChallengeProperties(); + properties.SetScope("baz", "qux"); + await context.ChallengeAsync("Microsoft", properties); + } + else if (req.Path == new PathString("/challengeWithOtherScopeWithBaseAuthenticationProperties")) + { + var properties = new AuthenticationProperties(); + properties.SetParameter(OAuthChallengeProperties.ScopeKey, new string[] { "baz", "qux" }); + await context.ChallengeAsync("Microsoft", properties); + } + else if (req.Path == new PathString("/me")) + { + res.Describe(context.User); + } + else if (req.Path == new PathString("/signIn")) + { + await Assert.ThrowsAsync(() => context.SignInAsync("Microsoft", new ClaimsPrincipal())); + } + else if (req.Path == new PathString("/signOut")) + { + await Assert.ThrowsAsync(() => context.SignOutAsync("Microsoft")); + } + else if (req.Path == new PathString("/forbid")) + { + await Assert.ThrowsAsync(() => context.ForbidAsync("Microsoft")); + } + else + { + await next(); + } + }); + }) + .ConfigureServices(services => + { + services.AddAuthentication(TestExtensions.CookieAuthenticationScheme) + .AddCookie(TestExtensions.CookieAuthenticationScheme, o => { }) + .AddMicrosoftAccount(configureOptions); + }); + return new TestServer(builder); + } + + private static HttpResponseMessage ReturnJsonResponse(object content) + { + var res = new HttpResponseMessage(HttpStatusCode.OK); + var text = JsonConvert.SerializeObject(content); + res.Content = new StringContent(text, Encoding.UTF8, "application/json"); + return res; + } + } +} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OAuthChallengePropertiesTest.cs b/test/Microsoft.AspNetCore.Authentication.Test/OAuthChallengePropertiesTest.cs new file mode 100644 index 000000000..c359bb0e8 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/OAuthChallengePropertiesTest.cs @@ -0,0 +1,149 @@ +using System; +using Microsoft.AspNetCore.Authentication.Google; +using Microsoft.AspNetCore.Authentication.OAuth; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Xunit; + +namespace Microsoft.AspNetCore.Authentication.Test +{ + public class OAuthChallengePropertiesTest + { + [Fact] + public void ScopeProperty() + { + var properties = new OAuthChallengeProperties + { + Scope = new string[] { "foo", "bar" } + }; + Assert.Equal(new string[] { "foo", "bar" }, properties.Scope); + Assert.Equal(new string[] { "foo", "bar" }, properties.Parameters["scope"]); + } + + [Fact] + public void ScopeProperty_NullValue() + { + var properties = new OAuthChallengeProperties(); + properties.Parameters["scope"] = new string[] { "foo", "bar" }; + Assert.Equal(new string[] { "foo", "bar" }, properties.Scope); + + properties.Scope = null; + Assert.Null(properties.Scope); + } + + [Fact] + public void SetScope() + { + var properties = new OAuthChallengeProperties(); + properties.SetScope("foo", "bar"); + Assert.Equal(new string[] { "foo", "bar" }, properties.Scope); + Assert.Equal(new string[] { "foo", "bar" }, properties.Parameters["scope"]); + } + + [Fact] + public void OidcMaxAge() + { + var properties = new OpenIdConnectChallengeProperties() + { + MaxAge = TimeSpan.FromSeconds(200) + }; + Assert.Equal(TimeSpan.FromSeconds(200), properties.MaxAge); + } + + [Fact] + public void OidcMaxAge_NullValue() + { + var properties = new OpenIdConnectChallengeProperties(); + properties.Parameters["max_age"] = TimeSpan.FromSeconds(500); + Assert.Equal(TimeSpan.FromSeconds(500), properties.MaxAge); + + properties.MaxAge = null; + Assert.Null(properties.MaxAge); + } + + [Fact] + public void OidcPrompt() + { + var properties = new OpenIdConnectChallengeProperties() + { + Prompt = "login" + }; + Assert.Equal("login", properties.Prompt); + Assert.Equal("login", properties.Parameters["prompt"]); + } + + [Fact] + public void OidcPrompt_NullValue() + { + var properties = new OpenIdConnectChallengeProperties(); + properties.Parameters["prompt"] = "consent"; + Assert.Equal("consent", properties.Prompt); + + properties.Prompt = null; + Assert.Null(properties.Prompt); + } + + [Fact] + public void GoogleProperties() + { + var properties = new GoogleChallengeProperties() + { + AccessType = "offline", + ApprovalPrompt = "force", + LoginHint = "test@example.com", + Prompt = "login", + }; + Assert.Equal("offline", properties.AccessType); + Assert.Equal("offline", properties.Parameters["access_type"]); + Assert.Equal("force", properties.ApprovalPrompt); + Assert.Equal("force", properties.Parameters["approval_prompt"]); + Assert.Equal("test@example.com", properties.LoginHint); + Assert.Equal("test@example.com", properties.Parameters["login_hint"]); + Assert.Equal("login", properties.Prompt); + Assert.Equal("login", properties.Parameters["prompt"]); + } + + [Fact] + public void GoogleProperties_NullValues() + { + var properties = new GoogleChallengeProperties(); + properties.Parameters["access_type"] = "offline"; + properties.Parameters["approval_prompt"] = "force"; + properties.Parameters["login_hint"] = "test@example.com"; + properties.Parameters["prompt"] = "login"; + Assert.Equal("offline", properties.AccessType); + Assert.Equal("force", properties.ApprovalPrompt); + Assert.Equal("test@example.com", properties.LoginHint); + Assert.Equal("login", properties.Prompt); + + properties.AccessType = null; + Assert.Null(properties.AccessType); + + properties.ApprovalPrompt = null; + Assert.Null(properties.ApprovalPrompt); + + properties.LoginHint = null; + Assert.Null(properties.LoginHint); + + properties.Prompt = null; + Assert.Null(properties.Prompt); + } + + [Fact] + public void GoogleIncludeGrantedScopes() + { + var properties = new GoogleChallengeProperties() + { + IncludeGrantedScopes = true + }; + Assert.True(properties.IncludeGrantedScopes); + Assert.Equal(true, properties.Parameters["include_granted_scopes"]); + + properties.IncludeGrantedScopes = false; + Assert.False(properties.IncludeGrantedScopes); + Assert.Equal(false, properties.Parameters["include_granted_scopes"]); + + properties.IncludeGrantedScopes = null; + Assert.Null(properties.IncludeGrantedScopes); + } + } +} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OAuthTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/OAuthTests.cs new file mode 100644 index 000000000..838798cea --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/OAuthTests.cs @@ -0,0 +1,434 @@ +// 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.Authentication.Cookies; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Authentication.OAuth +{ + public class OAuthTests : RemoteAuthenticationTests + { + protected override string DefaultScheme => OAuthDefaults.DisplayName; + protected override Type HandlerType => typeof(OAuthHandler); + protected override bool SupportsSignIn { get => false; } + protected override bool SupportsSignOut { get => false; } + + protected override void RegisterAuth(AuthenticationBuilder services, Action configure) + { + services.AddOAuth(DefaultScheme, o => + { + ConfigureDefaults(o); + configure.Invoke(o); + }); + } + + [Fact] + public async Task ThrowsIfClientIdMissing() + { + var server = CreateServer( + services => services.AddAuthentication().AddOAuth("weeblie", o => + { + o.SignInScheme = "whatever"; + o.CallbackPath = "/"; + o.ClientSecret = "whatever"; + o.TokenEndpoint = "/"; + o.AuthorizationEndpoint = "/"; + })); + await Assert.ThrowsAsync("ClientId", () => server.SendAsync("http://example.com/")); + } + + [Fact] + public async Task ThrowsIfClientSecretMissing() + { + var server = CreateServer( + services => services.AddAuthentication().AddOAuth("weeblie", o => + { + o.SignInScheme = "whatever"; + o.ClientId = "Whatever;"; + o.CallbackPath = "/"; + o.TokenEndpoint = "/"; + o.AuthorizationEndpoint = "/"; + })); + await Assert.ThrowsAsync("ClientSecret", () => server.SendAsync("http://example.com/")); + } + + [Fact] + public async Task ThrowsIfCallbackPathMissing() + { + var server = CreateServer( + services => services.AddAuthentication().AddOAuth("weeblie", o => + { + o.ClientId = "Whatever;"; + o.ClientSecret = "Whatever;"; + o.TokenEndpoint = "/"; + o.AuthorizationEndpoint = "/"; + o.SignInScheme = "eh"; + })); + await Assert.ThrowsAsync("CallbackPath", () => server.SendAsync("http://example.com/")); + } + + [Fact] + public async Task ThrowsIfTokenEndpointMissing() + { + var server = CreateServer( + services => services.AddAuthentication().AddOAuth("weeblie", o => + { + o.ClientId = "Whatever;"; + o.ClientSecret = "Whatever;"; + o.CallbackPath = "/"; + o.AuthorizationEndpoint = "/"; + o.SignInScheme = "eh"; + })); + await Assert.ThrowsAsync("TokenEndpoint", () => server.SendAsync("http://example.com/")); + } + + [Fact] + public async Task ThrowsIfAuthorizationEndpointMissing() + { + var server = CreateServer( + services => services.AddAuthentication().AddOAuth("weeblie", o => + { + o.ClientId = "Whatever;"; + o.ClientSecret = "Whatever;"; + o.CallbackPath = "/"; + o.TokenEndpoint = "/"; + o.SignInScheme = "eh"; + })); + await Assert.ThrowsAsync("AuthorizationEndpoint", () => server.SendAsync("http://example.com/")); + } + + [Fact] + public async Task RedirectToIdentityProvider_SetsCorrelationIdCookiePath_ToCallBackPath() + { + var server = CreateServer( + s => s.AddAuthentication().AddOAuth( + "Weblie", + opt => + { + ConfigureDefaults(opt); + }), + async ctx => + { + await ctx.ChallengeAsync("Weblie"); + return true; + }); + + var transaction = await server.SendAsync("https://www.example.com/challenge"); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.NotNull(res.Headers.Location); + var setCookie = Assert.Single(res.Headers, h => h.Key == "Set-Cookie"); + var correlation = Assert.Single(setCookie.Value, v => v.StartsWith(".AspNetCore.Correlation.")); + Assert.Contains("path=/oauth-callback", correlation); + } + + [Fact] + public async Task RedirectToAuthorizeEndpoint_CorrelationIdCookieOptions_CanBeOverriden() + { + var server = CreateServer( + s => s.AddAuthentication().AddOAuth( + "Weblie", + opt => + { + ConfigureDefaults(opt); + opt.CorrelationCookie.Path = "/"; + }), + async ctx => + { + await ctx.ChallengeAsync("Weblie"); + return true; + }); + + var transaction = await server.SendAsync("https://www.example.com/challenge"); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.NotNull(res.Headers.Location); + var setCookie = Assert.Single(res.Headers, h => h.Key == "Set-Cookie"); + var correlation = Assert.Single(setCookie.Value, v => v.StartsWith(".AspNetCore.Correlation.")); + Assert.Contains("path=/", correlation); + } + + [Fact] + public async Task RedirectToAuthorizeEndpoint_HasScopeAsConfigured() + { + var server = CreateServer( + s => s.AddAuthentication().AddOAuth( + "Weblie", + opt => + { + ConfigureDefaults(opt); + opt.Scope.Clear(); + opt.Scope.Add("foo"); + opt.Scope.Add("bar"); + }), + async ctx => + { + await ctx.ChallengeAsync("Weblie"); + return true; + }); + + var transaction = await server.SendAsync("https://www.example.com/challenge"); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.Contains("scope=foo%20bar", res.Headers.Location.Query); + } + + [Fact] + public async Task RedirectToAuthorizeEndpoint_HasScopeAsOverwritten() + { + var server = CreateServer( + s => s.AddAuthentication().AddOAuth( + "Weblie", + opt => + { + ConfigureDefaults(opt); + opt.Scope.Clear(); + opt.Scope.Add("foo"); + opt.Scope.Add("bar"); + }), + async ctx => + { + var properties = new OAuthChallengeProperties(); + properties.SetScope("baz", "qux"); + await ctx.ChallengeAsync("Weblie", properties); + return true; + }); + + var transaction = await server.SendAsync("https://www.example.com/challenge"); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.Contains("scope=baz%20qux", res.Headers.Location.Query); + } + + [Fact] + public async Task RedirectToAuthorizeEndpoint_HasScopeAsOverwrittenWithBaseAuthenticationProperties() + { + var server = CreateServer( + s => s.AddAuthentication().AddOAuth( + "Weblie", + opt => + { + ConfigureDefaults(opt); + opt.Scope.Clear(); + opt.Scope.Add("foo"); + opt.Scope.Add("bar"); + }), + async ctx => + { + var properties = new AuthenticationProperties(); + properties.SetParameter(OAuthChallengeProperties.ScopeKey, new string[] { "baz", "qux" }); + await ctx.ChallengeAsync("Weblie", properties); + return true; + }); + + var transaction = await server.SendAsync("https://www.example.com/challenge"); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.Contains("scope=baz%20qux", res.Headers.Location.Query); + } + + protected override void ConfigureDefaults(OAuthOptions o) + { + o.ClientId = "Test Id"; + o.ClientSecret = "secret"; + o.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + o.AuthorizationEndpoint = "https://example.com/provider/login"; + o.TokenEndpoint = "https://example.com/provider/token"; + o.CallbackPath = "/oauth-callback"; + } + + [Fact] + public async Task HandleRequestAsync_RedirectsToAccessDeniedPathWhenExplicitlySet() + { + var server = CreateServer( + s => s.AddAuthentication().AddOAuth( + "Weblie", + opt => + { + opt.ClientId = "Test Id"; + opt.ClientSecret = "secret"; + opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + opt.AuthorizationEndpoint = "https://example.com/provider/login"; + opt.TokenEndpoint = "https://example.com/provider/token"; + opt.CallbackPath = "/oauth-callback"; + opt.AccessDeniedPath = "/access-denied"; + opt.StateDataFormat = new TestStateDataFormat(); + opt.Events.OnRemoteFailure = context => throw new InvalidOperationException("This event should not be called."); + })); + + var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=access_denied&state=protected_state", + ".AspNetCore.Correlation.Weblie.correlationId=N"); + + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + Assert.Equal("/access-denied?ReturnUrl=http%3A%2F%2Ftesthost%2Fredirect", transaction.Response.Headers.Location.ToString()); + } + + [Fact] + public async Task HandleRequestAsync_InvokesAccessDeniedEvent() + { + var server = CreateServer( + s => s.AddAuthentication().AddOAuth( + "Weblie", + opt => + { + opt.ClientId = "Test Id"; + opt.ClientSecret = "secret"; + opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + opt.AuthorizationEndpoint = "https://example.com/provider/login"; + opt.TokenEndpoint = "https://example.com/provider/token"; + opt.CallbackPath = "/oauth-callback"; + opt.StateDataFormat = new TestStateDataFormat(); + opt.Events = new OAuthEvents() + { + OnAccessDenied = context => + { + Assert.Equal("testvalue", context.Properties.Items["testkey"]); + context.Response.StatusCode = StatusCodes.Status406NotAcceptable; + context.HandleResponse(); + return Task.CompletedTask; + } + }; + })); + + var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=access_denied&state=protected_state", + ".AspNetCore.Correlation.Weblie.correlationId=N"); + + Assert.Equal(HttpStatusCode.NotAcceptable, transaction.Response.StatusCode); + Assert.Null(transaction.Response.Headers.Location); + } + + [Fact] + public async Task HandleRequestAsync_InvokesRemoteFailureEventWhenAccessDeniedPathIsNotExplicitlySet() + { + var server = CreateServer( + s => s.AddAuthentication().AddOAuth( + "Weblie", + opt => + { + opt.ClientId = "Test Id"; + opt.ClientSecret = "secret"; + opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + opt.AuthorizationEndpoint = "https://example.com/provider/login"; + opt.TokenEndpoint = "https://example.com/provider/token"; + opt.CallbackPath = "/oauth-callback"; + opt.StateDataFormat = new TestStateDataFormat(); + opt.Events = new OAuthEvents() + { + OnRemoteFailure = context => + { + Assert.Equal("Access was denied by the resource owner or by the remote server.", context.Failure.Message); + Assert.Equal("testvalue", context.Properties.Items["testkey"]); + context.Response.StatusCode = StatusCodes.Status406NotAcceptable; + context.HandleResponse(); + return Task.CompletedTask; + } + }; + })); + + var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=access_denied&state=protected_state", + ".AspNetCore.Correlation.Weblie.correlationId=N"); + + Assert.Equal(HttpStatusCode.NotAcceptable, transaction.Response.StatusCode); + Assert.Null(transaction.Response.Headers.Location); + } + + [Fact] + public async Task RemoteAuthenticationFailed_OAuthError_IncludesProperties() + { + var server = CreateServer( + s => s.AddAuthentication().AddOAuth( + "Weblie", + opt => + { + opt.ClientId = "Test Id"; + opt.ClientSecret = "secret"; + opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + opt.AuthorizationEndpoint = "https://example.com/provider/login"; + opt.TokenEndpoint = "https://example.com/provider/token"; + opt.CallbackPath = "/oauth-callback"; + opt.StateDataFormat = new TestStateDataFormat(); + opt.Events = new OAuthEvents() + { + OnRemoteFailure = context => + { + Assert.Contains("custom_error", context.Failure.Message); + Assert.Equal("testvalue", context.Properties.Items["testkey"]); + context.Response.StatusCode = StatusCodes.Status406NotAcceptable; + context.HandleResponse(); + return Task.CompletedTask; + } + }; + })); + + var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=custom_error&state=protected_state", + ".AspNetCore.Correlation.Weblie.correlationId=N"); + + Assert.Equal(HttpStatusCode.NotAcceptable, transaction.Response.StatusCode); + Assert.Null(transaction.Response.Headers.Location); + } + + private static TestServer CreateServer(Action configureServices, Func> handler = null) + { + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseAuthentication(); + app.Use(async (context, next) => + { + if (handler == null || ! await handler(context)) + { + await next(); + } + }); + }) + .ConfigureServices(configureServices); + return new TestServer(builder); + } + + private class TestStateDataFormat : ISecureDataFormat + { + private AuthenticationProperties Data { get; set; } + + public string Protect(AuthenticationProperties data) + { + return "protected_state"; + } + + public string Protect(AuthenticationProperties data, string purpose) + { + throw new NotImplementedException(); + } + + public AuthenticationProperties Unprotect(string protectedText) + { + Assert.Equal("protected_state", protectedText); + var properties = new AuthenticationProperties(new Dictionary() + { + { ".xsrf", "correlationId" }, + { "testkey", "testvalue" } + }); + properties.RedirectUri = "http://testhost/redirect"; + return properties; + } + + public AuthenticationProperties Unprotect(string protectedText, string purpose) + { + throw new NotImplementedException(); + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/MockOpenIdConnectMessage.cs b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/MockOpenIdConnectMessage.cs index 432980f77..5614fe8fe 100644 --- a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/MockOpenIdConnectMessage.cs +++ b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/MockOpenIdConnectMessage.cs @@ -1,6 +1,6 @@ using Microsoft.IdentityModel.Protocols.OpenIdConnect; -namespace Microsoft.AspNetCore.Authentication.Tests.OpenIdConnect +namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect { internal class MockOpenIdConnectMessage : OpenIdConnectMessage { diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectChallengeTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectChallengeTests.cs index b9c0179af..cbafc4622 100644 --- a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectChallengeTests.cs +++ b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectChallengeTests.cs @@ -6,21 +6,29 @@ using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication.OpenIdConnect; -using Microsoft.AspNetCore.Http.Authentication; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Primitives; using Microsoft.IdentityModel.Protocols.OpenIdConnect; +using Microsoft.Net.Http.Headers; using Xunit; -namespace Microsoft.AspNetCore.Authentication.Tests.OpenIdConnect +namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect { public class OpenIdConnectChallengeTests { private static readonly string ChallengeEndpoint = TestServerBuilder.TestHost + TestServerBuilder.Challenge; [Fact] - public async Task ChallengeIsIssuedCorrectly() + public async Task ChallengeRedirectIsIssuedCorrectly() { var settings = new TestSettings( - opt => opt.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet); + opt => + { + opt.Authority = TestServerBuilder.DefaultAuthority; + opt.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet; + opt.ClientId = "Test Id"; + }); var server = settings.CreateTestServer(); var transaction = await server.SendAsync(ChallengeEndpoint); @@ -35,7 +43,28 @@ public async Task ChallengeIsIssuedCorrectly() OpenIdConnectParameterNames.ResponseType, OpenIdConnectParameterNames.ResponseMode, OpenIdConnectParameterNames.Scope, - OpenIdConnectParameterNames.RedirectUri); + OpenIdConnectParameterNames.RedirectUri, + OpenIdConnectParameterNames.SkuTelemetry, + OpenIdConnectParameterNames.VersionTelemetry); + } + + [Fact] + public async Task AuthorizationRequestDoesNotIncludeTelemetryParametersWhenDisabled() + { + var settings = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.Authority = TestServerBuilder.DefaultAuthority; + opt.DisableTelemetry = true; + }); + + var server = settings.CreateTestServer(); + var transaction = await server.SendAsync(ChallengeEndpoint); + + var res = transaction.Response; + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.DoesNotContain(OpenIdConnectParameterNames.SkuTelemetry, res.Headers.Location.Query); + Assert.DoesNotContain(OpenIdConnectParameterNames.VersionTelemetry, res.Headers.Location.Query); } /* @@ -58,10 +87,15 @@ Example of a form post */ [Fact] - public async Task ChallengeIssueedCorrectlyForFormPost() + public async Task ChallengeFormPostIssuedCorrectly() { var settings = new TestSettings( - opt => opt.AuthenticationMethod = OpenIdConnectRedirectBehavior.FormPost); + opt => + { + opt.Authority = TestServerBuilder.DefaultAuthority; + opt.AuthenticationMethod = OpenIdConnectRedirectBehavior.FormPost; + opt.ClientId = "Test Id"; + }); var server = settings.CreateTestServer(); var transaction = await server.SendAsync(ChallengeEndpoint); @@ -85,12 +119,18 @@ public async Task ChallengeIssueedCorrectlyForFormPost() [InlineData(null)] public async Task ChallengeCanSetUserStateThroughProperties(string userState) { - var settings = new TestSettings(); + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("OIDCTest")); + var settings = new TestSettings(o => + { + o.ClientId = "Test Id"; + o.Authority = TestServerBuilder.DefaultAuthority; + o.StateDataFormat = stateFormat; + }); var properties = new AuthenticationProperties(); properties.Items.Add(OpenIdConnectDefaults.UserstatePropertiesKey, userState); - var server = TestServerBuilder.CreateServer(settings.Options, handler: null, properties: properties); + var server = settings.CreateTestServer(properties); var transaction = await server.SendAsync(TestServerBuilder.TestHost + TestServerBuilder.ChallengeWithProperties); var res = transaction.Response; @@ -99,7 +139,7 @@ public async Task ChallengeCanSetUserStateThroughProperties(string userState) var values = settings.ValidateChallengeRedirect(res.Headers.Location); var actualState = values[OpenIdConnectParameterNames.State]; - var actualProperties = settings.Options.StateDataFormat.Unprotect(actualState); + var actualProperties = stateFormat.Unprotect(actualState); Assert.Equal(userState ?? string.Empty, actualProperties.Items[OpenIdConnectDefaults.UserstatePropertiesKey]); } @@ -109,8 +149,12 @@ public async Task ChallengeCanSetUserStateThroughProperties(string userState) [InlineData(null)] public async Task OnRedirectToIdentityProviderEventCanSetState(string userState) { + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("OIDCTest")); var settings = new TestSettings(opt => { + opt.StateDataFormat = stateFormat; + opt.ClientId = "Test Id"; + opt.Authority = TestServerBuilder.DefaultAuthority; opt.Events = new OpenIdConnectEvents() { OnRedirectToIdentityProvider = context => @@ -130,7 +174,7 @@ public async Task OnRedirectToIdentityProviderEventCanSetState(string userState) var values = settings.ValidateChallengeRedirect(res.Headers.Location); var actualState = values[OpenIdConnectParameterNames.State]; - var actualProperties = settings.Options.StateDataFormat.Unprotect(actualState); + var actualProperties = stateFormat.Unprotect(actualState); if (userState != null) { @@ -149,6 +193,8 @@ public async Task OnRedirectToIdentityProviderEventIsHit() var settings = new TestSettings( opts => { + opts.ClientId = "Test Id"; + opts.Authority = TestServerBuilder.DefaultAuthority; opts.Events = new OpenIdConnectEvents() { OnRedirectToIdentityProvider = context => @@ -187,12 +233,13 @@ public async Task OnRedirectToIdentityProviderEventCanReplaceValues() var settings = new TestSettings( opts => { + opts.ClientId = "Test Id"; + opts.Authority = TestServerBuilder.DefaultAuthority; opts.Events = new OpenIdConnectEvents() { OnRedirectToIdentityProvider = context => { context.ProtocolMessage.ClientId = newClientId; - return Task.FromResult(0); } }; @@ -229,6 +276,8 @@ public async Task OnRedirectToIdentityProviderEventCanReplaceMessage() var settings = new TestSettings( opts => { + opts.ClientId = "Test Id"; + opts.Authority = TestServerBuilder.DefaultAuthority; opts.Events = new OpenIdConnectEvents() { OnRedirectToIdentityProvider = context => @@ -252,12 +301,15 @@ public async Task OnRedirectToIdentityProviderEventCanReplaceMessage() // query string is not generated and the authorization endpoint is replaced. Assert.Equal(newMessage.TestAuthorizeEndpoint, res.Headers.Location.AbsoluteUri); } + [Fact] public async Task OnRedirectToIdentityProviderEventHandlesResponse() { var settings = new TestSettings( opts => { + opts.ClientId = "Test Id"; + opts.Authority = TestServerBuilder.DefaultAuthority; opts.Events = new OpenIdConnectEvents() { OnRedirectToIdentityProvider = context => @@ -281,19 +333,21 @@ public async Task OnRedirectToIdentityProviderEventHandlesResponse() Assert.Null(res.Headers.Location); } - // This test can be further refined. When one auth middleware skips, the authentication responsibility - // will be flowed to the next one. A dummy auth middleware can be added to ensure the correct logic. + // This test can be further refined. When one auth handler skips, the authentication responsibility + // will be flowed to the next one. A dummy auth handler can be added to ensure the correct logic. [Fact] - public async Task OnRedirectToIdentityProviderEventSkipResponse() + public async Task OnRedirectToIdentityProviderEventHandleResponse() { var settings = new TestSettings( opts => { + opts.ClientId = "Test Id"; + opts.Authority = TestServerBuilder.DefaultAuthority; opts.Events = new OpenIdConnectEvents() { OnRedirectToIdentityProvider = context => { - context.SkipToNextMiddleware(); + context.HandleResponse(); return Task.FromResult(0); } }; @@ -308,31 +362,255 @@ public async Task OnRedirectToIdentityProviderEventSkipResponse() Assert.Null(res.Headers.Location); } - [Fact] - public async Task ChallengeSetsNonceAndStateCookies() + [Theory] + [InlineData(OpenIdConnectRedirectBehavior.RedirectGet)] + [InlineData(OpenIdConnectRedirectBehavior.FormPost)] + public async Task ChallengeSetsNonceAndStateCookies(OpenIdConnectRedirectBehavior method) { - var settings = new TestSettings(); + var settings = new TestSettings(o => + { + o.AuthenticationMethod = method; + o.ClientId = "Test Id"; + o.Authority = TestServerBuilder.DefaultAuthority; + }); var server = settings.CreateTestServer(); var transaction = await server.SendAsync(ChallengeEndpoint); - var firstCookie = transaction.SetCookie.First(); - Assert.Contains(OpenIdConnectDefaults.CookieNoncePrefix, firstCookie); - Assert.Contains("expires", firstCookie); - - var secondCookie = transaction.SetCookie.Skip(1).First(); - Assert.StartsWith(".AspNetCore.Correlation.OpenIdConnect.", secondCookie); - Assert.Contains("expires", secondCookie); + var challengeCookies = SetCookieHeaderValue.ParseList(transaction.SetCookie); + var nonceCookie = challengeCookies.Where(cookie => cookie.Name.StartsWith(OpenIdConnectDefaults.CookieNoncePrefix, StringComparison.Ordinal)).Single(); + Assert.True(nonceCookie.Expires.HasValue); + Assert.True(nonceCookie.Expires > DateTime.UtcNow); + Assert.True(nonceCookie.HttpOnly); + Assert.Equal("/signin-oidc", nonceCookie.Path); + Assert.Equal("N", nonceCookie.Value); + Assert.Equal(Net.Http.Headers.SameSiteMode.None, nonceCookie.SameSite); + + var correlationCookie = challengeCookies.Where(cookie => cookie.Name.StartsWith(".AspNetCore.Correlation.", StringComparison.Ordinal)).Single(); + Assert.True(correlationCookie.Expires.HasValue); + Assert.True(nonceCookie.Expires > DateTime.UtcNow); + Assert.True(correlationCookie.HttpOnly); + Assert.Equal("/signin-oidc", correlationCookie.Path); + Assert.False(StringSegment.IsNullOrEmpty(correlationCookie.Value)); + + Assert.Equal(2, challengeCookies.Count); } [Fact] public async Task Challenge_WithEmptyConfig_Fails() { var settings = new TestSettings( - opt => opt.Configuration = new OpenIdConnectConfiguration()); + opt => + { + opt.ClientId = "Test Id"; + opt.Configuration = new OpenIdConnectConfiguration(); + }); var server = settings.CreateTestServer(); var exception = await Assert.ThrowsAsync(() => server.SendAsync(ChallengeEndpoint)); Assert.Equal("Cannot redirect to the authorization endpoint, the configuration may be missing or invalid.", exception.Message); } + + [Fact] + public async Task Challenge_WithDefaultMaxAge_HasExpectedMaxAgeParam() + { + var settings = new TestSettings( + opt => + { + opt.ClientId = "Test Id"; + opt.Authority = TestServerBuilder.DefaultAuthority; + }); + + var server = settings.CreateTestServer(); + var transaction = await server.SendAsync(ChallengeEndpoint); + + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + settings.ValidateChallengeRedirect( + res.Headers.Location, + OpenIdConnectParameterNames.MaxAge); + } + + [Fact] + public async Task Challenge_WithSpecificMaxAge_HasExpectedMaxAgeParam() + { + var settings = new TestSettings( + opt => + { + opt.ClientId = "Test Id"; + opt.Authority = TestServerBuilder.DefaultAuthority; + opt.MaxAge = TimeSpan.FromMinutes(20); + }); + + var server = settings.CreateTestServer(); + var transaction = await server.SendAsync(ChallengeEndpoint); + + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + settings.ValidateChallengeRedirect( + res.Headers.Location, + OpenIdConnectParameterNames.MaxAge); + } + + [Fact] + public async Task Challenge_HasExpectedPromptParam() + { + var settings = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.Authority = TestServerBuilder.DefaultAuthority; + opt.Prompt = "consent"; + }); + + var server = settings.CreateTestServer(); + var transaction = await server.SendAsync(ChallengeEndpoint); + + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + settings.ValidateChallengeRedirect(res.Headers.Location, OpenIdConnectParameterNames.Prompt); + Assert.Contains("prompt=consent", res.Headers.Location.Query); + } + + [Fact] + public async Task Challenge_HasOverwrittenPromptParam() + { + var settings = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.Authority = TestServerBuilder.DefaultAuthority; + opt.Prompt = "consent"; + }); + var properties = new OpenIdConnectChallengeProperties() + { + Prompt = "login", + }; + + var server = settings.CreateTestServer(properties); + var transaction = await server.SendAsync(TestServerBuilder.TestHost + TestServerBuilder.ChallengeWithProperties); + + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + settings.ValidateChallengeRedirect(res.Headers.Location); + Assert.Contains("prompt=login", res.Headers.Location.Query); + } + + [Fact] + public async Task Challenge_HasOverwrittenPromptParamFromBaseAuthenticationProperties() + { + var settings = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.Authority = TestServerBuilder.DefaultAuthority; + opt.Prompt = "consent"; + }); + var properties = new AuthenticationProperties(); + properties.SetParameter(OpenIdConnectChallengeProperties.PromptKey, "login"); + + var server = settings.CreateTestServer(properties); + var transaction = await server.SendAsync(TestServerBuilder.TestHost + TestServerBuilder.ChallengeWithProperties); + + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + settings.ValidateChallengeRedirect(res.Headers.Location); + Assert.Contains("prompt=login", res.Headers.Location.Query); + } + + [Fact] + public async Task Challenge_HasOverwrittenScopeParam() + { + var settings = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.Authority = TestServerBuilder.DefaultAuthority; + opt.Scope.Clear(); + opt.Scope.Add("foo"); + opt.Scope.Add("bar"); + }); + var properties = new OpenIdConnectChallengeProperties(); + properties.SetScope("baz", "qux"); + + var server = settings.CreateTestServer(properties); + var transaction = await server.SendAsync(TestServerBuilder.TestHost + TestServerBuilder.ChallengeWithProperties); + + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + settings.ValidateChallengeRedirect(res.Headers.Location); + Assert.Contains("scope=baz%20qux", res.Headers.Location.Query); + } + + [Fact] + public async Task Challenge_HasOverwrittenScopeParamFromBaseAuthenticationProperties() + { + var settings = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.Authority = TestServerBuilder.DefaultAuthority; + opt.Scope.Clear(); + opt.Scope.Add("foo"); + opt.Scope.Add("bar"); + }); + var properties = new AuthenticationProperties(); + properties.SetParameter(OpenIdConnectChallengeProperties.ScopeKey, new string[] { "baz", "qux" }); + + var server = settings.CreateTestServer(properties); + var transaction = await server.SendAsync(TestServerBuilder.TestHost + TestServerBuilder.ChallengeWithProperties); + + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + settings.ValidateChallengeRedirect(res.Headers.Location); + Assert.Contains("scope=baz%20qux", res.Headers.Location.Query); + } + + [Fact] + public async Task Challenge_HasOverwrittenMaxAgeParam() + { + var settings = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.Authority = TestServerBuilder.DefaultAuthority; + opt.MaxAge = TimeSpan.FromSeconds(500); + }); + var properties = new OpenIdConnectChallengeProperties() + { + MaxAge = TimeSpan.FromSeconds(1234), + }; + + var server = settings.CreateTestServer(properties); + var transaction = await server.SendAsync(TestServerBuilder.TestHost + TestServerBuilder.ChallengeWithProperties); + + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + settings.ValidateChallengeRedirect(res.Headers.Location); + Assert.Contains("max_age=1234", res.Headers.Location.Query); + } + + [Fact] + public async Task Challenge_HasOverwrittenMaxAgeParaFromBaseAuthenticationPropertiesm() + { + var settings = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.Authority = TestServerBuilder.DefaultAuthority; + opt.MaxAge = TimeSpan.FromSeconds(500); + }); + var properties = new AuthenticationProperties(); + properties.SetParameter(OpenIdConnectChallengeProperties.MaxAgeKey, TimeSpan.FromSeconds(1234)); + + var server = settings.CreateTestServer(properties); + var transaction = await server.SendAsync(TestServerBuilder.TestHost + TestServerBuilder.ChallengeWithProperties); + + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + settings.ValidateChallengeRedirect(res.Headers.Location); + Assert.Contains("max_age=1234", res.Headers.Location.Query); + } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectConfigurationTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectConfigurationTests.cs index 0f5338c5c..ed368c1ef 100644 --- a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectConfigurationTests.cs +++ b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectConfigurationTests.cs @@ -2,118 +2,572 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Net; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.AspNetCore.Authentication.Tests; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Xunit; -namespace Microsoft.AspNetCore.Authentication.Tests.OpenIdConnect +namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect { public class OpenIdConnectConfigurationTests { + private void ConfigureDefaults(OpenIdConnectOptions o) + { + o.Authority = TestServerBuilder.DefaultAuthority; + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; + o.SignInScheme = "auth1"; + } + + [Fact] + public async Task CanForwardDefault() + { + var services = new ServiceCollection().AddLogging(); + + services.AddAuthentication(o => + { + o.DefaultScheme = OpenIdConnectDefaults.AuthenticationScheme; + o.AddScheme("auth1", "auth1"); + }) + .AddOpenIdConnect(o => + { + ConfigureDefaults(o); + o.ForwardDefault = "auth1"; + }); + + var forwardDefault = new TestHandler(); + services.AddSingleton(forwardDefault); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + + await context.AuthenticateAsync(); + Assert.Equal(1, forwardDefault.AuthenticateCount); + + await context.ForbidAsync(); + Assert.Equal(1, forwardDefault.ForbidCount); + + await context.ChallengeAsync(); + Assert.Equal(1, forwardDefault.ChallengeCount); + + await context.SignOutAsync(); + Assert.Equal(1, forwardDefault.SignOutCount); + + await Assert.ThrowsAsync(() => context.SignInAsync(new ClaimsPrincipal())); + } + + [Fact] + public async Task ForwardSignInThrows() + { + var services = new ServiceCollection().AddLogging(); + + services.AddAuthentication(o => + { + o.DefaultScheme = OpenIdConnectDefaults.AuthenticationScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("specific", "specific"); + }) + .AddOpenIdConnect(o => + { + ConfigureDefaults(o); + o.ForwardDefault = "auth1"; + o.ForwardSignOut = "specific"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await Assert.ThrowsAsync(() => context.SignInAsync(new ClaimsPrincipal())); + } + + [Fact] + public async Task ForwardSignOutWinsOverDefault() + { + var services = new ServiceCollection().AddLogging(); + + services.AddAuthentication(o => + { + o.DefaultScheme = OpenIdConnectDefaults.AuthenticationScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("specific", "specific"); + }) + .AddOpenIdConnect(o => + { + ConfigureDefaults(o); + o.ForwardDefault = "auth1"; + o.ForwardSignOut = "specific"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.SignOutAsync(); + Assert.Equal(1, specific.SignOutCount); + Assert.Equal(0, specific.AuthenticateCount); + Assert.Equal(0, specific.ForbidCount); + Assert.Equal(0, specific.ChallengeCount); + Assert.Equal(0, specific.SignInCount); + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + } + + [Fact] + public async Task ForwardForbidWinsOverDefault() + { + var services = new ServiceCollection().AddLogging(); + + services.AddAuthentication(o => + { + o.DefaultScheme = OpenIdConnectDefaults.AuthenticationScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("specific", "specific"); + }) + .AddOpenIdConnect(o => + { + ConfigureDefaults(o); + o.ForwardDefault = "auth1"; + o.ForwardForbid = "specific"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.ForbidAsync(); + Assert.Equal(0, specific.SignOutCount); + Assert.Equal(0, specific.AuthenticateCount); + Assert.Equal(1, specific.ForbidCount); + Assert.Equal(0, specific.ChallengeCount); + Assert.Equal(0, specific.SignInCount); + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + } + + [Fact] + public async Task ForwardAuthenticateWinsOverDefault() + { + var services = new ServiceCollection().AddLogging(); + + services.AddAuthentication(o => + { + o.DefaultScheme = OpenIdConnectDefaults.AuthenticationScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("specific", "specific"); + }) + .AddOpenIdConnect(o => + { + ConfigureDefaults(o); + o.ForwardDefault = "auth1"; + o.ForwardAuthenticate = "specific"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.AuthenticateAsync(); + Assert.Equal(0, specific.SignOutCount); + Assert.Equal(1, specific.AuthenticateCount); + Assert.Equal(0, specific.ForbidCount); + Assert.Equal(0, specific.ChallengeCount); + Assert.Equal(0, specific.SignInCount); + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + } + + [Fact] + public async Task ForwardChallengeWinsOverDefault() + { + var services = new ServiceCollection().AddLogging(); + services.AddAuthentication(o => + { + o.DefaultScheme = OpenIdConnectDefaults.AuthenticationScheme; + o.AddScheme("specific", "specific"); + o.AddScheme("auth1", "auth1"); + }) + .AddOpenIdConnect(o => + { + ConfigureDefaults(o); + o.ForwardDefault = "auth1"; + o.ForwardChallenge = "specific"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.ChallengeAsync(); + Assert.Equal(0, specific.SignOutCount); + Assert.Equal(0, specific.AuthenticateCount); + Assert.Equal(0, specific.ForbidCount); + Assert.Equal(1, specific.ChallengeCount); + Assert.Equal(0, specific.SignInCount); + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + } + + [Fact] + public async Task ForwardSelectorWinsOverDefault() + { + var services = new ServiceCollection().AddLogging(); + services.AddAuthentication(o => + { + o.DefaultScheme = OpenIdConnectDefaults.AuthenticationScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("selector", "selector"); + o.AddScheme("specific", "specific"); + }) + .AddOpenIdConnect(o => + { + ConfigureDefaults(o); + o.ForwardDefault = "auth1"; + o.ForwardDefaultSelector = _ => "selector"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + var selector = new TestHandler3(); + services.AddSingleton(selector); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.AuthenticateAsync(); + Assert.Equal(1, selector.AuthenticateCount); + + await context.ForbidAsync(); + Assert.Equal(1, selector.ForbidCount); + + await context.ChallengeAsync(); + Assert.Equal(1, selector.ChallengeCount); + + await context.SignOutAsync(); + Assert.Equal(1, selector.SignOutCount); + + await Assert.ThrowsAsync(() => context.SignInAsync(new ClaimsPrincipal())); + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + Assert.Equal(0, specific.AuthenticateCount); + Assert.Equal(0, specific.ForbidCount); + Assert.Equal(0, specific.ChallengeCount); + Assert.Equal(0, specific.SignInCount); + Assert.Equal(0, specific.SignOutCount); + } + + [Fact] + public async Task NullForwardSelectorUsesDefault() + { + var services = new ServiceCollection().AddLogging(); + services.AddAuthentication(o => + { + o.DefaultScheme = OpenIdConnectDefaults.AuthenticationScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("selector", "selector"); + o.AddScheme("specific", "specific"); + }) + .AddOpenIdConnect(o => + { + ConfigureDefaults(o); + o.ForwardDefault = "auth1"; + o.ForwardDefaultSelector = _ => null; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + var selector = new TestHandler3(); + services.AddSingleton(selector); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.AuthenticateAsync(); + Assert.Equal(1, forwardDefault.AuthenticateCount); + + await context.ForbidAsync(); + Assert.Equal(1, forwardDefault.ForbidCount); + + await context.ChallengeAsync(); + Assert.Equal(1, forwardDefault.ChallengeCount); + + await context.SignOutAsync(); + Assert.Equal(1, forwardDefault.SignOutCount); + + await Assert.ThrowsAsync(() => context.SignInAsync(new ClaimsPrincipal())); + + Assert.Equal(0, selector.AuthenticateCount); + Assert.Equal(0, selector.ForbidCount); + Assert.Equal(0, selector.ChallengeCount); + Assert.Equal(0, selector.SignInCount); + Assert.Equal(0, selector.SignOutCount); + Assert.Equal(0, specific.AuthenticateCount); + Assert.Equal(0, specific.ForbidCount); + Assert.Equal(0, specific.ChallengeCount); + Assert.Equal(0, specific.SignInCount); + Assert.Equal(0, specific.SignOutCount); + } + [Fact] - public void MetadataAddressIsGeneratedFromAuthorityWhenMissing() + public async Task SpecificForwardWinsOverSelectorAndDefault() { - var options = new OpenIdConnectOptions + var services = new ServiceCollection().AddLogging(); + services.AddAuthentication(o => { - Authority = TestServerBuilder.DefaultAuthority, - ClientId = Guid.NewGuid().ToString(), - SignInScheme = Guid.NewGuid().ToString() - }; + o.DefaultScheme = OpenIdConnectDefaults.AuthenticationScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("selector", "selector"); + o.AddScheme("specific", "specific"); + }) + .AddOpenIdConnect(o => + { + ConfigureDefaults(o); + o.ForwardDefault = "auth1"; + o.ForwardDefaultSelector = _ => "selector"; + o.ForwardAuthenticate = "specific"; + o.ForwardChallenge = "specific"; + o.ForwardSignIn = "specific"; + o.ForwardSignOut = "specific"; + o.ForwardForbid = "specific"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + var selector = new TestHandler3(); + services.AddSingleton(selector); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; - BuildTestServer(options); + await context.AuthenticateAsync(); + Assert.Equal(1, specific.AuthenticateCount); - Assert.Equal($"{options.Authority}/.well-known/openid-configuration", options.MetadataAddress); + await context.ForbidAsync(); + Assert.Equal(1, specific.ForbidCount); + + await context.ChallengeAsync(); + Assert.Equal(1, specific.ChallengeCount); + + await context.SignOutAsync(); + Assert.Equal(1, specific.SignOutCount); + + await Assert.ThrowsAsync(() => context.SignInAsync(new ClaimsPrincipal())); + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + Assert.Equal(0, selector.AuthenticateCount); + Assert.Equal(0, selector.ForbidCount); + Assert.Equal(0, selector.ChallengeCount); + Assert.Equal(0, selector.SignInCount); + Assert.Equal(0, selector.SignOutCount); + } + + [Fact] + public async Task MetadataAddressIsGeneratedFromAuthorityWhenMissing() + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddAuthentication() + .AddCookie() + .AddOpenIdConnect(o => + { + o.Authority = TestServerBuilder.DefaultAuthority; + o.ClientId = Guid.NewGuid().ToString(); + o.SignInScheme = Guid.NewGuid().ToString(); + }); + }) + .Configure(app => + { + app.UseAuthentication(); + app.Run(async context => + { + var resolver = context.RequestServices.GetRequiredService(); + var handler = await resolver.GetHandlerAsync(context, OpenIdConnectDefaults.AuthenticationScheme) as OpenIdConnectHandler; + Assert.Equal($"{TestServerBuilder.DefaultAuthority}/.well-known/openid-configuration", handler.Options.MetadataAddress); + }); + }); + var server = new TestServer(builder); + var transaction = await server.SendAsync(@"https://example.com"); + Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); } - public void ThrowsWhenSignInSchemeIsMissing() + [Fact] + public Task ThrowsWhenSignInSchemeIsSetToSelf() { - TestConfigurationException( - new OpenIdConnectOptions + return TestConfigurationException( + o => { - Authority = TestServerBuilder.DefaultAuthority, - ClientId = Guid.NewGuid().ToString() + o.SignInScheme = OpenIdConnectDefaults.AuthenticationScheme; + o.Authority = TestServerBuilder.DefaultAuthority; + o.ClientId = "Test Id"; + o.ClientSecret = "Test Secret"; }, - ex => Assert.Equal("SignInScheme", ex.ParamName)); + ex => Assert.Contains("cannot be set to itself", ex.Message)); } [Fact] - public void ThrowsWhenClientIdIsMissing() + public Task ThrowsWhenClientIdIsMissing() { - TestConfigurationException( - new OpenIdConnectOptions + return TestConfigurationException( + o => { - SignInScheme = "TestScheme", - Authority = TestServerBuilder.DefaultAuthority, + o.SignInScheme = "TestScheme"; + o.Authority = TestServerBuilder.DefaultAuthority; }, ex => Assert.Equal("ClientId", ex.ParamName)); } [Fact] - public void ThrowsWhenAuthorityIsMissing() + public Task ThrowsWhenAuthorityIsMissing() { - TestConfigurationException( - new OpenIdConnectOptions + return TestConfigurationException( + o => { - SignInScheme = "TestScheme", - ClientId = "Test Id", + o.SignInScheme = "TestScheme"; + o.ClientId = "Test Id"; + o.CallbackPath = "/"; }, ex => Assert.Equal("Provide Authority, MetadataAddress, Configuration, or ConfigurationManager to OpenIdConnectOptions", ex.Message) ); } [Fact] - public void ThrowsWhenAuthorityIsNotHttps() + public Task ThrowsWhenAuthorityIsNotHttps() { - TestConfigurationException( - new OpenIdConnectOptions + return TestConfigurationException( + o => { - SignInScheme = "TestScheme", - ClientId = "Test Id", - Authority = "http://example.com" + o.SignInScheme = "TestScheme"; + o.ClientId = "Test Id"; + o.MetadataAddress = "http://example.com"; + o.CallbackPath = "/"; }, ex => Assert.Equal("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.", ex.Message) ); } [Fact] - public void ThrowsWhenMetadataAddressIsNotHttps() + public Task ThrowsWhenMetadataAddressIsNotHttps() { - TestConfigurationException( - new OpenIdConnectOptions + return TestConfigurationException( + o => { - SignInScheme = "TestScheme", - ClientId = "Test Id", - MetadataAddress = "http://example.com" + o.SignInScheme = "TestScheme"; + o.ClientId = "Test Id"; + o.MetadataAddress = "http://example.com"; + o.CallbackPath = "/"; }, ex => Assert.Equal("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.", ex.Message) ); } - private TestServer BuildTestServer(OpenIdConnectOptions options) + [Fact] + public Task ThrowsWhenMaxAgeIsNegative() + { + return TestConfigurationException( + o => + { + o.SignInScheme = "TestScheme"; + o.ClientId = "Test Id"; + o.Authority = TestServerBuilder.DefaultAuthority; + o.MaxAge = TimeSpan.FromSeconds(-1); + }, + ex => Assert.StartsWith("The value must not be a negative TimeSpan.", ex.Message) + ); + } + + private TestServer BuildTestServer(Action options) { var builder = new WebHostBuilder() - .ConfigureServices(services => services.AddAuthentication()) - .Configure(app => app.UseOpenIdConnectAuthentication(options)); + .ConfigureServices(services => + { + services.AddAuthentication() + .AddCookie() + .AddOpenIdConnect(options); + }) + .Configure(app => app.UseAuthentication()); return new TestServer(builder); } - private void TestConfigurationException( - OpenIdConnectOptions options, + private async Task TestConfigurationException( + Action options, Action verifyException) where T : Exception { - var builder = new WebHostBuilder() - .ConfigureServices(services => services.AddAuthentication()) - .Configure(app => app.UseOpenIdConnectAuthentication(options)); - - var exception = Assert.Throws(() => - { - new TestServer(builder); - }); - + var exception = await Assert.ThrowsAsync(() => BuildTestServer(options).SendAsync(@"https://example.com")); verifyException(exception); } } diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectEventTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectEventTests.cs index a212af649..090bf3dec 100644 --- a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectEventTests.cs +++ b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectEventTests.cs @@ -16,1391 +16,1252 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Primitives; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Tokens; +using Microsoft.Net.Http.Headers; using Xunit; namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect { public class OpenIdConnectEventTests { - private readonly Func MessageNotImpl = context => { throw new NotImplementedException("Message"); }; - private readonly Func TokenNotImpl = context => { throw new NotImplementedException("Token"); }; - private readonly Func CodeNotImpl = context => { throw new NotImplementedException("Code"); }; - private readonly Func TokenResponseNotImpl = context => { throw new NotImplementedException("TokenResponse"); }; - private readonly Func UserNotImpl = context => { throw new NotImplementedException("User"); }; - private readonly Func FailedNotImpl = context => { throw new NotImplementedException("Failed", context.Exception); }; - private readonly Func TicketNotImpl = context => { throw new NotImplementedException("Ticket"); }; - private readonly Func FailureNotImpl = context => { throw new NotImplementedException("Failure", context.Failure); }; - private readonly Func RedirectNotImpl = context => { throw new NotImplementedException("Redirect"); }; - private readonly Func RemoteSignOutNotImpl = context => { throw new NotImplementedException("Remote"); }; + private readonly RequestDelegate AppWritePath = context => context.Response.WriteAsync(context.Request.Path); private readonly RequestDelegate AppNotImpl = context => { throw new NotImplementedException("App"); }; [Fact] - public async Task OnMessageReceived_Skipped_NoMoreEventsRun() + public async Task OnMessageReceived_Skip_NoMoreEventsRun() { - var messageReceived = false; - var server = CreateServer(new OpenIdConnectEvents() + var events = new ExpectedOidcEvents() { - OnMessageReceived = context => - { - messageReceived = true; - context.SkipToNextMiddleware(); - return Task.FromResult(0); - }, - OnTokenValidated = TokenNotImpl, - OnAuthorizationCodeReceived = CodeNotImpl, - OnTokenResponseReceived = TokenResponseNotImpl, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnTicketReceived = TicketNotImpl, - OnRemoteFailure = FailureNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - context => + ExpectMessageReceived = true, + }; + events.OnMessageReceived = context => { - return context.Response.WriteAsync(context.Request.Path); - }); + context.SkipHandler(); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); var response = await PostAsync(server, "signin-oidc", ""); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("/signin-oidc", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnMessageReceived_Fail_NoMoreEventsRun() + { + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectRemoteFailure = true, + }; + events.OnMessageReceived = context => + { + context.Fail("Authentication was aborted from user code."); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); + + var exception = await Assert.ThrowsAsync(delegate + { + return PostAsync(server, "signin-oidc", ""); + }); + + Assert.Equal("Authentication was aborted from user code.", exception.InnerException.Message); + events.ValidateExpectations(); } [Fact] public async Task OnMessageReceived_Handled_NoMoreEventsRun() { - var messageReceived = false; - var server = CreateServer(new OpenIdConnectEvents() + var events = new ExpectedOidcEvents() { - OnMessageReceived = context => - { - messageReceived = true; - context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - OnTokenValidated = TokenNotImpl, - OnAuthorizationCodeReceived = CodeNotImpl, - OnTokenResponseReceived = TokenResponseNotImpl, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + ExpectMessageReceived = true, + }; + events.OnMessageReceived = context => + { + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", ""); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); + events.ValidateExpectations(); } [Fact] - public async Task OnTokenValidated_Skipped_NoMoreEventsRun() + public async Task OnTokenValidated_Skip_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var server = CreateServer(new OpenIdConnectEvents() + var events = new ExpectedOidcEvents() { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - context.SkipToNextMiddleware(); - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = CodeNotImpl, - OnTokenResponseReceived = TokenResponseNotImpl, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - context => + ExpectMessageReceived = true, + ExpectTokenValidated = true, + }; + events.OnTokenValidated = context => { - return context.Response.WriteAsync(context.Request.Path); - }); + context.SkipHandler(); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("/signin-oidc", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnTokenValidated_Fail_NoMoreEventsRun() + { + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectRemoteFailure = true, + }; + events.OnTokenValidated = context => + { + context.Fail("Authentication was aborted from user code."); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); + + var exception = await Assert.ThrowsAsync(delegate + { + return PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state"); + }); + + Assert.Equal("Authentication was aborted from user code.", exception.InnerException.Message); + events.ValidateExpectations(); } [Fact] public async Task OnTokenValidated_HandledWithoutTicket_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var server = CreateServer(new OpenIdConnectEvents() + var events = new ExpectedOidcEvents() { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - context.HandleResponse(); - context.Ticket = null; - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = CodeNotImpl, - OnTokenResponseReceived = TokenResponseNotImpl, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + ExpectMessageReceived = true, + ExpectTokenValidated = true, + }; + events.OnTokenValidated = context => + { + context.HandleResponse(); + context.Principal = null; + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); + events.ValidateExpectations(); } - // TODO: Do any other events depend on the presence of the ticket? It's strange we have to double handle this event. [Fact] public async Task OnTokenValidated_HandledWithTicket_SkipToTicketReceived() { - var messageReceived = false; - var tokenValidated = false; - var ticketReceived = false; - var server = CreateServer(new OpenIdConnectEvents() + var events = new ExpectedOidcEvents() { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - context.HandleResponse(); - // context.Ticket = null; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = CodeNotImpl, - OnTokenResponseReceived = TokenResponseNotImpl, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = context => - { - ticketReceived = true; - context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectTicketReceived = true, + }; + events.OnTokenValidated = context => + { + context.HandleResponse(); + context.Principal = null; + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + events.OnTokenValidated = context => + { + context.Success(); + return Task.FromResult(0); + }; + events.OnTicketReceived = context => + { + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(ticketReceived); + events.ValidateExpectations(); } [Fact] - public async Task OnAuthorizationCodeReceived_Skipped_NoMoreEventsRun() + public async Task OnAuthorizationCodeReceived_Skip_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var server = CreateServer(new OpenIdConnectEvents() + var events = new ExpectedOidcEvents() { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - context.SkipToNextMiddleware(); - return Task.FromResult(0); - }, - OnTokenResponseReceived = TokenResponseNotImpl, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - context => + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + }; + events.OnAuthorizationCodeReceived = context => { - return context.Response.WriteAsync(context.Request.Path); - }); + context.SkipHandler(); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("/signin-oidc", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnAuthorizationCodeReceived_Fail_NoMoreEventsRun() + { + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectRemoteFailure = true, + }; + events.OnAuthorizationCodeReceived = context => + { + context.Fail("Authentication was aborted from user code."); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); + + var exception = await Assert.ThrowsAsync(delegate + { + return PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); + }); + + Assert.Equal("Authentication was aborted from user code.", exception.InnerException.Message); + events.ValidateExpectations(); } [Fact] public async Task OnAuthorizationCodeReceived_HandledWithoutTicket_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var server = CreateServer(new OpenIdConnectEvents() + var events = new ExpectedOidcEvents() { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - context.HandleResponse(); - context.Ticket = null; - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - OnTokenResponseReceived = TokenResponseNotImpl, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + }; + events.OnAuthorizationCodeReceived = context => + { + context.HandleResponse(); + context.Principal = null; + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); + events.ValidateExpectations(); } [Fact] public async Task OnAuthorizationCodeReceived_HandledWithTicket_SkipToTicketReceived() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var ticketReceived = false; - var server = CreateServer(new OpenIdConnectEvents() + var events = new ExpectedOidcEvents() { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - context.HandleResponse(); - // context.Ticket = null; - return Task.FromResult(0); - }, - OnTokenResponseReceived = TokenResponseNotImpl, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = context => - { - ticketReceived = true; - context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTicketReceived = true, + }; + events.OnAuthorizationCodeReceived = context => + { + context.Success(); + return Task.FromResult(0); + }; + events.OnTicketReceived = context => + { + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(ticketReceived); + events.ValidateExpectations(); } [Fact] - public async Task OnTokenResponseReceived_Skipped_NoMoreEventsRun() + public async Task OnTokenResponseReceived_Skip_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var tokenResponseReceived = false; - var server = CreateServer(new OpenIdConnectEvents() + var events = new ExpectedOidcEvents() { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - context.SkipToNextMiddleware(); - return Task.FromResult(0); - }, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - context => + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + }; + events.OnTokenResponseReceived = context => { - return context.Response.WriteAsync(context.Request.Path); - }); + context.SkipHandler(); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("/signin-oidc", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnTokenResponseReceived_Fail_NoMoreEventsRun() + { + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectRemoteFailure = true, + }; + events.OnTokenResponseReceived = context => + { + context.Fail("Authentication was aborted from user code."); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); + + var exception = await Assert.ThrowsAsync(delegate + { + return PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); + }); + + Assert.Equal("Authentication was aborted from user code.", exception.InnerException.Message); + events.ValidateExpectations(); } [Fact] public async Task OnTokenResponseReceived_HandledWithoutTicket_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var tokenResponseReceived = false; - var server = CreateServer(new OpenIdConnectEvents() + var events = new ExpectedOidcEvents() { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - context.Ticket = null; - context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + }; + events.OnTokenResponseReceived = context => + { + context.Principal = null; + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); + events.ValidateExpectations(); } [Fact] public async Task OnTokenResponseReceived_HandledWithTicket_SkipToTicketReceived() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var ticketReceived = false; - var tokenResponseReceived = false; - var server = CreateServer(new OpenIdConnectEvents() - { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - // context.Ticket = null; - context.HandleResponse(); - return Task.FromResult(0); - }, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = context => - { - ticketReceived = true; - context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectTicketReceived = true, + }; + events.OnTokenResponseReceived = context => + { + context.Success(); + return Task.FromResult(0); + }; + events.OnTicketReceived = context => + { + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(ticketReceived); + events.ValidateExpectations(); } [Fact] - public async Task OnTokenValidatedBackchannel_Skipped_NoMoreEventsRun() + public async Task OnTokenValidatedBackchannel_Skip_NoMoreEventsRun() { - var messageReceived = false; - var codeReceived = false; - var tokenResponseReceived = false; - var tokenValidated = false; - var server = CreateServer(new OpenIdConnectEvents() + var events = new ExpectedOidcEvents() { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - context.SkipToNextMiddleware(); - return Task.FromResult(0); - }, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - context => + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + }; + events.OnTokenValidated = context => { - return context.Response.WriteAsync(context.Request.Path); - }); + context.SkipHandler(); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); var response = await PostAsync(server, "signin-oidc", "state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("/signin-oidc", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(tokenValidated); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnTokenValidatedBackchannel_Fail_NoMoreEventsRun() + { + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectRemoteFailure = true, + }; + events.OnTokenValidated = context => + { + context.Fail("Authentication was aborted from user code."); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); + + var exception = await Assert.ThrowsAsync(delegate + { + return PostAsync(server, "signin-oidc", "state=protected_state&code=my_code"); + }); + + Assert.Equal("Authentication was aborted from user code.", exception.InnerException.Message); + events.ValidateExpectations(); } [Fact] public async Task OnTokenValidatedBackchannel_HandledWithoutTicket_NoMoreEventsRun() { - var messageReceived = false; - var codeReceived = false; - var tokenResponseReceived = false; - var tokenValidated = false; - var server = CreateServer(new OpenIdConnectEvents() + var events = new ExpectedOidcEvents() { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - context.Ticket = null; - context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + }; + events.OnTokenValidated = context => + { + context.Principal = null; + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(tokenValidated); + events.ValidateExpectations(); } [Fact] public async Task OnTokenValidatedBackchannel_HandledWithTicket_SkipToTicketReceived() { - var messageReceived = false; - var codeReceived = false; - var ticketReceived = false; - var tokenResponseReceived = false; - var tokenValidated = false; - var server = CreateServer(new OpenIdConnectEvents() - { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - // context.Ticket = null; - context.HandleResponse(); - return Task.FromResult(0); - }, - OnUserInformationReceived = UserNotImpl, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = context => - { - ticketReceived = true; - context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectTicketReceived = true, + }; + events.OnTokenValidated = context => + { + context.Success(); + return Task.FromResult(0); + }; + events.OnTicketReceived = context => + { + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(tokenValidated); - Assert.True(ticketReceived); + events.ValidateExpectations(); } [Fact] - public async Task OnUserInformationReceived_Skipped_NoMoreEventsRun() + public async Task OnUserInformationReceived_Skip_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var tokenResponseReceived = false; - var userInfoReceived = false; - var server = CreateServer(new OpenIdConnectEvents() - { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - return Task.FromResult(0); - }, - OnUserInformationReceived = context => - { - userInfoReceived = true; - context.SkipToNextMiddleware(); - return Task.FromResult(0); - }, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - context => + var events = new ExpectedOidcEvents() { - return context.Response.WriteAsync(context.Request.Path); - }); + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectUserInfoReceived = true, + }; + events.OnUserInformationReceived = context => + { + context.SkipHandler(); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("/signin-oidc", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(userInfoReceived); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnUserInformationReceived_Fail_NoMoreEventsRun() + { + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectUserInfoReceived = true, + ExpectRemoteFailure = true, + }; + events.OnUserInformationReceived = context => + { + context.Fail("Authentication was aborted from user code."); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); + + var exception = await Assert.ThrowsAsync(delegate + { + return PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); + }); + + Assert.Equal("Authentication was aborted from user code.", exception.InnerException.Message); + events.ValidateExpectations(); } [Fact] public async Task OnUserInformationReceived_HandledWithoutTicket_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var tokenResponseReceived = false; - var userInfoReceived = false; - var server = CreateServer(new OpenIdConnectEvents() - { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - return Task.FromResult(0); - }, - OnUserInformationReceived = context => - { - userInfoReceived = true; - context.Ticket = null; - context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectUserInfoReceived = true, + }; + events.OnUserInformationReceived = context => + { + context.Principal = null; + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(userInfoReceived); + events.ValidateExpectations(); } [Fact] public async Task OnUserInformationReceived_HandledWithTicket_SkipToTicketReceived() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var ticketReceived = false; - var tokenResponseReceived = false; - var userInfoReceived = false; - var server = CreateServer(new OpenIdConnectEvents() - { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - return Task.FromResult(0); - }, - OnUserInformationReceived = context => - { - userInfoReceived = true; - // context.Ticket = null; - context.HandleResponse(); - return Task.FromResult(0); - }, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = context => - { - ticketReceived = true; - context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectUserInfoReceived = true, + ExpectTicketReceived = true, + }; + events.OnUserInformationReceived = context => + { + context.Success(); + return Task.FromResult(0); + }; + events.OnTicketReceived = context => + { + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(userInfoReceived); - Assert.True(ticketReceived); + events.ValidateExpectations(); } [Fact] - public async Task OnAuthenticationFailed_Skipped_NoMoreEventsRun() + public async Task OnAuthenticationFailed_Skip_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var tokenResponseReceived = false; - var userInfoReceived = false; - var authFailed = false; - var server = CreateServer(new OpenIdConnectEvents() - { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - return Task.FromResult(0); - }, - OnUserInformationReceived = context => - { - userInfoReceived = true; - throw new NotImplementedException("TestException"); - }, - OnAuthenticationFailed = context => - { - authFailed = true; - Assert.Equal("TestException", context.Exception.Message); - context.SkipToNextMiddleware(); - return Task.FromResult(0); - }, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - context => + var events = new ExpectedOidcEvents() { - return context.Response.WriteAsync(context.Request.Path); - }); + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectUserInfoReceived = true, + ExpectAuthenticationFailed = true, + }; + events.OnUserInformationReceived = context => + { + throw new NotImplementedException("TestException"); + }; + events.OnAuthenticationFailed = context => + { + Assert.Equal("TestException", context.Exception.Message); + context.SkipHandler(); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("/signin-oidc", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(userInfoReceived); - Assert.True(authFailed); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnAuthenticationFailed_Fail_NoMoreEventsRun() + { + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectUserInfoReceived = true, + ExpectAuthenticationFailed = true, + ExpectRemoteFailure = true, + }; + events.OnUserInformationReceived = context => + { + throw new NotImplementedException("TestException"); + }; + events.OnAuthenticationFailed = context => + { + Assert.Equal("TestException", context.Exception.Message); + context.Fail("Authentication was aborted from user code."); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); + + var exception = await Assert.ThrowsAsync(delegate + { + return PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); + }); + + Assert.Equal("Authentication was aborted from user code.", exception.InnerException.Message); + events.ValidateExpectations(); } [Fact] public async Task OnAuthenticationFailed_HandledWithoutTicket_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var tokenResponseReceived = false; - var userInfoReceived = false; - var authFailed = false; - var server = CreateServer(new OpenIdConnectEvents() - { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - return Task.FromResult(0); - }, - OnUserInformationReceived = context => - { - userInfoReceived = true; - throw new NotImplementedException("TestException"); - }, - OnAuthenticationFailed = context => - { - authFailed = true; - Assert.Equal("TestException", context.Exception.Message); - Assert.Null(context.Ticket); - context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectUserInfoReceived = true, + ExpectAuthenticationFailed = true, + }; + events.OnUserInformationReceived = context => + { + throw new NotImplementedException("TestException"); + }; + events.OnAuthenticationFailed = context => + { + Assert.Equal("TestException", context.Exception.Message); + Assert.Null(context.Principal); + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(userInfoReceived); - Assert.True(authFailed); + events.ValidateExpectations(); } [Fact] public async Task OnAuthenticationFailed_HandledWithTicket_SkipToTicketReceived() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var ticketReceived = false; - var tokenResponseReceived = false; - var userInfoReceived = false; - var authFailed = false; - var server = CreateServer(new OpenIdConnectEvents() - { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - return Task.FromResult(0); - }, - OnUserInformationReceived = context => - { - userInfoReceived = true; - throw new NotImplementedException("TestException"); - }, - OnAuthenticationFailed = context => - { - authFailed = true; - Assert.Equal("TestException", context.Exception.Message); - Assert.Null(context.Ticket); + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectUserInfoReceived = true, + ExpectAuthenticationFailed = true, + ExpectTicketReceived = true, + }; + events.OnUserInformationReceived = context => + { + throw new NotImplementedException("TestException"); + }; + events.OnAuthenticationFailed = context => + { + Assert.Equal("TestException", context.Exception.Message); + Assert.Null(context.Principal); - var claims = new[] - { - new Claim(ClaimTypes.NameIdentifier, "Bob le Magnifique"), - new Claim(ClaimTypes.Email, "bob@contoso.com"), - new Claim(ClaimsIdentity.DefaultNameClaimType, "bob") - }; - - context.Ticket = new AuthenticationTicket( - new ClaimsPrincipal(new ClaimsIdentity(claims, context.Options.AuthenticationScheme)), - new AuthenticationProperties(), context.Options.AuthenticationScheme); - - context.HandleResponse(); - return Task.FromResult(0); - }, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = context => + var claims = new[] { - ticketReceived = true; - context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + new Claim(ClaimTypes.NameIdentifier, "Bob le Magnifique"), + new Claim(ClaimTypes.Email, "bob@contoso.com"), + new Claim(ClaimsIdentity.DefaultNameClaimType, "bob") + }; + + context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name)); + context.Success(); + return Task.FromResult(0); + }; + events.OnTicketReceived = context => + { + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(userInfoReceived); - Assert.True(authFailed); - Assert.True(ticketReceived); + events.ValidateExpectations(); } [Fact] - public async Task OnRemoteFailure_Skipped_NoMoreEventsRun() + public async Task OnAccessDenied_Skip_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var tokenResponseReceived = false; - var userInfoReceived = false; - var authFailed = false; - var remoteFailure = false; - var server = CreateServer(new OpenIdConnectEvents() - { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - return Task.FromResult(0); - }, - OnUserInformationReceived = context => - { - userInfoReceived = true; - throw new NotImplementedException("TestException"); - }, - OnAuthenticationFailed = context => - { - authFailed = true; - Assert.Equal("TestException", context.Exception.Message); - return Task.FromResult(0); - }, - OnRemoteFailure = context => - { - remoteFailure = true; - Assert.Equal("TestException", context.Failure.Message); - context.SkipToNextMiddleware(); - return Task.FromResult(0); - }, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - context => + var events = new ExpectedOidcEvents() { - return context.Response.WriteAsync(context.Request.Path); - }); + ExpectMessageReceived = true, + ExpectAccessDenied = true + }; + events.OnAccessDenied = context => + { + context.SkipHandler(); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); + + var response = await PostAsync(server, "signin-oidc", "error=access_denied&state=protected_state"); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("/signin-oidc", await response.Content.ReadAsStringAsync()); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnAccessDenied_Handled_NoMoreEventsRun() + { + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectAccessDenied = true + }; + events.OnAccessDenied = context => + { + Assert.Equal("testvalue", context.Properties.Items["testkey"]); + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); + + var response = await PostAsync(server, "signin-oidc", "error=access_denied&state=protected_state"); + + Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); + Assert.Equal("", await response.Content.ReadAsStringAsync()); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnRemoteFailure_Skip_NoMoreEventsRun() + { + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectUserInfoReceived = true, + ExpectAuthenticationFailed = true, + ExpectRemoteFailure = true, + }; + events.OnUserInformationReceived = context => + { + throw new NotImplementedException("TestException"); + }; + events.OnAuthenticationFailed = context => + { + Assert.Equal("TestException", context.Exception.Message); + return Task.FromResult(0); + }; + events.OnRemoteFailure = context => + { + Assert.Equal("TestException", context.Failure.Message); + context.SkipHandler(); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("/signin-oidc", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(userInfoReceived); - Assert.True(authFailed); - Assert.True(remoteFailure); + events.ValidateExpectations(); } [Fact] public async Task OnRemoteFailure_Handled_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var tokenResponseReceived = false; - var userInfoReceived = false; - var authFailed = false; - var remoteFailure = false; - var server = CreateServer(new OpenIdConnectEvents() - { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - return Task.FromResult(0); - }, - OnUserInformationReceived = context => - { - userInfoReceived = true; - throw new NotImplementedException("TestException"); - }, - OnAuthenticationFailed = context => - { - authFailed = true; - Assert.Equal("TestException", context.Exception.Message); - return Task.FromResult(0); - }, - OnRemoteFailure = context => - { - remoteFailure = true; - Assert.Equal("TestException", context.Failure.Message); - context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - OnTicketReceived = TicketNotImpl, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectUserInfoReceived = true, + ExpectAuthenticationFailed = true, + ExpectRemoteFailure = true, + }; + events.OnUserInformationReceived = context => + { + throw new NotImplementedException("TestException"); + }; + events.OnRemoteFailure = context => + { + Assert.Equal("TestException", context.Failure.Message); + Assert.Equal("testvalue", context.Properties.Items["testkey"]); + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(userInfoReceived); - Assert.True(authFailed); - Assert.True(remoteFailure); + events.ValidateExpectations(); } [Fact] - public async Task OnTicketReceived_Skipped_NoMoreEventsRun() + public async Task OnTicketReceived_Skip_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var tokenResponseReceived = false; - var userInfoReceived = false; - var ticektReceived = false; - var server = CreateServer(new OpenIdConnectEvents() - { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - return Task.FromResult(0); - }, - OnUserInformationReceived = context => - { - userInfoReceived = true; - return Task.FromResult(0); - }, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = context => - { - ticektReceived = true; - context.SkipToNextMiddleware(); - return Task.FromResult(0); - }, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - context => + var events = new ExpectedOidcEvents() { - return context.Response.WriteAsync(context.Request.Path); - }); + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectUserInfoReceived = true, + ExpectTicketReceived = true, + }; + events.OnTicketReceived = context => + { + context.SkipHandler(); + return Task.FromResult(0); + }; + var server = CreateServer(events, AppWritePath); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("/signin-oidc", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(userInfoReceived); - Assert.True(ticektReceived); + events.ValidateExpectations(); } [Fact] public async Task OnTicketReceived_Handled_NoMoreEventsRun() { - var messageReceived = false; - var tokenValidated = false; - var codeReceived = false; - var tokenResponseReceived = false; - var userInfoReceived = false; - var ticektReceived = false; - var server = CreateServer(new OpenIdConnectEvents() - { - OnMessageReceived = context => - { - messageReceived = true; - return Task.FromResult(0); - }, - OnTokenValidated = context => - { - tokenValidated = true; - return Task.FromResult(0); - }, - OnAuthorizationCodeReceived = context => - { - codeReceived = true; - return Task.FromResult(0); - }, - OnTokenResponseReceived = context => - { - tokenResponseReceived = true; - return Task.FromResult(0); - }, - OnUserInformationReceived = context => - { - userInfoReceived = true; - return Task.FromResult(0); - }, - OnAuthenticationFailed = FailedNotImpl, - OnRemoteFailure = FailureNotImpl, - OnTicketReceived = context => - { - ticektReceived = true; - context.HandleResponse(); - context.Response.StatusCode = StatusCodes.Status202Accepted; - return Task.FromResult(0); - }, - - OnRedirectToIdentityProvider = RedirectNotImpl, - OnRedirectToIdentityProviderForSignOut = RedirectNotImpl, - OnRemoteSignOut = RemoteSignOutNotImpl, - }, - AppNotImpl); + var events = new ExpectedOidcEvents() + { + ExpectMessageReceived = true, + ExpectTokenValidated = true, + ExpectAuthorizationCodeReceived = true, + ExpectTokenResponseReceived = true, + ExpectUserInfoReceived = true, + ExpectTicketReceived = true, + }; + events.OnTicketReceived = context => + { + context.HandleResponse(); + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.FromResult(0); + }; + var server = CreateServer(events, AppNotImpl); var response = await PostAsync(server, "signin-oidc", "id_token=my_id_token&state=protected_state&code=my_code"); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); Assert.Equal("", await response.Content.ReadAsStringAsync()); - Assert.True(messageReceived); - Assert.True(tokenValidated); - Assert.True(codeReceived); - Assert.True(tokenResponseReceived); - Assert.True(userInfoReceived); - Assert.True(ticektReceived); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnRedirectToIdentityProviderForSignOut_Invoked() + { + var events = new ExpectedOidcEvents() + { + ExpectRedirectForSignOut = true, + }; + var server = CreateServer(events, + context => + { + return context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme); + }); + + var client = server.CreateClient(); + var response = await client.GetAsync("/"); + + Assert.Equal(HttpStatusCode.Found, response.StatusCode); + Assert.Equal("http://testhost/end", response.Headers.Location.GetLeftPart(UriPartial.Path)); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnRedirectToIdentityProviderForSignOut_Handled_RedirectNotInvoked() + { + var events = new ExpectedOidcEvents() + { + ExpectRedirectForSignOut = true, + }; + events.OnRedirectToIdentityProviderForSignOut = context => + { + context.Response.StatusCode = StatusCodes.Status202Accepted; + context.HandleResponse(); + return Task.CompletedTask; + }; + var server = CreateServer(events, + context => + { + return context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme); + }); + + var client = server.CreateClient(); + var response = await client.GetAsync("/"); + + Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); + Assert.Null(response.Headers.Location); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnRemoteSignOut_Invoked() + { + var events = new ExpectedOidcEvents() + { + ExpectRemoteSignOut = true, + }; + var server = CreateServer(events, AppNotImpl); + + var client = server.CreateClient(); + var response = await client.GetAsync("/signout-oidc"); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + events.ValidateExpectations(); + Assert.True(response.Headers.TryGetValues(HeaderNames.SetCookie, out var values)); + Assert.True(SetCookieHeaderValue.TryParseStrictList(values.ToList(), out var parsedValues)); + Assert.Equal(1, parsedValues.Count); + Assert.True(StringSegment.IsNullOrEmpty(parsedValues.Single().Value)); + } + + [Fact] + public async Task OnRemoteSignOut_Handled_NoSignout() + { + var events = new ExpectedOidcEvents() + { + ExpectRemoteSignOut = true, + }; + events.OnRemoteSignOut = context => + { + context.Response.StatusCode = StatusCodes.Status202Accepted; + context.HandleResponse(); + return Task.CompletedTask; + }; + var server = CreateServer(events, AppNotImpl); + + var client = server.CreateClient(); + var response = await client.GetAsync("/signout-oidc"); + + Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); + events.ValidateExpectations(); + Assert.False(response.Headers.TryGetValues(HeaderNames.SetCookie, out var values)); + } + + [Fact] + public async Task OnRemoteSignOut_Skip_NoSignout() + { + var events = new ExpectedOidcEvents() + { + ExpectRemoteSignOut = true, + }; + events.OnRemoteSignOut = context => + { + context.SkipHandler(); + return Task.CompletedTask; + }; + var server = CreateServer(events, context => + { + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.CompletedTask; + }); + + var client = server.CreateClient(); + var response = await client.GetAsync("/signout-oidc"); + + Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); + events.ValidateExpectations(); + Assert.False(response.Headers.TryGetValues(HeaderNames.SetCookie, out var values)); + } + + [Fact] + public async Task OnRedirectToSignedOutRedirectUri_Invoked() + { + var events = new ExpectedOidcEvents() + { + ExpectRedirectToSignedOut = true, + }; + var server = CreateServer(events, AppNotImpl); + + var client = server.CreateClient(); + var response = await client.GetAsync("/signout-callback-oidc?state=protected_state"); + + Assert.Equal(HttpStatusCode.Found, response.StatusCode); + Assert.Equal("http://testhost/redirect", response.Headers.Location.AbsoluteUri); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnRedirectToSignedOutRedirectUri_Handled_NoRedirect() + { + var events = new ExpectedOidcEvents() + { + ExpectRedirectToSignedOut = true, + }; + events.OnSignedOutCallbackRedirect = context => + { + context.Response.StatusCode = StatusCodes.Status202Accepted; + context.HandleResponse(); + return Task.CompletedTask; + }; + var server = CreateServer(events, AppNotImpl); + + var client = server.CreateClient(); + var response = await client.GetAsync("/signout-callback-oidc?state=protected_state"); + + Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); + Assert.Null(response.Headers.Location); + events.ValidateExpectations(); + } + + [Fact] + public async Task OnRedirectToSignedOutRedirectUri_Skipped_NoRedirect() + { + var events = new ExpectedOidcEvents() + { + ExpectRedirectToSignedOut = true, + }; + events.OnSignedOutCallbackRedirect = context => + { + context.SkipHandler(); + return Task.CompletedTask; + }; + var server = CreateServer(events, + context => + { + context.Response.StatusCode = StatusCodes.Status202Accepted; + return Task.CompletedTask; + }); + + var client = server.CreateClient(); + var response = await client.GetAsync("/signout-callback-oidc?state=protected_state"); + + Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); + Assert.Null(response.Headers.Location); + events.ValidateExpectations(); + } + + private class ExpectedOidcEvents : OpenIdConnectEvents + { + public bool ExpectMessageReceived { get; set; } + public bool InvokedMessageReceived { get; set; } + + public bool ExpectTokenValidated { get; set; } + public bool InvokedTokenValidated { get; set; } + + public bool ExpectAccessDenied { get; set; } + public bool InvokedAccessDenied { get; set; } + + public bool ExpectRemoteFailure { get; set; } + public bool InvokedRemoteFailure { get; set; } + + public bool ExpectTicketReceived { get; set; } + public bool InvokedTicketReceived { get; set; } + + public bool ExpectAuthorizationCodeReceived { get; set; } + public bool InvokedAuthorizationCodeReceived { get; set; } + + public bool ExpectTokenResponseReceived { get; set; } + public bool InvokedTokenResponseReceived { get; set; } + + public bool ExpectUserInfoReceived { get; set; } + public bool InvokedUserInfoReceived { get; set; } + + public bool ExpectAuthenticationFailed { get; set; } + public bool InvokeAuthenticationFailed { get; set; } + + public bool ExpectRedirectForSignOut { get; set; } + public bool InvokedRedirectForSignOut { get; set; } + + public bool ExpectRemoteSignOut { get; set; } + public bool InvokedRemoteSignOut { get; set; } + + public bool ExpectRedirectToSignedOut { get; set; } + public bool InvokedRedirectToSignedOut { get; set; } + + public override Task MessageReceived(MessageReceivedContext context) + { + InvokedMessageReceived = true; + return base.MessageReceived(context); + } + + public override Task TokenValidated(TokenValidatedContext context) + { + InvokedTokenValidated = true; + return base.TokenValidated(context); + } + + public override Task AuthorizationCodeReceived(AuthorizationCodeReceivedContext context) + { + InvokedAuthorizationCodeReceived = true; + return base.AuthorizationCodeReceived(context); + } + + public override Task TokenResponseReceived(TokenResponseReceivedContext context) + { + InvokedTokenResponseReceived = true; + return base.TokenResponseReceived(context); + } + + public override Task UserInformationReceived(UserInformationReceivedContext context) + { + InvokedUserInfoReceived = true; + return base.UserInformationReceived(context); + } + + public override Task AuthenticationFailed(AuthenticationFailedContext context) + { + InvokeAuthenticationFailed = true; + return base.AuthenticationFailed(context); + } + + public override Task TicketReceived(TicketReceivedContext context) + { + InvokedTicketReceived = true; + return base.TicketReceived(context); + } + + public override Task AccessDenied(AccessDeniedContext context) + { + InvokedAccessDenied = true; + return base.AccessDenied(context); + } + + public override Task RemoteFailure(RemoteFailureContext context) + { + InvokedRemoteFailure = true; + return base.RemoteFailure(context); + } + + public override Task RedirectToIdentityProviderForSignOut(RedirectContext context) + { + InvokedRedirectForSignOut = true; + return base.RedirectToIdentityProviderForSignOut(context); + } + + public override Task RemoteSignOut(RemoteSignOutContext context) + { + InvokedRemoteSignOut = true; + return base.RemoteSignOut(context); + } + + public override Task SignedOutCallbackRedirect(RemoteSignOutContext context) + { + InvokedRedirectToSignedOut = true; + return base.SignedOutCallbackRedirect(context); + } + + public void ValidateExpectations() + { + Assert.Equal(ExpectMessageReceived, InvokedMessageReceived); + Assert.Equal(ExpectTokenValidated, InvokedTokenValidated); + Assert.Equal(ExpectAuthorizationCodeReceived, InvokedAuthorizationCodeReceived); + Assert.Equal(ExpectTokenResponseReceived, InvokedTokenResponseReceived); + Assert.Equal(ExpectUserInfoReceived, InvokedUserInfoReceived); + Assert.Equal(ExpectAuthenticationFailed, InvokeAuthenticationFailed); + Assert.Equal(ExpectTicketReceived, InvokedTicketReceived); + Assert.Equal(ExpectAccessDenied, InvokedAccessDenied); + Assert.Equal(ExpectRemoteFailure, InvokedRemoteFailure); + Assert.Equal(ExpectRedirectForSignOut, InvokedRedirectForSignOut); + Assert.Equal(ExpectRemoteSignOut, InvokedRemoteSignOut); + Assert.Equal(ExpectRedirectToSignedOut, InvokedRedirectToSignedOut); + } } private TestServer CreateServer(OpenIdConnectEvents events, RequestDelegate appCode) @@ -1408,27 +1269,32 @@ private TestServer CreateServer(OpenIdConnectEvents events, RequestDelegate appC var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddAuthentication(); - }) - .Configure(app => - { - app.UseCookieAuthentication(); - app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions() + services.AddAuthentication(auth => + { + auth.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; + auth.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; + }) + .AddCookie() + .AddOpenIdConnect(o => { - Events = events, - SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme, - ClientId = "ClientId", - GetClaimsFromUserInfoEndpoint = true, - Configuration = new OpenIdConnectConfiguration() + o.Events = events; + o.ClientId = "ClientId"; + o.GetClaimsFromUserInfoEndpoint = true; + o.Configuration = new OpenIdConnectConfiguration() { TokenEndpoint = "http://testhost/tokens", UserInfoEndpoint = "http://testhost/user", - }, - StateDataFormat = new TestStateDataFormat(), - SecurityTokenValidator = new TestTokenValidator(), - ProtocolValidator = new TestProtocolValidator(), - BackchannelHttpHandler = new TestBackchannel(), + EndSessionEndpoint = "http://testhost/end" + }; + o.StateDataFormat = new TestStateDataFormat(); + o.SecurityTokenValidator = new TestTokenValidator(); + o.ProtocolValidator = new TestProtocolValidator(); + o.BackchannelHttpHandler = new TestBackchannel(); }); + }) + .Configure(app => + { + app.UseAuthentication(); app.Run(appCode); }); @@ -1438,7 +1304,7 @@ private TestServer CreateServer(OpenIdConnectEvents events, RequestDelegate appC private Task PostAsync(TestServer server, string path, string form) { var client = server.CreateClient(); - var cookie = ".AspNetCore.Correlation." + OpenIdConnectDefaults.AuthenticationScheme + ".corrilationId=N"; + var cookie = ".AspNetCore.Correlation." + OpenIdConnectDefaults.AuthenticationScheme + ".correlationId=N"; client.DefaultRequestHeaders.Add("Cookie", cookie); return client.PostAsync("signin-oidc", new StringContent(form, Encoding.ASCII, "application/x-www-form-urlencoded")); @@ -1450,7 +1316,7 @@ private class TestStateDataFormat : ISecureDataFormat public string Protect(AuthenticationProperties data) { - throw new NotImplementedException(); + return "protected_state"; } public string Protect(AuthenticationProperties data, string purpose) @@ -1461,11 +1327,14 @@ public string Protect(AuthenticationProperties data, string purpose) public AuthenticationProperties Unprotect(string protectedText) { Assert.Equal("protected_state", protectedText); - return new AuthenticationProperties(new Dictionary() + var properties = new AuthenticationProperties(new Dictionary() { - { ".xsrf", "corrilationId" }, - { OpenIdConnectDefaults.RedirectUriForCodePropertiesKey, "redirect_uri" } + { ".xsrf", "correlationId" }, + { OpenIdConnectDefaults.RedirectUriForCodePropertiesKey, "redirect_uri" }, + { "testkey", "testvalue" } }); + properties.RedirectUri = "http://testhost/redirect"; + return properties; } public AuthenticationProperties Unprotect(string protectedText, string purpose) diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectMiddlewareTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectMiddlewareTests.cs deleted file mode 100644 index 6c427c600..000000000 --- a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectMiddlewareTests.cs +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Globalization; -using System.Net; -using System.Text.Encodings.Web; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.IdentityModel.Protocols.OpenIdConnect; -using Xunit; - -namespace Microsoft.AspNetCore.Authentication.Tests.OpenIdConnect -{ - public class OpenIdConnectMiddlewareTests - { - static string noncePrefix = "OpenIdConnect." + "Nonce."; - static string nonceDelimiter = "."; - const string DefaultHost = @"https://example.com"; - const string Logout = "/logout"; - const string Signin = "/signin"; - const string Signout = "/signout"; - - - /// - /// Tests RedirectForSignOutContext replaces the OpenIdConnectMesssage correctly. - /// summary> - /// Task - [Fact] - public async Task SignOutSettingMessage() - { - var setting = new TestSettings(opt => - { - opt.Configuration = new OpenIdConnectConfiguration - { - EndSessionEndpoint = "https://example.com/signout_test/signout_request" - }; - }); - - var server = setting.CreateTestServer(); - - var transaction = await server.SendAsync(DefaultHost + TestServerBuilder.Signout); - var res = transaction.Response; - - Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); - Assert.NotNull(res.Headers.Location); - - setting.ValidateSignoutRedirect(transaction.Response.Headers.Location); - } - - [Fact] - public async Task SignOutWithDefaultRedirectUri() - { - var configuration = TestServerBuilder.CreateDefaultOpenIdConnectConfiguration(); - var options = new OpenIdConnectOptions - { - Authority = TestServerBuilder.DefaultAuthority, - ClientId = "Test Id", - Configuration = configuration - }; - var server = TestServerBuilder.CreateServer(options); - - var transaction = await server.SendAsync(DefaultHost + TestServerBuilder.Signout); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - Assert.True(transaction.Response.Headers.Location.AbsoluteUri.StartsWith(configuration.EndSessionEndpoint)); - - var query = transaction.Response.Headers.Location.Query.Substring(1).Split('&') - .Select(each => each.Split('=')) - .ToDictionary(pair => pair[0], pair => pair[1]); - - string redirectUri; - Assert.True(query.TryGetValue("post_logout_redirect_uri", out redirectUri)); - Assert.Equal(UrlEncoder.Default.Encode("https://example.com" + options.SignedOutCallbackPath), redirectUri, true); - } - - [Fact] - public async Task SignOutWithCustomRedirectUri() - { - var configuration = TestServerBuilder.CreateDefaultOpenIdConnectConfiguration(); - var options = new OpenIdConnectOptions - { - Authority = TestServerBuilder.DefaultAuthority, - ClientId = "Test Id", - Configuration = configuration, - SignedOutCallbackPath = "/thelogout", - PostLogoutRedirectUri = "https://example.com/postlogout" - }; - var server = TestServerBuilder.CreateServer(options); - - var transaction = await server.SendAsync(DefaultHost + TestServerBuilder.Signout); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - - var query = transaction.Response.Headers.Location.Query.Substring(1).Split('&') - .Select(each => each.Split('=')) - .ToDictionary(pair => pair[0], pair => pair[1]); - - string redirectUri; - Assert.True(query.TryGetValue("post_logout_redirect_uri", out redirectUri)); - Assert.Equal(UrlEncoder.Default.Encode("https://example.com" + options.SignedOutCallbackPath), redirectUri, true); - - string state; - Assert.True(query.TryGetValue("state", out state)); - var properties = options.StateDataFormat.Unprotect(state); - Assert.Equal("https://example.com/postlogout", properties.RedirectUri, true); - } - - [Fact] - public async Task SignOutWith_Specific_RedirectUri_From_Authentication_Properites() - { - var configuration = TestServerBuilder.CreateDefaultOpenIdConnectConfiguration(); - var options = new OpenIdConnectOptions - { - Authority = TestServerBuilder.DefaultAuthority, - ClientId = "Test Id", - Configuration = configuration, - PostLogoutRedirectUri = "https://example.com/postlogout" - }; - var server = TestServerBuilder.CreateServer(options); - - var transaction = await server.SendAsync("https://example.com/signout_with_specific_redirect_uri"); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - - var query = transaction.Response.Headers.Location.Query.Substring(1).Split('&') - .Select(each => each.Split('=')) - .ToDictionary(pair => pair[0], pair => pair[1]); - - string redirectUri; - Assert.True(query.TryGetValue("post_logout_redirect_uri", out redirectUri)); - Assert.Equal(UrlEncoder.Default.Encode("https://example.com" + options.SignedOutCallbackPath), redirectUri, true); - - string state; - Assert.True(query.TryGetValue("state", out state)); - var properties = options.StateDataFormat.Unprotect(state); - Assert.Equal("http://www.example.com/specific_redirect_uri", properties.RedirectUri, true); - } - - [Fact] - public async Task SignOut_WithMissingConfig_Throws() - { - var setting = new TestSettings(opt => opt.Configuration = new OpenIdConnectConfiguration()); - - var server = setting.CreateTestServer(); - - var exception = await Assert.ThrowsAsync(() => server.SendAsync(DefaultHost + TestServerBuilder.Signout)); - Assert.Equal("Cannot redirect to the end session endpoint, the configuration may be missing or invalid.", exception.Message); - } - - // Test Cases for calculating the expiration time of cookie from cookie name - [Fact] - public void NonceCookieExpirationTime() - { - DateTime utcNow = DateTime.UtcNow; - - Assert.Equal(DateTime.MaxValue, GetNonceExpirationTime(noncePrefix + DateTime.MaxValue.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter, TimeSpan.FromHours(1))); - - Assert.Equal(DateTime.MinValue + TimeSpan.FromHours(1), GetNonceExpirationTime(noncePrefix + DateTime.MinValue.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter, TimeSpan.FromHours(1))); - - Assert.Equal(utcNow + TimeSpan.FromHours(1), GetNonceExpirationTime(noncePrefix + utcNow.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter, TimeSpan.FromHours(1))); - - Assert.Equal(DateTime.MinValue, GetNonceExpirationTime(noncePrefix, TimeSpan.FromHours(1))); - - Assert.Equal(DateTime.MinValue, GetNonceExpirationTime("", TimeSpan.FromHours(1))); - - Assert.Equal(DateTime.MinValue, GetNonceExpirationTime(noncePrefix + noncePrefix, TimeSpan.FromHours(1))); - - Assert.Equal(utcNow + TimeSpan.FromHours(1), GetNonceExpirationTime(noncePrefix + utcNow.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter + utcNow.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter, TimeSpan.FromHours(1))); - - Assert.Equal(DateTime.MinValue, GetNonceExpirationTime(utcNow.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter + utcNow.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter, TimeSpan.FromHours(1))); - } - - private static DateTime GetNonceExpirationTime(string keyname, TimeSpan nonceLifetime) - { - DateTime nonceTime = DateTime.MinValue; - string timestamp = null; - int endOfTimestamp; - if (keyname.StartsWith(noncePrefix, StringComparison.Ordinal)) - { - timestamp = keyname.Substring(noncePrefix.Length); - endOfTimestamp = timestamp.IndexOf('.'); - - if (endOfTimestamp != -1) - { - timestamp = timestamp.Substring(0, endOfTimestamp); - try - { - nonceTime = DateTime.FromBinary(Convert.ToInt64(timestamp, CultureInfo.InvariantCulture)); - if ((nonceTime >= DateTime.UtcNow) && ((DateTime.MaxValue - nonceTime) < nonceLifetime)) - nonceTime = DateTime.MaxValue; - else - nonceTime += nonceLifetime; - } - catch - { - } - } - } - - return nonceTime; - } - - } -} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectTests.cs new file mode 100644 index 000000000..da52e0e4c --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/OpenIdConnectTests.cs @@ -0,0 +1,351 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.IdentityModel.Protocols.OpenIdConnect; +using Xunit; + +namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect +{ + public class OpenIdConnectTests + { + static string noncePrefix = "OpenIdConnect." + "Nonce."; + static string nonceDelimiter = "."; + const string DefaultHost = @"https://example.com"; + const string Logout = "/logout"; + const string Signin = "/signin"; + const string Signout = "/signout"; + + /// + /// Tests RedirectForSignOutContext replaces the OpenIdConnectMesssage correctly. + /// + /// Task + [Fact] + public async Task SignOutSettingMessage() + { + var setting = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + opt.Configuration = new OpenIdConnectConfiguration + { + EndSessionEndpoint = "https://example.com/signout_test/signout_request" + }; + }); + + var server = setting.CreateTestServer(); + + var transaction = await server.SendAsync(DefaultHost + TestServerBuilder.Signout); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.NotNull(res.Headers.Location); + + setting.ValidateSignoutRedirect( + transaction.Response.Headers.Location, + OpenIdConnectParameterNames.SkuTelemetry, + OpenIdConnectParameterNames.VersionTelemetry); + } + + [Fact] + public async Task RedirectToIdentityProvider_SetsNonceCookiePath_ToCallBackPath() + { + var setting = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + opt.Configuration = new OpenIdConnectConfiguration + { + AuthorizationEndpoint = "https://example.com/provider/login" + }; + }); + + var server = setting.CreateTestServer(); + + var transaction = await server.SendAsync(DefaultHost + TestServerBuilder.Challenge); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.NotNull(res.Headers.Location); + var setCookie = Assert.Single(res.Headers, h => h.Key == "Set-Cookie"); + var nonce = Assert.Single(setCookie.Value, v => v.StartsWith(OpenIdConnectDefaults.CookieNoncePrefix)); + Assert.Contains("path=/signin-oidc", nonce); + } + + [Fact] + public async Task RedirectToIdentityProvider_NonceCookieOptions_CanBeOverriden() + { + var setting = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + opt.Configuration = new OpenIdConnectConfiguration + { + AuthorizationEndpoint = "https://example.com/provider/login" + }; + opt.NonceCookie.Path = "/"; + }); + + var server = setting.CreateTestServer(); + + var transaction = await server.SendAsync(DefaultHost + TestServerBuilder.Challenge); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.NotNull(res.Headers.Location); + var setCookie = Assert.Single(res.Headers, h => h.Key == "Set-Cookie"); + var nonce = Assert.Single(setCookie.Value, v => v.StartsWith(OpenIdConnectDefaults.CookieNoncePrefix)); + Assert.Contains("path=/", nonce); + } + + [Fact] + public async Task RedirectToIdentityProvider_SetsCorrelationIdCookiePath_ToCallBackPath() + { + var setting = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + opt.Configuration = new OpenIdConnectConfiguration + { + AuthorizationEndpoint = "https://example.com/provider/login" + }; + }); + + var server = setting.CreateTestServer(); + + var transaction = await server.SendAsync(DefaultHost + TestServerBuilder.Challenge); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.NotNull(res.Headers.Location); + var setCookie = Assert.Single(res.Headers, h => h.Key == "Set-Cookie"); + var correlation = Assert.Single(setCookie.Value, v => v.StartsWith(".AspNetCore.Correlation.")); + Assert.Contains("path=/signin-oidc", correlation); + } + + [Fact] + public async Task RedirectToIdentityProvider_CorrelationIdCookieOptions_CanBeOverriden() + { + var setting = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + opt.Configuration = new OpenIdConnectConfiguration + { + AuthorizationEndpoint = "https://example.com/provider/login" + }; + opt.CorrelationCookie.Path = "/"; + }); + + var server = setting.CreateTestServer(); + + var transaction = await server.SendAsync(DefaultHost + TestServerBuilder.Challenge); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.NotNull(res.Headers.Location); + var setCookie = Assert.Single(res.Headers, h => h.Key == "Set-Cookie"); + var correlation = Assert.Single(setCookie.Value, v => v.StartsWith(".AspNetCore.Correlation.")); + Assert.Contains("path=/", correlation); + } + + [Fact] + public async Task EndSessionRequestDoesNotIncludeTelemetryParametersWhenDisabled() + { + var configuration = TestServerBuilder.CreateDefaultOpenIdConnectConfiguration(); + var setting = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.Configuration = configuration; + opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + opt.DisableTelemetry = true; + }); + + var server = setting.CreateTestServer(); + + var transaction = await server.SendAsync(DefaultHost + TestServerBuilder.Signout); + var res = transaction.Response; + + Assert.Equal(HttpStatusCode.Redirect, res.StatusCode); + Assert.DoesNotContain(OpenIdConnectParameterNames.SkuTelemetry, res.Headers.Location.Query); + Assert.DoesNotContain(OpenIdConnectParameterNames.VersionTelemetry, res.Headers.Location.Query); + setting.ValidateSignoutRedirect(transaction.Response.Headers.Location); + } + + [Fact] + public async Task SignOutFormPostWithDefaultRedirectUri() + { + var settings = new TestSettings(o => + { + o.AuthenticationMethod = OpenIdConnectRedirectBehavior.FormPost; + o.Authority = TestServerBuilder.DefaultAuthority; + o.ClientId = "Test Id"; + }); + var server = settings.CreateTestServer(); + + var transaction = await server.SendAsync(DefaultHost + TestServerBuilder.Signout); + Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); + + settings.ValidateSignoutFormPost(transaction, + OpenIdConnectParameterNames.PostLogoutRedirectUri); + } + + [Fact] + public async Task SignOutRedirectWithDefaultRedirectUri() + { + var settings = new TestSettings(o => + { + o.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet; + o.Authority = TestServerBuilder.DefaultAuthority; + o.ClientId = "Test Id"; + }); + var server = settings.CreateTestServer(); + + var transaction = await server.SendAsync(DefaultHost + TestServerBuilder.Signout); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + + settings.ValidateSignoutRedirect(transaction.Response.Headers.Location, + OpenIdConnectParameterNames.PostLogoutRedirectUri); + } + + [Fact] + public async Task SignOutWithCustomRedirectUri() + { + var configuration = TestServerBuilder.CreateDefaultOpenIdConnectConfiguration(); + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("OIDCTest")); + var server = TestServerBuilder.CreateServer(o => + { + o.Authority = TestServerBuilder.DefaultAuthority; + o.ClientId = "Test Id"; + o.Configuration = configuration; + o.StateDataFormat = stateFormat; + o.SignedOutCallbackPath = "/thelogout"; + o.SignedOutRedirectUri = "https://example.com/postlogout"; + }); + + var transaction = await server.SendAsync(DefaultHost + TestServerBuilder.Signout); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + + var query = transaction.Response.Headers.Location.Query.Substring(1).Split('&') + .Select(each => each.Split('=')) + .ToDictionary(pair => pair[0], pair => pair[1]); + + string redirectUri; + Assert.True(query.TryGetValue("post_logout_redirect_uri", out redirectUri)); + Assert.Equal(UrlEncoder.Default.Encode("https://example.com/thelogout"), redirectUri, true); + + string state; + Assert.True(query.TryGetValue("state", out state)); + var properties = stateFormat.Unprotect(state); + Assert.Equal("https://example.com/postlogout", properties.RedirectUri, true); + } + + [Fact] + public async Task SignOutWith_Specific_RedirectUri_From_Authentication_Properites() + { + var configuration = TestServerBuilder.CreateDefaultOpenIdConnectConfiguration(); + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("OIDCTest")); + var server = TestServerBuilder.CreateServer(o => + { + o.Authority = TestServerBuilder.DefaultAuthority; + o.StateDataFormat = stateFormat; + o.ClientId = "Test Id"; + o.Configuration = configuration; + o.SignedOutRedirectUri = "https://example.com/postlogout"; + }); + + var transaction = await server.SendAsync("https://example.com/signout_with_specific_redirect_uri"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + + var query = transaction.Response.Headers.Location.Query.Substring(1).Split('&') + .Select(each => each.Split('=')) + .ToDictionary(pair => pair[0], pair => pair[1]); + + string redirectUri; + Assert.True(query.TryGetValue("post_logout_redirect_uri", out redirectUri)); + Assert.Equal(UrlEncoder.Default.Encode("https://example.com/signout-callback-oidc"), redirectUri, true); + + string state; + Assert.True(query.TryGetValue("state", out state)); + var properties = stateFormat.Unprotect(state); + Assert.Equal("http://www.example.com/specific_redirect_uri", properties.RedirectUri, true); + } + + [Fact] + public async Task SignOut_WithMissingConfig_Throws() + { + var setting = new TestSettings(opt => + { + opt.ClientId = "Test Id"; + opt.Configuration = new OpenIdConnectConfiguration(); + }); + var server = setting.CreateTestServer(); + + var exception = await Assert.ThrowsAsync(() => server.SendAsync(DefaultHost + TestServerBuilder.Signout)); + Assert.Equal("Cannot redirect to the end session endpoint, the configuration may be missing or invalid.", exception.Message); + } + + // Test Cases for calculating the expiration time of cookie from cookie name + [Fact] + public void NonceCookieExpirationTime() + { + DateTime utcNow = DateTime.UtcNow; + + Assert.Equal(DateTime.MaxValue, GetNonceExpirationTime(noncePrefix + DateTime.MaxValue.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter, TimeSpan.FromHours(1))); + + Assert.Equal(DateTime.MinValue + TimeSpan.FromHours(1), GetNonceExpirationTime(noncePrefix + DateTime.MinValue.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter, TimeSpan.FromHours(1))); + + Assert.Equal(utcNow + TimeSpan.FromHours(1), GetNonceExpirationTime(noncePrefix + utcNow.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter, TimeSpan.FromHours(1))); + + Assert.Equal(DateTime.MinValue, GetNonceExpirationTime(noncePrefix, TimeSpan.FromHours(1))); + + Assert.Equal(DateTime.MinValue, GetNonceExpirationTime("", TimeSpan.FromHours(1))); + + Assert.Equal(DateTime.MinValue, GetNonceExpirationTime(noncePrefix + noncePrefix, TimeSpan.FromHours(1))); + + Assert.Equal(utcNow + TimeSpan.FromHours(1), GetNonceExpirationTime(noncePrefix + utcNow.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter + utcNow.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter, TimeSpan.FromHours(1))); + + Assert.Equal(DateTime.MinValue, GetNonceExpirationTime(utcNow.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter + utcNow.Ticks.ToString(CultureInfo.InvariantCulture) + nonceDelimiter, TimeSpan.FromHours(1))); + } + + private static DateTime GetNonceExpirationTime(string keyname, TimeSpan nonceLifetime) + { + DateTime nonceTime = DateTime.MinValue; + string timestamp = null; + int endOfTimestamp; + if (keyname.StartsWith(noncePrefix, StringComparison.Ordinal)) + { + timestamp = keyname.Substring(noncePrefix.Length); + endOfTimestamp = timestamp.IndexOf('.'); + + if (endOfTimestamp != -1) + { + timestamp = timestamp.Substring(0, endOfTimestamp); + try + { + nonceTime = DateTime.FromBinary(Convert.ToInt64(timestamp, CultureInfo.InvariantCulture)); + if ((nonceTime >= DateTime.UtcNow) && ((DateTime.MaxValue - nonceTime) < nonceLifetime)) + nonceTime = DateTime.MaxValue; + else + nonceTime += nonceLifetime; + } + catch + { + } + } + } + + return nonceTime; + } + + } +} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestServerBuilder.cs b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestServerBuilder.cs index 5a672093e..c37da8c04 100644 --- a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestServerBuilder.cs +++ b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestServerBuilder.cs @@ -9,13 +9,12 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Protocols; using Microsoft.IdentityModel.Protocols.OpenIdConnect; -namespace Microsoft.AspNetCore.Authentication.Tests.OpenIdConnect +namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect { internal class TestServerBuilder { @@ -38,12 +37,7 @@ public static OpenIdConnectOptions CreateOpenIdConnectOptions() => public static OpenIdConnectOptions CreateOpenIdConnectOptions(Action update) { var options = CreateOpenIdConnectOptions(); - - if (update != null) - { - update(options); - } - + update?.Invoke(options); return options; } @@ -58,26 +52,20 @@ public static OpenIdConnectConfiguration CreateDefaultOpenIdConnectConfiguration public static IConfigurationManager CreateDefaultOpenIdConnectConfigurationManager() => new StaticConfigurationManager(CreateDefaultOpenIdConnectConfiguration()); - public static TestServer CreateServer(OpenIdConnectOptions options) + public static TestServer CreateServer(Action options) { return CreateServer(options, handler: null, properties: null); } public static TestServer CreateServer( - OpenIdConnectOptions options, + Action options, Func handler, AuthenticationProperties properties) { var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme - }); - - app.UseOpenIdConnectAuthentication(options); - + app.UseAuthentication(); app.Use(async (context, next) => { var req = context.Request; @@ -85,11 +73,11 @@ public static TestServer CreateServer( if (req.Path == new PathString(Challenge)) { - await context.Authentication.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme); + await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme); } else if (req.Path == new PathString(ChallengeWithProperties)) { - await context.Authentication.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, properties); + await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, properties); } else if (req.Path == new PathString(ChallengeWithOutContext)) { @@ -97,16 +85,15 @@ public static TestServer CreateServer( } else if (req.Path == new PathString(Signin)) { - // REVIEW: this used to just be res.SignIn() - await context.Authentication.SignInAsync(OpenIdConnectDefaults.AuthenticationScheme, new ClaimsPrincipal()); + await context.SignInAsync(OpenIdConnectDefaults.AuthenticationScheme, new ClaimsPrincipal()); } else if (req.Path == new PathString(Signout)) { - await context.Authentication.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme); + await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme); } else if (req.Path == new PathString("/signout_with_specific_redirect_uri")) { - await context.Authentication.SignOutAsync( + await context.SignOutAsync( OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties() { RedirectUri = "http://www.example.com/specific_redirect_uri" }); } @@ -122,8 +109,9 @@ await context.Authentication.SignOutAsync( }) .ConfigureServices(services => { - services.AddAuthentication(); - services.Configure(authOptions => authOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme); + services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) + .AddCookie() + .AddOpenIdConnect(options); }); return new TestServer(builder); diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestServerExtensions.cs b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestServerExtensions.cs index a7085966a..609aed6f6 100644 --- a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestServerExtensions.cs +++ b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestServerExtensions.cs @@ -5,7 +5,6 @@ using System.Net.Http; using System.Threading.Tasks; using System.Xml.Linq; -using Microsoft.AspNetCore.Authentication.Tests.OpenIdConnect; using Microsoft.AspNetCore.TestHost; namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestSettings.cs b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestSettings.cs index 3e50a7abe..eb045b438 100644 --- a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestSettings.cs +++ b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestSettings.cs @@ -4,23 +4,29 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; +using System.Net.Http; +using System.Reflection; using System.Text; using System.Text.Encodings.Web; +using System.Threading; +using System.Threading.Tasks; using System.Xml.Linq; -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.TestHost; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Xunit; -namespace Microsoft.AspNetCore.Authentication.Tests.OpenIdConnect +namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect { /// /// This helper class is used to check that query string parameters are as expected. /// internal class TestSettings { - private readonly OpenIdConnectOptions _options; + private readonly Action _configureOptions; + private OpenIdConnectOptions _options; public TestSettings() : this(configure: null) { @@ -28,21 +34,19 @@ public TestSettings() : this(configure: null) public TestSettings(Action configure) { - _options = TestServerBuilder.CreateOpenIdConnectOptions(configure); - } - - public TestSettings(OpenIdConnectOptions options) - { - _options = options; + _configureOptions = o => + { + configure?.Invoke(o); + _options = o; + _options.BackchannelHttpHandler = new MockBackchannel(); + }; } - public OpenIdConnectOptions Options => _options; - public UrlEncoder Encoder => UrlEncoder.Default; public string ExpectedState { get; set; } - public TestServer CreateTestServer() => TestServerBuilder.CreateServer(Options); + public TestServer CreateTestServer(AuthenticationProperties properties = null) => TestServerBuilder.CreateServer(_configureOptions, handler: null, properties: properties); public IDictionary ValidateChallengeFormPost(string responseBody, params string[] parametersToValidate) { @@ -82,6 +86,44 @@ public IDictionary ValidateChallengeFormPost(string responseBody return formInputs; } + public IDictionary ValidateSignoutFormPost(TestTransaction transaction, params string[] parametersToValidate) + { + IDictionary formInputs = null; + var errors = new List(); + var xdoc = XDocument.Parse(transaction.ResponseText.Replace("doctype", "DOCTYPE")); + var forms = xdoc.Descendants("form"); + if (forms.Count() != 1) + { + errors.Add("Only one form element is expected in response body."); + } + else + { + formInputs = forms.Single() + .Elements("input") + .ToDictionary(elem => elem.Attribute("name").Value, + elem => elem.Attribute("value").Value); + + ValidateParameters(formInputs, parametersToValidate, errors, htmlEncoded: false); + } + + if (errors.Any()) + { + var buf = new StringBuilder(); + buf.AppendLine($"The signout form post is not valid."); + // buf.AppendLine(); + + foreach (var error in errors) + { + buf.AppendLine(error); + } + + Debug.WriteLine(buf.ToString()); + Assert.True(false, buf.ToString()); + } + + return formInputs; + } + public IDictionary ValidateChallengeRedirect(Uri redirectUri, params string[] parametersToValidate) => ValidateRedirectCore(redirectUri, OpenIdConnectRequestType.Authentication, parametersToValidate); @@ -152,6 +194,21 @@ private void ValidateParameters( case OpenIdConnectParameterNames.State: ValidateState(actualValues, errors, htmlEncoded); break; + case OpenIdConnectParameterNames.SkuTelemetry: + ValidateSkuTelemetry(actualValues, errors); + break; + case OpenIdConnectParameterNames.VersionTelemetry: + ValidateVersionTelemetry(actualValues, errors, htmlEncoded); + break; + case OpenIdConnectParameterNames.PostLogoutRedirectUri: + ValidatePostLogoutRedirectUri(actualValues, errors, htmlEncoded); + break; + case OpenIdConnectParameterNames.MaxAge: + ValidateMaxAge(actualValues, errors, htmlEncoded); + break; + case OpenIdConnectParameterNames.Prompt: + ValidatePrompt(actualValues, errors, htmlEncoded); + break; default: throw new InvalidOperationException($"Unknown parameter \"{paramToValidate}\"."); } @@ -180,36 +237,67 @@ private void ValidateExpectedAuthority(string absoluteUri, ICollection e } } - private void ValidateClientId(IDictionary actualQuery, ICollection errors, bool htmlEncoded) => - ValidateQueryParameter(OpenIdConnectParameterNames.ClientId, _options.ClientId, actualQuery, errors, htmlEncoded); + private void ValidateClientId(IDictionary actualParams, ICollection errors, bool htmlEncoded) => + ValidateParameter(OpenIdConnectParameterNames.ClientId, _options.ClientId, actualParams, errors, htmlEncoded); - private void ValidateResponseType(IDictionary actualQuery, ICollection errors, bool htmlEncoded) => - ValidateQueryParameter(OpenIdConnectParameterNames.ResponseType, _options.ResponseType, actualQuery, errors, htmlEncoded); + private void ValidateResponseType(IDictionary actualParams, ICollection errors, bool htmlEncoded) => + ValidateParameter(OpenIdConnectParameterNames.ResponseType, _options.ResponseType, actualParams, errors, htmlEncoded); - private void ValidateResponseMode(IDictionary actualQuery, ICollection errors, bool htmlEncoded) => - ValidateQueryParameter(OpenIdConnectParameterNames.ResponseMode, _options.ResponseMode, actualQuery, errors, htmlEncoded); + private void ValidateResponseMode(IDictionary actualParams, ICollection errors, bool htmlEncoded) => + ValidateParameter(OpenIdConnectParameterNames.ResponseMode, _options.ResponseMode, actualParams, errors, htmlEncoded); - private void ValidateScope(IDictionary actualQuery, ICollection errors, bool htmlEncoded) => - ValidateQueryParameter(OpenIdConnectParameterNames.Scope, string.Join(" ", _options.Scope), actualQuery, errors, htmlEncoded); + private void ValidateScope(IDictionary actualParams, ICollection errors, bool htmlEncoded) => + ValidateParameter(OpenIdConnectParameterNames.Scope, string.Join(" ", _options.Scope), actualParams, errors, htmlEncoded); - private void ValidateRedirectUri(IDictionary actualQuery, ICollection errors, bool htmlEncoded) => - ValidateQueryParameter(OpenIdConnectParameterNames.RedirectUri, TestServerBuilder.TestHost + _options.CallbackPath, actualQuery, errors, htmlEncoded); + private void ValidateRedirectUri(IDictionary actualParams, ICollection errors, bool htmlEncoded) => + ValidateParameter(OpenIdConnectParameterNames.RedirectUri, TestServerBuilder.TestHost + _options.CallbackPath, actualParams, errors, htmlEncoded); - private void ValidateResource(IDictionary actualQuery, ICollection errors, bool htmlEncoded) => - ValidateQueryParameter(OpenIdConnectParameterNames.RedirectUri, _options.Resource, actualQuery, errors, htmlEncoded); + private void ValidateResource(IDictionary actualParams, ICollection errors, bool htmlEncoded) => + ValidateParameter(OpenIdConnectParameterNames.RedirectUri, _options.Resource, actualParams, errors, htmlEncoded); - private void ValidateState(IDictionary actualQuery, ICollection errors, bool htmlEncoded) => - ValidateQueryParameter(OpenIdConnectParameterNames.State, ExpectedState, actualQuery, errors, htmlEncoded); + private void ValidateState(IDictionary actualParams, ICollection errors, bool htmlEncoded) => + ValidateParameter(OpenIdConnectParameterNames.State, ExpectedState, actualParams, errors, htmlEncoded); - private void ValidateQueryParameter( + private static void ValidateSkuTelemetry(IDictionary actualParams, ICollection errors) + { + if (!actualParams.ContainsKey(OpenIdConnectParameterNames.SkuTelemetry)) + { + errors.Add($"Parameter {OpenIdConnectParameterNames.SkuTelemetry} is missing"); + } + } + + private void ValidateVersionTelemetry(IDictionary actualParams, ICollection errors, bool htmlEncoded) => + ValidateParameter(OpenIdConnectParameterNames.VersionTelemetry, typeof(OpenIdConnectMessage).GetTypeInfo().Assembly.GetName().Version.ToString(), actualParams, errors, htmlEncoded); + + private void ValidatePostLogoutRedirectUri(IDictionary actualParams, ICollection errors, bool htmlEncoded) => + ValidateParameter(OpenIdConnectParameterNames.PostLogoutRedirectUri, "https://example.com/signout-callback-oidc", actualParams, errors, htmlEncoded); + + private void ValidateMaxAge(IDictionary actualQuery, ICollection errors, bool htmlEncoded) + { + if(_options.MaxAge.HasValue) + { + Assert.Equal(TimeSpan.FromMinutes(20), _options.MaxAge.Value); + string expectedMaxAge = "1200"; + ValidateParameter(OpenIdConnectParameterNames.MaxAge, expectedMaxAge, actualQuery, errors, htmlEncoded); + } + else if(actualQuery.ContainsKey(OpenIdConnectParameterNames.MaxAge)) + { + errors.Add($"Parameter {OpenIdConnectParameterNames.MaxAge} is present but it should be absent"); + } + } + + private void ValidatePrompt(IDictionary actualParams, ICollection errors, bool htmlEncoded) => + ValidateParameter(OpenIdConnectParameterNames.Prompt, _options.Prompt, actualParams, errors, htmlEncoded); + + private void ValidateParameter( string parameterName, string expectedValue, - IDictionary actualQuery, + IDictionary actualParams, ICollection errors, bool htmlEncoded) { string actualValue; - if (actualQuery.TryGetValue(parameterName, out actualValue)) + if (actualParams.TryGetValue(parameterName, out actualValue)) { if (htmlEncoded) { @@ -218,13 +306,45 @@ private void ValidateQueryParameter( if (actualValue != expectedValue) { - errors.Add($"Query parameter {parameterName}'s expected value is {expectedValue} but its actual value is {actualValue}"); + errors.Add($"Parameter {parameterName}'s expected value is '{expectedValue}' but its actual value is '{actualValue}'"); } } else { - errors.Add($"Query parameter {parameterName} is missing"); + errors.Add($"Parameter {parameterName} is missing"); + } + } + + private class MockBackchannel : HttpMessageHandler + { + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + if (request.RequestUri.AbsoluteUri.Equals("https://login.microsoftonline.com/common/.well-known/openid-configuration")) + { + return await ReturnResource("wellknownconfig.json"); + } + if (request.RequestUri.AbsoluteUri.Equals("https://login.microsoftonline.com/common/discovery/keys")) + { + return await ReturnResource("wellknownkeys.json"); + } + + throw new NotImplementedException(); + } + + private async Task ReturnResource(string resource) + { + var resourceName = "Microsoft.AspNetCore.Authentication.Test.OpenIdConnect." + resource; + using (var stream = typeof(MockBackchannel).Assembly.GetManifestResourceStream(resourceName)) + using (var reader = new StreamReader(stream)) + { + var body = await reader.ReadToEndAsync(); + var content = new StringContent(body, Encoding.UTF8, "application/json"); + return new HttpResponseMessage() + { + Content = content, + }; + } } } } -} +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestTransaction.cs b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestTransaction.cs index 745c41350..4f924172c 100644 --- a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestTransaction.cs +++ b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/TestTransaction.cs @@ -6,7 +6,7 @@ using System.Net.Http; using System.Xml.Linq; -namespace Microsoft.AspNetCore.Authentication.Tests.OpenIdConnect +namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect { internal class TestTransaction { diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/wellknownconfig.json b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/wellknownconfig.json new file mode 100644 index 000000000..4d46a8cf0 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/wellknownconfig.json @@ -0,0 +1,23 @@ +{ + "authorization_endpoint": "https://login.microsoftonline.com/common/oauth2/authorize", + "token_endpoint": "https://login.microsoftonline.com/common/oauth2/token", + "token_endpoint_auth_methods_supported": [ "client_secret_post", "private_key_jwt", "client_secret_basic" ], + "jwks_uri": "https://login.microsoftonline.com/common/discovery/keys", + "response_modes_supported": [ "query", "fragment", "form_post" ], + "subject_types_supported": [ "pairwise" ], + "id_token_signing_alg_values_supported": [ "RS256" ], + "http_logout_supported": true, + "frontchannel_logout_supported": true, + "end_session_endpoint": "https://login.microsoftonline.com/common/oauth2/logout", + "response_types_supported": [ "code", "id_token", "code id_token", "token id_token", "token" ], + "scopes_supported": [ "openid" ], + "issuer": "https://sts.windows.net/{tenantid}/", + "claims_supported": [ "sub", "iss", "cloud_instance_name", "cloud_instance_host_name", "cloud_graph_host_name", "msgraph_host", "aud", "exp", "iat", "auth_time", "acr", "amr", "nonce", "email", "given_name", "family_name", "nickname" ], + "microsoft_multi_refresh_token": true, + "check_session_iframe": "https://login.microsoftonline.com/common/oauth2/checksession", + "userinfo_endpoint": "https://login.microsoftonline.com/common/openid/userinfo", + "tenant_region_scope": null, + "cloud_instance_name": "microsoftonline.com", + "cloud_graph_host_name": "graph.windows.net", + "msgraph_host": "graph.microsoft.com" +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/wellknownkeys.json b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/wellknownkeys.json new file mode 100644 index 000000000..77cc5562a --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/OpenIdConnect/wellknownkeys.json @@ -0,0 +1,31 @@ +{ + "keys": [ + { + "kty": "RSA", + "use": "sig", + "kid": "SSQdhI1cKvhQEDSJxE2gGYs40Q0", + "x5t": "SSQdhI1cKvhQEDSJxE2gGYs40Q0", + "n": "pJUB90EMxiNjgkVz5CLLUuG5bYwirL2LXfVsq_nnY686WzbinkvFnNs6LvrJ6DWD5NV1-0Tq2eZj7WU8H9ytmDPsRnJ0b49gRCJYOg6-SdOe9Tl0lB0IBJE1aWh3OdCVrZLE4LH4-LGIDrkwnCV8dKFkO3EIUYPaEysL4g4wLx-TCfpMWE37XC09P-nBRVkRNcihrzY38_MC42NkRdDwByZemXkQKddnn5Y5o4rVzPGqQy3vjmTjKolYEIBYa7n3yF0848MG0k338bjnyceJgmZzjxttkWTVDikQXSldbu3QCrCAlipbWPUAXaZK8buY8LP80G4U_wx4LuZ_Krq5OQ", + "e": "AQAB", + "x5c": [ "MIIDBTCCAe2gAwIBAgIQHJ7yHxNEM7tBeqcRTMBhhTANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE4MDEwODAwMDAwMFoXDTIwMDEwOTAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKSVAfdBDMYjY4JFc+Qiy1LhuW2MIqy9i131bKv552OvOls24p5LxZzbOi76yeg1g+TVdftE6tnmY+1lPB/crZgz7EZydG+PYEQiWDoOvknTnvU5dJQdCASRNWlodznQla2SxOCx+PixiA65MJwlfHShZDtxCFGD2hMrC+IOMC8fkwn6TFhN+1wtPT/pwUVZETXIoa82N/PzAuNjZEXQ8AcmXpl5ECnXZ5+WOaOK1czxqkMt745k4yqJWBCAWGu598hdPOPDBtJN9/G458nHiYJmc48bbZFk1Q4pEF0pXW7t0AqwgJYqW1j1AF2mSvG7mPCz/NBuFP8MeC7mfyq6uTkCAwEAAaMhMB8wHQYDVR0OBBYEFFVWt/4iTcBiWk+EX1dCKZGoAlBQMA0GCSqGSIb3DQEBCwUAA4IBAQCJrLUiCfldfDFhZLG08DpLcwpn8Mvhm61ZpPANyCawRgaoBOsxFJew1qpC2wfXh3yUwJEIkkTGXAsiWENkeqmjd2XXQwZuIHIo5/KyZLfo2m1CmEH/QXL6uRx1f8liPr4efC8H+7/sduf6nPfk0UpNsAHA6RxJFy2jg2wHU+Ux4jK4Gc5d/rJPhJhvyS9Zax1hbTlf+N32ZvS780VMDb/nf2LdtACL0ya/+KSDGVXS3GhS9FLEXrBNjq921ghVIFJhPzm54yfeupIwz+zfISoTHIYw37i7iNUbkvDrm14a27pwLS/tfSuJHKcGPt1sjMu6SS/pf1BlvdoFkKdLLaUb" ] + }, + { + "kty": "RSA", + "use": "sig", + "kid": "FSimuFrFNoC0sJXGmv13nNZceDc", + "x5t": "FSimuFrFNoC0sJXGmv13nNZceDc", + "n": "yCYaJF8uHoV2L31cjZUDdcodK1Y1EsTLkDD-DEXFyGeHaQ92T9t6MU6zazBzHvJRarG6OMI1GwsFxZ9opSVOeuRjuL3H2ehmUyuKOAnL8uT4cfkdfbg9AIN_63COccfFn0br_xUszZ7lkF5mb63sze-G66YQcbdTCWgsXpxR6491b57Gc4HVTV8cEgU4byezhJIiirrPDmt23QJIjr6XtvUMSNW88u0kX7PKOUnVCns2AG8DB2I-JExTiXwhFVu5JUqgpgmjIngvd5eyNzOgFJMnpWNXabKDP3oMLvQxjdq9xwWuTu0IQLpmUxEF9jVc8vKV1Pu2xHcS7ON5xJrUzw", + "e": "AQAB", + "x5c": [ "MIIDBTCCAe2gAwIBAgIQev76BWqjWZxChmKkGqoAfDANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE4MDIxODAwMDAwMFoXDTIwMDIxOTAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMgmGiRfLh6Fdi99XI2VA3XKHStWNRLEy5Aw/gxFxchnh2kPdk/bejFOs2swcx7yUWqxujjCNRsLBcWfaKUlTnrkY7i9x9noZlMrijgJy/Lk+HH5HX24PQCDf+twjnHHxZ9G6/8VLM2e5ZBeZm+t7M3vhuumEHG3UwloLF6cUeuPdW+exnOB1U1fHBIFOG8ns4SSIoq6zw5rdt0CSI6+l7b1DEjVvPLtJF+zyjlJ1Qp7NgBvAwdiPiRMU4l8IRVbuSVKoKYJoyJ4L3eXsjczoBSTJ6VjV2mygz96DC70MY3avccFrk7tCEC6ZlMRBfY1XPLyldT7tsR3EuzjecSa1M8CAwEAAaMhMB8wHQYDVR0OBBYEFIks1srixjpSLXeiR8zES5cTY6fBMA0GCSqGSIb3DQEBCwUAA4IBAQCKthfK4C31DMuDyQZVS3F7+4Evld3hjiwqu2uGDK+qFZas/D/eDunxsFpiwqC01RIMFFN8yvmMjHphLHiBHWxcBTS+tm7AhmAvWMdxO5lzJLS+UWAyPF5ICROe8Mu9iNJiO5JlCo0Wpui9RbB1C81Xhax1gWHK245ESL6k7YWvyMYWrGqr1NuQcNS0B/AIT1Nsj1WY7efMJQOmnMHkPUTWryVZlthijYyd7P2Gz6rY5a81DAFqhDNJl2pGIAE6HWtSzeUEh3jCsHEkoglKfm4VrGJEuXcALmfCMbdfTvtu4rlsaP2hQad+MG/KJFlenoTK34EMHeBPDCpqNDz8UVNk" ] + }, + { + "kty": "RSA", + "use": "sig", + "kid": "2S4SCVGs8Sg9LS6AqLIq6DpW-g8", + "x5t": "2S4SCVGs8Sg9LS6AqLIq6DpW-g8", + "n": "oZ-QQrNuB4ei9ATYrT61ebPtvwwYWnsrTpp4ISSp6niZYb92XM0oUTNgqd_C1vGN8J-y9wCbaJWkpBf46CjdZehrqczPhzhHau8WcRXocSB1u_tuZhv1ooAZ4bAcy79UkeLiG60HkuTNJJC8CfaTp1R97szBhuk0Vz5yt4r5SpfewIlBCnZUYwkDS172H9WapQu-3P2Qjh0l-JLyCkdrhvizZUk0atq5_AIDKRU-A0pRGc-EZhUL0LqUMz6c6M2s_4GnQaScv44A5iZUDD15B6e8Apb2yARohkWmOnmRcTVfes8EkfxjzZEzm3cNkvP0ogILyISHKlkzy2OmlU6iXw", + "e": "AQAB", + "x5c": [ "MIIDKDCCAhCgAwIBAgIQBHJvVNxP1oZO4HYKh+rypDANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDExhsb2dpbi5taWNyb3NvZnRvbmxpbmUudXMwHhcNMTYxMTE2MDgwMDAwWhcNMTgxMTE2MDgwMDAwWjAjMSEwHwYDVQQDExhsb2dpbi5taWNyb3NvZnRvbmxpbmUudXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChn5BCs24Hh6L0BNitPrV5s+2/DBhaeytOmnghJKnqeJlhv3ZczShRM2Cp38LW8Y3wn7L3AJtolaSkF/joKN1l6GupzM+HOEdq7xZxFehxIHW7+25mG/WigBnhsBzLv1SR4uIbrQeS5M0kkLwJ9pOnVH3uzMGG6TRXPnK3ivlKl97AiUEKdlRjCQNLXvYf1ZqlC77c/ZCOHSX4kvIKR2uG+LNlSTRq2rn8AgMpFT4DSlEZz4RmFQvQupQzPpzozaz/gadBpJy/jgDmJlQMPXkHp7wClvbIBGiGRaY6eZFxNV96zwSR/GPNkTObdw2S8/SiAgvIhIcqWTPLY6aVTqJfAgMBAAGjWDBWMFQGA1UdAQRNMEuAEDUj0BrjP0RTbmoRPTRMY3WhJTAjMSEwHwYDVQQDExhsb2dpbi5taWNyb3NvZnRvbmxpbmUudXOCEARyb1TcT9aGTuB2Cofq8qQwDQYJKoZIhvcNAQELBQADggEBAGnLhDHVz2gLDiu9L34V3ro/6xZDiSWhGyHcGqky7UlzQH3pT5so8iF5P0WzYqVtogPsyC2LPJYSTt2vmQugD4xlu/wbvMFLcV0hmNoTKCF1QTVtEQiAiy0Aq+eoF7Al5fV1S3Sune0uQHimuUFHCmUuF190MLcHcdWnPAmzIc8fv7quRUUsExXmxSX2ktUYQXzqFyIOSnDCuWFm6tpfK5JXS8fW5bpqTlrysXXz/OW/8NFGq/alfjrya4ojrOYLpunGriEtNPwK7hxj1AlCYEWaRHRXaUIW1ByoSff/6Y6+ZhXPUe0cDlNRt/qIz5aflwO7+W8baTS4O8m/icu7ItE=" ] + } + ] +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authentication.Test/PolicyTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/PolicyTests.cs new file mode 100644 index 000000000..368026beb --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/PolicyTests.cs @@ -0,0 +1,487 @@ +// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Microsoft.AspNetCore.Authentication +{ + public class PolicyTests + { + [Fact] + public async Task CanDispatch() + { + var server = CreateServer(services => + { + services.AddLogging().AddAuthentication(o => + { + o.AddScheme("auth1", "auth1"); + o.AddScheme("auth2", "auth2"); + o.AddScheme("auth3", "auth3"); + }) + .AddPolicyScheme("policy1", "policy1", p => + { + p.ForwardDefault = "auth1"; + }) + .AddPolicyScheme("policy2", "policy2", p => + { + p.ForwardAuthenticate = "auth2"; + }); + }); + + var transaction = await server.SendAsync("http://example.com/auth/policy1"); + Assert.Equal("auth1", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "auth1")); + + transaction = await server.SendAsync("http://example.com/auth/auth1"); + Assert.Equal("auth1", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "auth1")); + + transaction = await server.SendAsync("http://example.com/auth/auth2"); + Assert.Equal("auth2", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "auth2")); + + transaction = await server.SendAsync("http://example.com/auth/auth3"); + Assert.Equal("auth3", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "auth3")); + + transaction = await server.SendAsync("http://example.com/auth/policy2"); + Assert.Equal("auth2", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "auth2")); + } + + [Fact] + public async Task DefaultTargetSelectorWinsOverDefaultTarget() + { + var services = new ServiceCollection().AddOptions().AddLogging(); + services.AddAuthentication(o => + { + o.AddScheme("auth1", "auth1"); + o.AddScheme("auth2", "auth2"); + }) + .AddPolicyScheme("forward", "forward", p => { + p.ForwardDefault= "auth2"; + p.ForwardDefaultSelector = ctx => "auth1"; + }); + + var handler1 = new TestHandler(); + services.AddSingleton(handler1); + var handler2 = new TestHandler2(); + services.AddSingleton(handler2); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + Assert.Equal(0, handler1.AuthenticateCount); + Assert.Equal(0, handler1.ForbidCount); + Assert.Equal(0, handler1.ChallengeCount); + Assert.Equal(0, handler1.SignInCount); + Assert.Equal(0, handler1.SignOutCount); + Assert.Equal(0, handler2.AuthenticateCount); + Assert.Equal(0, handler2.ForbidCount); + Assert.Equal(0, handler2.ChallengeCount); + Assert.Equal(0, handler2.SignInCount); + Assert.Equal(0, handler2.SignOutCount); + + await context.AuthenticateAsync("forward"); + Assert.Equal(1, handler1.AuthenticateCount); + Assert.Equal(0, handler2.AuthenticateCount); + + await context.ForbidAsync("forward"); + Assert.Equal(1, handler1.ForbidCount); + Assert.Equal(0, handler2.ForbidCount); + + await context.ChallengeAsync("forward"); + Assert.Equal(1, handler1.ChallengeCount); + Assert.Equal(0, handler2.ChallengeCount); + + await context.SignOutAsync("forward"); + Assert.Equal(1, handler1.SignOutCount); + Assert.Equal(0, handler2.SignOutCount); + + await context.SignInAsync("forward", new ClaimsPrincipal()); + Assert.Equal(1, handler1.SignInCount); + Assert.Equal(0, handler2.SignInCount); + } + + [Fact] + public async Task NullDefaultTargetSelectorFallsBacktoDefaultTarget() + { + var services = new ServiceCollection().AddOptions().AddLogging(); + services.AddAuthentication(o => + { + o.AddScheme("auth1", "auth1"); + o.AddScheme("auth2", "auth2"); + }) + .AddPolicyScheme("forward", "forward", p => { + p.ForwardDefault= "auth1"; + p.ForwardDefaultSelector = ctx => null; + }); + + var handler1 = new TestHandler(); + services.AddSingleton(handler1); + var handler2 = new TestHandler2(); + services.AddSingleton(handler2); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + Assert.Equal(0, handler1.AuthenticateCount); + Assert.Equal(0, handler1.ForbidCount); + Assert.Equal(0, handler1.ChallengeCount); + Assert.Equal(0, handler1.SignInCount); + Assert.Equal(0, handler1.SignOutCount); + Assert.Equal(0, handler2.AuthenticateCount); + Assert.Equal(0, handler2.ForbidCount); + Assert.Equal(0, handler2.ChallengeCount); + Assert.Equal(0, handler2.SignInCount); + Assert.Equal(0, handler2.SignOutCount); + + await context.AuthenticateAsync("forward"); + Assert.Equal(1, handler1.AuthenticateCount); + Assert.Equal(0, handler2.AuthenticateCount); + + await context.ForbidAsync("forward"); + Assert.Equal(1, handler1.ForbidCount); + Assert.Equal(0, handler2.ForbidCount); + + await context.ChallengeAsync("forward"); + Assert.Equal(1, handler1.ChallengeCount); + Assert.Equal(0, handler2.ChallengeCount); + + await context.SignOutAsync("forward"); + Assert.Equal(1, handler1.SignOutCount); + Assert.Equal(0, handler2.SignOutCount); + + await context.SignInAsync("forward", new ClaimsPrincipal()); + Assert.Equal(1, handler1.SignInCount); + Assert.Equal(0, handler2.SignInCount); + } + + [Fact] + public async Task SpecificTargetAlwaysWinsOverDefaultTarget() + { + var services = new ServiceCollection().AddOptions().AddLogging(); + services.AddAuthentication(o => + { + o.AddScheme("auth1", "auth1"); + o.AddScheme("auth2", "auth2"); + }) + .AddPolicyScheme("forward", "forward", p => { + p.ForwardDefault= "auth2"; + p.ForwardDefaultSelector = ctx => "auth2"; + p.ForwardAuthenticate = "auth1"; + p.ForwardSignIn = "auth1"; + p.ForwardSignOut = "auth1"; + p.ForwardForbid = "auth1"; + p.ForwardChallenge = "auth1"; + }); + + var handler1 = new TestHandler(); + services.AddSingleton(handler1); + var handler2 = new TestHandler2(); + services.AddSingleton(handler2); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + Assert.Equal(0, handler1.AuthenticateCount); + Assert.Equal(0, handler1.ForbidCount); + Assert.Equal(0, handler1.ChallengeCount); + Assert.Equal(0, handler1.SignInCount); + Assert.Equal(0, handler1.SignOutCount); + Assert.Equal(0, handler2.AuthenticateCount); + Assert.Equal(0, handler2.ForbidCount); + Assert.Equal(0, handler2.ChallengeCount); + Assert.Equal(0, handler2.SignInCount); + Assert.Equal(0, handler2.SignOutCount); + + await context.AuthenticateAsync("forward"); + Assert.Equal(1, handler1.AuthenticateCount); + Assert.Equal(0, handler2.AuthenticateCount); + + await context.ForbidAsync("forward"); + Assert.Equal(1, handler1.ForbidCount); + Assert.Equal(0, handler2.ForbidCount); + + await context.ChallengeAsync("forward"); + Assert.Equal(1, handler1.ChallengeCount); + Assert.Equal(0, handler2.ChallengeCount); + + await context.SignOutAsync("forward"); + Assert.Equal(1, handler1.SignOutCount); + Assert.Equal(0, handler2.SignOutCount); + + await context.SignInAsync("forward", new ClaimsPrincipal()); + Assert.Equal(1, handler1.SignInCount); + Assert.Equal(0, handler2.SignInCount); + } + + [Fact] + public async Task VirtualSchemeTargetsForwardWithDefaultTarget() + { + var services = new ServiceCollection().AddOptions().AddLogging(); + services.AddAuthentication(o => + { + o.AddScheme("auth1", "auth1"); + o.AddScheme("auth2", "auth2"); + }) + .AddPolicyScheme("forward", "forward", p => p.ForwardDefault= "auth1"); + + var handler1 = new TestHandler(); + services.AddSingleton(handler1); + var handler2 = new TestHandler2(); + services.AddSingleton(handler2); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + Assert.Equal(0, handler1.AuthenticateCount); + Assert.Equal(0, handler1.ForbidCount); + Assert.Equal(0, handler1.ChallengeCount); + Assert.Equal(0, handler1.SignInCount); + Assert.Equal(0, handler1.SignOutCount); + Assert.Equal(0, handler2.AuthenticateCount); + Assert.Equal(0, handler2.ForbidCount); + Assert.Equal(0, handler2.ChallengeCount); + Assert.Equal(0, handler2.SignInCount); + Assert.Equal(0, handler2.SignOutCount); + + await context.AuthenticateAsync("forward"); + Assert.Equal(1, handler1.AuthenticateCount); + Assert.Equal(0, handler2.AuthenticateCount); + + await context.ForbidAsync("forward"); + Assert.Equal(1, handler1.ForbidCount); + Assert.Equal(0, handler2.ForbidCount); + + await context.ChallengeAsync("forward"); + Assert.Equal(1, handler1.ChallengeCount); + Assert.Equal(0, handler2.ChallengeCount); + + await context.SignOutAsync("forward"); + Assert.Equal(1, handler1.SignOutCount); + Assert.Equal(0, handler2.SignOutCount); + + await context.SignInAsync("forward", new ClaimsPrincipal()); + Assert.Equal(1, handler1.SignInCount); + Assert.Equal(0, handler2.SignInCount); + } + + [Fact] + public async Task VirtualSchemeTargetsOverrideDefaultTarget() + { + var services = new ServiceCollection().AddOptions().AddLogging(); + services.AddAuthentication(o => + { + o.AddScheme("auth1", "auth1"); + o.AddScheme("auth2", "auth2"); + }) + .AddPolicyScheme("forward", "forward", p => + { + p.ForwardDefault= "auth1"; + p.ForwardChallenge = "auth2"; + p.ForwardSignIn = "auth2"; + }); + + var handler1 = new TestHandler(); + services.AddSingleton(handler1); + var handler2 = new TestHandler2(); + services.AddSingleton(handler2); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + Assert.Equal(0, handler1.AuthenticateCount); + Assert.Equal(0, handler1.ForbidCount); + Assert.Equal(0, handler1.ChallengeCount); + Assert.Equal(0, handler1.SignInCount); + Assert.Equal(0, handler1.SignOutCount); + Assert.Equal(0, handler2.AuthenticateCount); + Assert.Equal(0, handler2.ForbidCount); + Assert.Equal(0, handler2.ChallengeCount); + Assert.Equal(0, handler2.SignInCount); + Assert.Equal(0, handler2.SignOutCount); + + await context.AuthenticateAsync("forward"); + Assert.Equal(1, handler1.AuthenticateCount); + Assert.Equal(0, handler2.AuthenticateCount); + + await context.ForbidAsync("forward"); + Assert.Equal(1, handler1.ForbidCount); + Assert.Equal(0, handler2.ForbidCount); + + await context.ChallengeAsync("forward"); + Assert.Equal(0, handler1.ChallengeCount); + Assert.Equal(1, handler2.ChallengeCount); + + await context.SignOutAsync("forward"); + Assert.Equal(1, handler1.SignOutCount); + Assert.Equal(0, handler2.SignOutCount); + + await context.SignInAsync("forward", new ClaimsPrincipal()); + Assert.Equal(0, handler1.SignInCount); + Assert.Equal(1, handler2.SignInCount); + } + + [Fact] + public async Task CanDynamicTargetBasedOnQueryString() + { + var server = CreateServer(services => + { + services.AddAuthentication(o => + { + o.AddScheme("auth1", "auth1"); + o.AddScheme("auth2", "auth2"); + o.AddScheme("auth3", "auth3"); + }) + .AddPolicyScheme("dynamic", "dynamic", p => + { + p.ForwardDefaultSelector = c => c.Request.QueryString.Value.Substring(1); + }); + }); + + var transaction = await server.SendAsync("http://example.com/auth/dynamic?auth1"); + Assert.Equal("auth1", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "auth1")); + transaction = await server.SendAsync("http://example.com/auth/dynamic?auth2"); + Assert.Equal("auth2", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "auth2")); + transaction = await server.SendAsync("http://example.com/auth/dynamic?auth3"); + Assert.Equal("auth3", transaction.FindClaimValue(ClaimTypes.NameIdentifier, "auth3")); + } + + private class TestHandler : IAuthenticationSignInHandler + { + public AuthenticationScheme Scheme { get; set; } + public int SignInCount { get; set; } + public int SignOutCount { get; set; } + public int ForbidCount { get; set; } + public int ChallengeCount { get; set; } + public int AuthenticateCount { get; set; } + + public Task AuthenticateAsync() + { + AuthenticateCount++; + var principal = new ClaimsPrincipal(); + var id = new ClaimsIdentity(); + id.AddClaim(new Claim(ClaimTypes.NameIdentifier, Scheme.Name, ClaimValueTypes.String, Scheme.Name)); + principal.AddIdentity(id); + return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name))); + } + + public Task ChallengeAsync(AuthenticationProperties properties) + { + ChallengeCount++; + return Task.CompletedTask; + } + + public Task ForbidAsync(AuthenticationProperties properties) + { + ForbidCount++; + return Task.CompletedTask; + } + + public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context) + { + Scheme = scheme; + return Task.CompletedTask; + } + + public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties) + { + SignInCount++; + return Task.CompletedTask; + } + + public Task SignOutAsync(AuthenticationProperties properties) + { + SignOutCount++; + return Task.CompletedTask; + } + } + + private class TestHandler2 : IAuthenticationSignInHandler + { + public AuthenticationScheme Scheme { get; set; } + public int SignInCount { get; set; } + public int SignOutCount { get; set; } + public int ForbidCount { get; set; } + public int ChallengeCount { get; set; } + public int AuthenticateCount { get; set; } + + public Task AuthenticateAsync() + { + AuthenticateCount++; + var principal = new ClaimsPrincipal(); + var id = new ClaimsIdentity(); + id.AddClaim(new Claim(ClaimTypes.NameIdentifier, Scheme.Name, ClaimValueTypes.String, Scheme.Name)); + principal.AddIdentity(id); + return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name))); + } + + public Task ChallengeAsync(AuthenticationProperties properties) + { + ChallengeCount++; + return Task.CompletedTask; + } + + public Task ForbidAsync(AuthenticationProperties properties) + { + ForbidCount++; + return Task.CompletedTask; + } + + public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context) + { + Scheme = scheme; + return Task.CompletedTask; + } + + public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties) + { + SignInCount++; + return Task.CompletedTask; + } + + public Task SignOutAsync(AuthenticationProperties properties) + { + SignOutCount++; + return Task.CompletedTask; + } + } + + private static TestServer CreateServer(Action configure = null, string defaultScheme = null) + { + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseAuthentication(); + app.Use(async (context, next) => + { + var req = context.Request; + var res = context.Response; + if (req.Path.StartsWithSegments(new PathString("/auth"), out var remainder)) + { + var name = (remainder.Value.Length > 0) ? remainder.Value.Substring(1) : null; + var result = await context.AuthenticateAsync(name); + res.Describe(result?.Ticket?.Principal); + } + else + { + await next(); + } + }); + }) + .ConfigureServices(services => + { + configure?.Invoke(services); + }); + return new TestServer(builder); + } + } +} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/RemoteAuthenticationTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/RemoteAuthenticationTests.cs new file mode 100644 index 000000000..d477e7534 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/RemoteAuthenticationTests.cs @@ -0,0 +1,92 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Authentication +{ + public abstract class RemoteAuthenticationTests : SharedAuthenticationTests where TOptions : RemoteAuthenticationOptions + { + protected override string DisplayName => DefaultScheme; + + private TestServer CreateServer(Action configureOptions, Func testpath = null, bool isDefault = true) + => CreateServerWithServices(s => + { + var builder = s.AddAuthentication(); + if (isDefault) + { + s.Configure(o => o.DefaultScheme = DefaultScheme); + } + RegisterAuth(builder, configureOptions); + s.AddSingleton(Clock); + }, testpath); + + + protected virtual TestServer CreateServerWithServices(Action configureServices, Func testpath = null) + { + //private static TestServer CreateServer(Action configure, Action configureServices, Func> handler) + var builder = new WebHostBuilder() + .Configure(app => + { + app.Use(async (context, next) => + { + if (testpath != null) + { + await testpath(context); + } + await next(); + }); + }) + .ConfigureServices(configureServices); + return new TestServer(builder); + } + + protected abstract void ConfigureDefaults(TOptions o); + + [Fact] + public async Task VerifySignInSchemeCannotBeSetToSelf() + { + var server = CreateServer( + o => + { + ConfigureDefaults(o); + o.SignInScheme = DefaultScheme; + }, + context => context.ChallengeAsync(DefaultScheme)); + var error = await Assert.ThrowsAsync(() => server.SendAsync("https://example.com/challenge")); + Assert.Contains("cannot be set to itself", error.Message); + } + + [Fact] + public async Task VerifySignInSchemeCannotBeSetToSelfUsingDefaultScheme() + { + var server = CreateServer( + o => o.SignInScheme = null, + context => context.ChallengeAsync(DefaultScheme), + isDefault: true); + var error = await Assert.ThrowsAsync(() => server.SendAsync("https://example.com/challenge")); + Assert.Contains("cannot be set to itself", error.Message); + } + + [Fact] + public async Task VerifySignInSchemeCannotBeSetToSelfUsingDefaultSignInScheme() + { + var server = CreateServerWithServices( + services => + { + var builder = services.AddAuthentication(o => o.DefaultSignInScheme = DefaultScheme); + RegisterAuth(builder, o => o.SignInScheme = null); + }, + context => context.ChallengeAsync(DefaultScheme)); + var error = await Assert.ThrowsAsync(() => server.SendAsync("https://example.com/challenge")); + Assert.Contains("cannot be set to itself", error.Message); + } + } +} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/DataHandler/SecureDataFormatTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/SecureDataFormatTests.cs similarity index 100% rename from test/Microsoft.AspNetCore.Authentication.Test/DataHandler/SecureDataFormatTests.cs rename to test/Microsoft.AspNetCore.Authentication.Test/SecureDataFormatTests.cs diff --git a/test/Microsoft.AspNetCore.Authentication.Test/SharedAuthenticationTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/SharedAuthenticationTests.cs new file mode 100644 index 000000000..4590c4915 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/SharedAuthenticationTests.cs @@ -0,0 +1,510 @@ +// 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.Authentication.Tests; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Security.Claims; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Authentication +{ + public abstract class SharedAuthenticationTests where TOptions : AuthenticationSchemeOptions + { + protected TestClock Clock { get; } = new TestClock(); + + protected abstract string DefaultScheme { get; } + protected virtual string DisplayName { get; } + protected abstract Type HandlerType { get; } + + protected virtual bool SupportsSignIn { get => true; } + protected virtual bool SupportsSignOut { get => true; } + + protected abstract void RegisterAuth(AuthenticationBuilder services, Action configure); + + [Fact] + public async Task CanForwardDefault() + { + var services = new ServiceCollection().AddLogging(); + + var builder = services.AddAuthentication(o => + { + o.DefaultScheme = DefaultScheme; + o.AddScheme("auth1", "auth1"); + }); + RegisterAuth(builder, o => o.ForwardDefault = "auth1"); + + var forwardDefault = new TestHandler(); + services.AddSingleton(forwardDefault); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + + await context.AuthenticateAsync(); + Assert.Equal(1, forwardDefault.AuthenticateCount); + + await context.ForbidAsync(); + Assert.Equal(1, forwardDefault.ForbidCount); + + await context.ChallengeAsync(); + Assert.Equal(1, forwardDefault.ChallengeCount); + + if (SupportsSignOut) + { + await context.SignOutAsync(); + Assert.Equal(1, forwardDefault.SignOutCount); + } + else + { + await Assert.ThrowsAsync(() => context.SignOutAsync()); + } + + if (SupportsSignIn) + { + await context.SignInAsync(new ClaimsPrincipal()); + Assert.Equal(1, forwardDefault.SignInCount); + } + else + { + await Assert.ThrowsAsync(() => context.SignInAsync(new ClaimsPrincipal())); + } + } + + [Fact] + public async Task ForwardSignInWinsOverDefault() + { + if (SupportsSignIn) + { + var services = new ServiceCollection().AddLogging(); + + var builder = services.AddAuthentication(o => + { + o.DefaultScheme = DefaultScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("specific", "specific"); + }); + RegisterAuth(builder, o => + { + o.ForwardDefault = "auth1"; + o.ForwardSignIn = "specific"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.SignInAsync(new ClaimsPrincipal()); + Assert.Equal(1, specific.SignInCount); + Assert.Equal(0, specific.AuthenticateCount); + Assert.Equal(0, specific.ForbidCount); + Assert.Equal(0, specific.ChallengeCount); + Assert.Equal(0, specific.SignOutCount); + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + } + } + + [Fact] + public async Task ForwardSignOutWinsOverDefault() + { + if (SupportsSignOut) + { + var services = new ServiceCollection().AddLogging(); + var builder = services.AddAuthentication(o => + { + o.DefaultScheme = DefaultScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("specific", "specific"); + }); + RegisterAuth(builder, o => + { + o.ForwardDefault = "auth1"; + o.ForwardSignOut = "specific"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.SignOutAsync(); + Assert.Equal(1, specific.SignOutCount); + Assert.Equal(0, specific.AuthenticateCount); + Assert.Equal(0, specific.ForbidCount); + Assert.Equal(0, specific.ChallengeCount); + Assert.Equal(0, specific.SignInCount); + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + } + } + + [Fact] + public async Task ForwardForbidWinsOverDefault() + { + var services = new ServiceCollection().AddLogging(); + var builder = services.AddAuthentication(o => + { + o.DefaultScheme = DefaultScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("specific", "specific"); + }); + RegisterAuth(builder, o => + { + o.ForwardDefault = "auth1"; + o.ForwardForbid = "specific"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.ForbidAsync(); + Assert.Equal(0, specific.SignOutCount); + Assert.Equal(0, specific.AuthenticateCount); + Assert.Equal(1, specific.ForbidCount); + Assert.Equal(0, specific.ChallengeCount); + Assert.Equal(0, specific.SignInCount); + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + } + + [Fact] + public async Task ForwardAuthenticateWinsOverDefault() + { + var services = new ServiceCollection().AddLogging(); + var builder = services.AddAuthentication(o => + { + o.DefaultScheme = DefaultScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("specific", "specific"); + }); + RegisterAuth(builder, o => + { + o.ForwardDefault = "auth1"; + o.ForwardAuthenticate = "specific"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.AuthenticateAsync(); + Assert.Equal(0, specific.SignOutCount); + Assert.Equal(1, specific.AuthenticateCount); + Assert.Equal(0, specific.ForbidCount); + Assert.Equal(0, specific.ChallengeCount); + Assert.Equal(0, specific.SignInCount); + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + } + + [Fact] + public async Task ForwardChallengeWinsOverDefault() + { + var services = new ServiceCollection().AddLogging(); + var builder = services.AddAuthentication(o => + { + o.DefaultScheme = DefaultScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("specific", "specific"); + }); + RegisterAuth(builder, o => + { + o.ForwardDefault = "auth1"; + o.ForwardChallenge = "specific"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.ChallengeAsync(); + Assert.Equal(0, specific.SignOutCount); + Assert.Equal(0, specific.AuthenticateCount); + Assert.Equal(0, specific.ForbidCount); + Assert.Equal(1, specific.ChallengeCount); + Assert.Equal(0, specific.SignInCount); + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + } + + [Fact] + public async Task ForwardSelectorWinsOverDefault() + { + var services = new ServiceCollection().AddLogging(); + var builder = services.AddAuthentication(o => + { + o.DefaultScheme = DefaultScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("selector", "selector"); + o.AddScheme("specific", "specific"); + }); + RegisterAuth(builder, o => + { + o.ForwardDefault = "auth1"; + o.ForwardDefaultSelector = _ => "selector"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + var selector = new TestHandler3(); + services.AddSingleton(selector); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.AuthenticateAsync(); + Assert.Equal(1, selector.AuthenticateCount); + + await context.ForbidAsync(); + Assert.Equal(1, selector.ForbidCount); + + await context.ChallengeAsync(); + Assert.Equal(1, selector.ChallengeCount); + + if (SupportsSignOut) + { + await context.SignOutAsync(); + Assert.Equal(1, selector.SignOutCount); + } + else + { + await Assert.ThrowsAsync(() => context.SignOutAsync()); + } + + if (SupportsSignIn) + { + await context.SignInAsync(new ClaimsPrincipal()); + Assert.Equal(1, selector.SignInCount); + } + else + { + await Assert.ThrowsAsync(() => context.SignInAsync(new ClaimsPrincipal())); + } + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + Assert.Equal(0, specific.AuthenticateCount); + Assert.Equal(0, specific.ForbidCount); + Assert.Equal(0, specific.ChallengeCount); + Assert.Equal(0, specific.SignInCount); + Assert.Equal(0, specific.SignOutCount); + } + + [Fact] + public async Task NullForwardSelectorUsesDefault() + { + var services = new ServiceCollection().AddLogging(); + var builder = services.AddAuthentication(o => + { + o.DefaultScheme = DefaultScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("selector", "selector"); + o.AddScheme("specific", "specific"); + }); + RegisterAuth(builder, o => + { + o.ForwardDefault = "auth1"; + o.ForwardDefaultSelector = _ => null; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + var selector = new TestHandler3(); + services.AddSingleton(selector); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.AuthenticateAsync(); + Assert.Equal(1, forwardDefault.AuthenticateCount); + + await context.ForbidAsync(); + Assert.Equal(1, forwardDefault.ForbidCount); + + await context.ChallengeAsync(); + Assert.Equal(1, forwardDefault.ChallengeCount); + + if (SupportsSignOut) + { + await context.SignOutAsync(); + Assert.Equal(1, forwardDefault.SignOutCount); + } + else + { + await Assert.ThrowsAsync(() => context.SignOutAsync()); + } + + if (SupportsSignIn) + { + await context.SignInAsync(new ClaimsPrincipal()); + Assert.Equal(1, forwardDefault.SignInCount); + } + else + { + await Assert.ThrowsAsync(() => context.SignInAsync(new ClaimsPrincipal())); + } + + Assert.Equal(0, selector.AuthenticateCount); + Assert.Equal(0, selector.ForbidCount); + Assert.Equal(0, selector.ChallengeCount); + Assert.Equal(0, selector.SignInCount); + Assert.Equal(0, selector.SignOutCount); + Assert.Equal(0, specific.AuthenticateCount); + Assert.Equal(0, specific.ForbidCount); + Assert.Equal(0, specific.ChallengeCount); + Assert.Equal(0, specific.SignInCount); + Assert.Equal(0, specific.SignOutCount); + } + + [Fact] + public async Task SpecificForwardWinsOverSelectorAndDefault() + { + var services = new ServiceCollection().AddLogging(); + var builder = services.AddAuthentication(o => + { + o.DefaultScheme = DefaultScheme; + o.AddScheme("auth1", "auth1"); + o.AddScheme("selector", "selector"); + o.AddScheme("specific", "specific"); + }); + RegisterAuth(builder, o => + { + o.ForwardDefault = "auth1"; + o.ForwardDefaultSelector = _ => "selector"; + o.ForwardAuthenticate = "specific"; + o.ForwardChallenge = "specific"; + o.ForwardSignIn = "specific"; + o.ForwardSignOut = "specific"; + o.ForwardForbid = "specific"; + }); + + var specific = new TestHandler(); + services.AddSingleton(specific); + var forwardDefault = new TestHandler2(); + services.AddSingleton(forwardDefault); + var selector = new TestHandler3(); + services.AddSingleton(selector); + + var sp = services.BuildServiceProvider(); + var context = new DefaultHttpContext(); + context.RequestServices = sp; + + await context.AuthenticateAsync(); + Assert.Equal(1, specific.AuthenticateCount); + + await context.ForbidAsync(); + Assert.Equal(1, specific.ForbidCount); + + await context.ChallengeAsync(); + Assert.Equal(1, specific.ChallengeCount); + + if (SupportsSignOut) + { + await context.SignOutAsync(); + Assert.Equal(1, specific.SignOutCount); + } + else + { + await Assert.ThrowsAsync(() => context.SignOutAsync()); + } + + if (SupportsSignIn) + { + await context.SignInAsync(new ClaimsPrincipal()); + Assert.Equal(1, specific.SignInCount); + } + else + { + await Assert.ThrowsAsync(() => context.SignInAsync(new ClaimsPrincipal())); + } + + Assert.Equal(0, forwardDefault.AuthenticateCount); + Assert.Equal(0, forwardDefault.ForbidCount); + Assert.Equal(0, forwardDefault.ChallengeCount); + Assert.Equal(0, forwardDefault.SignInCount); + Assert.Equal(0, forwardDefault.SignOutCount); + Assert.Equal(0, selector.AuthenticateCount); + Assert.Equal(0, selector.ForbidCount); + Assert.Equal(0, selector.ChallengeCount); + Assert.Equal(0, selector.SignInCount); + Assert.Equal(0, selector.SignOutCount); + } + + [Fact] + public async Task VerifySchemeDefaults() + { + var services = new ServiceCollection(); + var builder = services.AddAuthentication(); + RegisterAuth(builder, o => { }); + var sp = services.BuildServiceProvider(); + var schemeProvider = sp.GetRequiredService(); + var scheme = await schemeProvider.GetSchemeAsync(DefaultScheme); + Assert.NotNull(scheme); + Assert.Equal(HandlerType, scheme.HandlerType); + Assert.Equal(DisplayName, scheme.DisplayName); + } + } +} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/TestHandlers.cs b/test/Microsoft.AspNetCore.Authentication.Test/TestHandlers.cs new file mode 100644 index 000000000..cd9fe9fb1 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/TestHandlers.cs @@ -0,0 +1,115 @@ +// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information. + +using System.Security.Claims; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Authentication.Tests +{ + public class TestAuthHandler : AuthenticationHandler, IAuthenticationSignInHandler + { + public TestAuthHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) + { } + + public int SignInCount { get; set; } + public int SignOutCount { get; set; } + public int ForbidCount { get; set; } + public int ChallengeCount { get; set; } + public int AuthenticateCount { get; set; } + + protected override Task HandleChallengeAsync(AuthenticationProperties properties) + { + ChallengeCount++; + return Task.CompletedTask; + } + + protected override Task HandleForbiddenAsync(AuthenticationProperties properties) + { + ForbidCount++; + return Task.CompletedTask; + } + + protected override Task HandleAuthenticateAsync() + { + AuthenticateCount++; + var principal = new ClaimsPrincipal(); + var id = new ClaimsIdentity(); + id.AddClaim(new Claim(ClaimTypes.NameIdentifier, Scheme.Name, ClaimValueTypes.String, Scheme.Name)); + principal.AddIdentity(id); + return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name))); + } + + public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties) + { + SignInCount++; + return Task.CompletedTask; + } + + public Task SignOutAsync(AuthenticationProperties properties) + { + SignOutCount++; + return Task.CompletedTask; + } + } + + public class TestHandler : IAuthenticationSignInHandler + { + public AuthenticationScheme Scheme { get; set; } + public int SignInCount { get; set; } + public int SignOutCount { get; set; } + public int ForbidCount { get; set; } + public int ChallengeCount { get; set; } + public int AuthenticateCount { get; set; } + + public Task AuthenticateAsync() + { + AuthenticateCount++; + var principal = new ClaimsPrincipal(); + var id = new ClaimsIdentity(); + id.AddClaim(new Claim(ClaimTypes.NameIdentifier, Scheme.Name, ClaimValueTypes.String, Scheme.Name)); + principal.AddIdentity(id); + return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name))); + } + + public Task ChallengeAsync(AuthenticationProperties properties) + { + ChallengeCount++; + return Task.CompletedTask; + } + + public Task ForbidAsync(AuthenticationProperties properties) + { + ForbidCount++; + return Task.CompletedTask; + } + + public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context) + { + Scheme = scheme; + return Task.CompletedTask; + } + + public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties) + { + SignInCount++; + return Task.CompletedTask; + } + + public Task SignOutAsync(AuthenticationProperties properties) + { + SignOutCount++; + return Task.CompletedTask; + } + } + + public class TestHandler2 : TestHandler + { + } + + public class TestHandler3 : TestHandler + { + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authentication.Test/DataHandler/TicketSerializerTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/TicketSerializerTests.cs similarity index 85% rename from test/Microsoft.AspNetCore.Authentication.Test/DataHandler/TicketSerializerTests.cs rename to test/Microsoft.AspNetCore.Authentication.Test/TicketSerializerTests.cs index 8eeedde0d..a1e58743b 100644 --- a/test/Microsoft.AspNetCore.Authentication.Test/DataHandler/TicketSerializerTests.cs +++ b/test/Microsoft.AspNetCore.Authentication.Test/TicketSerializerTests.cs @@ -5,7 +5,7 @@ using System.IO; using System.Linq; using System.Security.Claims; -using Microsoft.AspNetCore.Http.Authentication; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Testing.xunit; using Xunit; @@ -28,7 +28,7 @@ public void CanRoundTripEmptyPrincipal() serializer.Write(writer, ticket); stream.Position = 0; var readTicket = serializer.Read(reader); - Assert.Equal(0, readTicket.Principal.Identities.Count()); + Assert.Empty(readTicket.Principal.Identities); Assert.Equal("bye", readTicket.Properties.RedirectUri); Assert.Equal("Hello", readTicket.AuthenticationScheme); } @@ -50,7 +50,7 @@ public void CanRoundTripBootstrapContext() serializer.Write(writer, ticket); stream.Position = 0; var readTicket = serializer.Read(reader); - Assert.Equal(1, readTicket.Principal.Identities.Count()); + Assert.Single(readTicket.Principal.Identities); Assert.Equal("misc", readTicket.Principal.Identity.AuthenticationType); Assert.Equal("bootstrap", readTicket.Principal.Identities.First().BootstrapContext); } @@ -73,12 +73,12 @@ public void CanRoundTripActorIdentity() serializer.Write(writer, ticket); stream.Position = 0; var readTicket = serializer.Read(reader); - Assert.Equal(1, readTicket.Principal.Identities.Count()); + Assert.Single(readTicket.Principal.Identities); Assert.Equal("misc", readTicket.Principal.Identity.AuthenticationType); var identity = (ClaimsIdentity) readTicket.Principal.Identity; Assert.NotNull(identity.Actor); - Assert.Equal(identity.Actor.AuthenticationType, "actor"); + Assert.Equal("actor", identity.Actor.AuthenticationType); } } @@ -108,22 +108,22 @@ public void CanRoundTripClaimProperties() serializer.Write(writer, ticket); stream.Position = 0; var readTicket = serializer.Read(reader); - Assert.Equal(1, readTicket.Principal.Identities.Count()); + Assert.Single(readTicket.Principal.Identities); Assert.Equal("misc", readTicket.Principal.Identity.AuthenticationType); var readClaim = readTicket.Principal.FindFirst("type"); Assert.NotNull(claim); - Assert.Equal(claim.Type, "type"); - Assert.Equal(claim.Value, "value"); - Assert.Equal(claim.ValueType, "valueType"); - Assert.Equal(claim.Issuer, "issuer"); - Assert.Equal(claim.OriginalIssuer, "original-issuer"); + Assert.Equal("type", claim.Type); + Assert.Equal("value", claim.Value); + Assert.Equal("valueType", claim.ValueType); + Assert.Equal("issuer", claim.Issuer); + Assert.Equal("original-issuer", claim.OriginalIssuer); var property1 = readClaim.Properties["property-1"]; - Assert.Equal(property1, "property-value"); + Assert.Equal("property-value", property1); var property2 = readClaim.Properties["property-2"]; - Assert.Equal(property2, string.Empty); + Assert.Equal(string.Empty, property2); } } } diff --git a/test/Microsoft.AspNetCore.Authentication.Test/TokenExtensionTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/TokenExtensionTests.cs index 028cf6760..4d4023bee 100644 --- a/test/Microsoft.AspNetCore.Authentication.Test/TokenExtensionTests.cs +++ b/test/Microsoft.AspNetCore.Authentication.Test/TokenExtensionTests.cs @@ -1,14 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; using System.Collections.Generic; using System.Linq; -using System.Security.Claims; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Authentication; -using Microsoft.AspNetCore.Http.Features.Authentication; using Xunit; namespace Microsoft.AspNetCore.Authentication @@ -51,10 +45,10 @@ public void SubsequentStoreTokenDeletesPreviousTokens() props.StoreTokens(new[] { new AuthenticationToken { Name = "Zero", Value = "0" } }); Assert.Equal("0", props.GetTokenValue("Zero")); - Assert.Equal(null, props.GetTokenValue("One")); - Assert.Equal(null, props.GetTokenValue("Two")); - Assert.Equal(null, props.GetTokenValue("Three")); - Assert.Equal(1, props.GetTokens().Count()); + Assert.Null(props.GetTokenValue("One")); + Assert.Null(props.GetTokenValue("Two")); + Assert.Null(props.GetTokenValue("Three")); + Assert.Single(props.GetTokens()); } [Fact] @@ -126,62 +120,62 @@ public void UpdateTokenValueReturnsFalseForUnknownToken() } - public class TestAuthHandler : IAuthenticationHandler - { - private readonly AuthenticationProperties _props; - public TestAuthHandler(AuthenticationProperties props) - { - _props = props; - } - - public Task AuthenticateAsync(AuthenticateContext context) - { - context.Authenticated(new ClaimsPrincipal(), _props.Items, new Dictionary()); - return Task.FromResult(0); - } - - public Task ChallengeAsync(ChallengeContext context) - { - throw new NotImplementedException(); - } - - public void GetDescriptions(DescribeSchemesContext context) - { - throw new NotImplementedException(); - } - - public Task SignInAsync(SignInContext context) - { - throw new NotImplementedException(); - } - - public Task SignOutAsync(SignOutContext context) - { - throw new NotImplementedException(); - } - } - - [Fact] - public async Task CanGetTokenFromContext() - { - var props = new AuthenticationProperties(); - var tokens = new List(); - var tok1 = new AuthenticationToken { Name = "One", Value = "1" }; - var tok2 = new AuthenticationToken { Name = "Two", Value = "2" }; - var tok3 = new AuthenticationToken { Name = "Three", Value = "3" }; - tokens.Add(tok1); - tokens.Add(tok2); - tokens.Add(tok3); - props.StoreTokens(tokens); - - var context = new DefaultHttpContext(); - var handler = new TestAuthHandler(props); - context.Features.Set(new HttpAuthenticationFeature() { Handler = handler }); - - Assert.Equal("1", await context.Authentication.GetTokenAsync("One")); - Assert.Equal("2", await context.Authentication.GetTokenAsync("Two")); - Assert.Equal("3", await context.Authentication.GetTokenAsync("Three")); - } + //public class TestAuthHandler : IAuthenticationHandler + //{ + // private readonly AuthenticationProperties _props; + // public TestAuthHandler(AuthenticationProperties props) + // { + // _props = props; + // } + + // public Task AuthenticateAsync(AuthenticateContext context) + // { + // context.Authenticated(new ClaimsPrincipal(), _props.Items, new Dictionary()); + // return Task.FromResult(0); + // } + + // public Task ChallengeAsync(AuthenticationProperties properties) + // { + // throw new NotImplementedException(); + // } + + // public void GetDescriptions(DescribeSchemesContext context) + // { + // throw new NotImplementedException(); + // } + + // public Task SignInAsync(ClaimsPrincipal principal, AuthenticationProperties properties) + // { + // throw new NotImplementedException(); + // } + + // public Task SignOutAsync(AuthenticationProperties properties) + // { + // throw new NotImplementedException(); + // } + //} + + //[Fact] + //public async Task CanGetTokenFromContext() + //{ + // var props = new AuthenticationProperties(); + // var tokens = new List(); + // var tok1 = new AuthenticationToken { Name = "One", Value = "1" }; + // var tok2 = new AuthenticationToken { Name = "Two", Value = "2" }; + // var tok3 = new AuthenticationToken { Name = "Three", Value = "3" }; + // tokens.Add(tok1); + // tokens.Add(tok2); + // tokens.Add(tok3); + // props.StoreTokens(tokens); + + // var context = new DefaultHttpContext(); + // var handler = new TestAuthHandler(props); + // context.Features.Set(new HttpAuthenticationFeature() { Handler = handler }); + + // Assert.Equal("1", await context.GetTokenAsync("One")); + // Assert.Equal("2", await context.GetTokenAsync("Two")); + // Assert.Equal("3", await context.GetTokenAsync("Three")); + //} } } diff --git a/test/Microsoft.AspNetCore.Authentication.Test/Twitter/TwitterMiddlewareTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/Twitter/TwitterMiddlewareTests.cs deleted file mode 100644 index 2ca2223b9..000000000 --- a/test/Microsoft.AspNetCore.Authentication.Test/Twitter/TwitterMiddlewareTests.cs +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information. - -using System; -using System.Net; -using System.Net.Http; -using System.Security.Claims; -using System.Text; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Xunit; - -namespace Microsoft.AspNetCore.Authentication.Twitter -{ - public class TwitterMiddlewareTests - { - [Fact] - public async Task ChallengeWillTriggerApplyRedirectEvent() - { - var server = CreateServer(new TwitterOptions - { - ConsumerKey = "Test Consumer Key", - ConsumerSecret = "Test Consumer Secret", - Events = new TwitterEvents - { - OnRedirectToAuthorizationEndpoint = context => - { - context.Response.Redirect(context.RedirectUri + "&custom=test"); - return Task.FromResult(0); - } - }, - BackchannelHttpHandler = new TestHttpMessageHandler - { - Sender = req => - { - if (req.RequestUri.AbsoluteUri == "https://api.twitter.com/oauth/request_token") - { - return new HttpResponseMessage(HttpStatusCode.OK) - { - Content = - new StringContent("oauth_callback_confirmed=true&oauth_token=test_oauth_token&oauth_token_secret=test_oauth_token_secret", - Encoding.UTF8, - "application/x-www-form-urlencoded") - }; - } - return null; - } - } - }, - context => - { - // REVIEW: Gross - context.Authentication.ChallengeAsync("Twitter").GetAwaiter().GetResult(); - return true; - }); - var transaction = await server.SendAsync("http://example.com/challenge"); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - var query = transaction.Response.Headers.Location.Query; - Assert.Contains("custom=test", query); - } - - [Fact] - public async Task BadSignInWillThrow() - { - var server = CreateServer(new TwitterOptions - { - ConsumerKey = "Test Consumer Key", - ConsumerSecret = "Test Consumer Secret" - }); - - // Send a bogus sign in - var error = await Assert.ThrowsAnyAsync(() => server.SendAsync("https://example.com/signin-twitter")); - Assert.Equal("Invalid state cookie.", error.GetBaseException().Message); - } - - [Fact] - public async Task SignInThrows() - { - var server = CreateServer(new TwitterOptions - { - ConsumerKey = "Test Consumer Key", - ConsumerSecret = "Test Consumer Secret" - }); - var transaction = await server.SendAsync("https://example.com/signIn"); - Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); - } - - [Fact] - public async Task SignOutThrows() - { - var server = CreateServer(new TwitterOptions - { - ConsumerKey = "Test Consumer Key", - ConsumerSecret = "Test Consumer Secret" - }); - var transaction = await server.SendAsync("https://example.com/signOut"); - Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); - } - - [Fact] - public async Task ForbidThrows() - { - var server = CreateServer(new TwitterOptions - { - ConsumerKey = "Test Consumer Key", - ConsumerSecret = "Test Consumer Secret" - }); - var transaction = await server.SendAsync("https://example.com/signOut"); - Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); - } - - - [Fact] - public async Task ChallengeWillTriggerRedirection() - { - var server = CreateServer(new TwitterOptions - { - ConsumerKey = "Test Consumer Key", - ConsumerSecret = "Test Consumer Secret", - BackchannelHttpHandler = new TestHttpMessageHandler - { - Sender = req => - { - if (req.RequestUri.AbsoluteUri == "https://api.twitter.com/oauth/request_token") - { - return new HttpResponseMessage(HttpStatusCode.OK) - { - Content = - new StringContent("oauth_callback_confirmed=true&oauth_token=test_oauth_token&oauth_token_secret=test_oauth_token_secret", - Encoding.UTF8, - "application/x-www-form-urlencoded") - }; - } - return null; - } - } - }, - context => - { - // REVIEW: gross - context.Authentication.ChallengeAsync("Twitter").GetAwaiter().GetResult(); - return true; - }); - var transaction = await server.SendAsync("http://example.com/challenge"); - Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); - var location = transaction.Response.Headers.Location.AbsoluteUri; - Assert.Contains("https://api.twitter.com/oauth/authenticate?oauth_token=", location); - } - - private static TestServer CreateServer(TwitterOptions options, Func handler = null) - { - var builder = new WebHostBuilder() - .Configure(app => - { - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - AuthenticationScheme = "External" - }); - app.UseTwitterAuthentication(options); - app.Use(async (context, next) => - { - var req = context.Request; - var res = context.Response; - if (req.Path == new PathString("/signIn")) - { - await Assert.ThrowsAsync(() => context.Authentication.SignInAsync("Twitter", new ClaimsPrincipal())); - } - else if (req.Path == new PathString("/signOut")) - { - await Assert.ThrowsAsync(() => context.Authentication.SignOutAsync("Twitter")); - } - else if (req.Path == new PathString("/forbid")) - { - await Assert.ThrowsAsync(() => context.Authentication.ForbidAsync("Twitter")); - } - else if (handler == null || !handler(context)) - { - await next(); - } - }); - }) - .ConfigureServices(services => - { - services.AddAuthentication(); - services.Configure(authOptions => - { - authOptions.SignInScheme = "External"; - }); - }); - return new TestServer(builder); - } - } -} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/TwitterTests.cs b/test/Microsoft.AspNetCore.Authentication.Test/TwitterTests.cs new file mode 100644 index 000000000..8eb7a5cd7 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/TwitterTests.cs @@ -0,0 +1,372 @@ +// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Net.Http.Headers; +using System; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Authentication.Twitter +{ + public class TwitterTests : RemoteAuthenticationTests + { + protected override string DefaultScheme => TwitterDefaults.AuthenticationScheme; + protected override Type HandlerType => typeof(TwitterHandler); + protected override bool SupportsSignIn { get => false; } + protected override bool SupportsSignOut { get => false; } + + protected override void RegisterAuth(AuthenticationBuilder services, Action configure) + { + services.AddTwitter(o => + { + ConfigureDefaults(o); + configure.Invoke(o); + }); + } + + protected override void ConfigureDefaults(TwitterOptions o) + { + o.ConsumerKey = "whatever"; + o.ConsumerSecret = "whatever"; + o.SignInScheme = "auth1"; + } + + [Fact] + public async Task ChallengeWillTriggerApplyRedirectEvent() + { + var server = CreateServer(o => + { + o.ConsumerKey = "Test Consumer Key"; + o.ConsumerSecret = "Test Consumer Secret"; + o.Events = new TwitterEvents + { + OnRedirectToAuthorizationEndpoint = context => + { + context.Response.Redirect(context.RedirectUri + "&custom=test"); + return Task.FromResult(0); + } + }; + o.BackchannelHttpHandler = new TestHttpMessageHandler + { + Sender = BackchannelRequestToken + }; + }, + async context => + { + await context.ChallengeAsync("Twitter"); + return true; + }); + var transaction = await server.SendAsync("http://example.com/challenge"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + var query = transaction.Response.Headers.Location.Query; + Assert.Contains("custom=test", query); + } + + /// + /// Validates the Twitter Options to check if the Consumer Key is missing in the TwitterOptions and if so throws the ArgumentException + /// + /// + [Fact] + public async Task ThrowsIfClientIdMissing() + { + var server = CreateServer(o => + { + o.ConsumerSecret = "Test Consumer Secret"; + }); + + await Assert.ThrowsAsync("ConsumerKey", async () => await server.SendAsync("http://example.com/challenge")); + } + + /// + /// Validates the Twitter Options to check if the Consumer Secret is missing in the TwitterOptions and if so throws the ArgumentException + /// + /// + [Fact] + public async Task ThrowsIfClientSecretMissing() + { + var server = CreateServer(o => + { + o.ConsumerKey = "Test Consumer Key"; + }); + + await Assert.ThrowsAsync("ConsumerSecret", async () => await server.SendAsync("http://example.com/challenge")); + } + + [Fact] + public async Task BadSignInWillThrow() + { + var server = CreateServer(o => + { + o.ConsumerKey = "Test Consumer Key"; + o.ConsumerSecret = "Test Consumer Secret"; + }); + + // Send a bogus sign in + var error = await Assert.ThrowsAnyAsync(() => server.SendAsync("https://example.com/signin-twitter")); + Assert.Equal("Invalid state cookie.", error.GetBaseException().Message); + } + + [Fact] + public async Task SignInThrows() + { + var server = CreateServer(o => + { + o.ConsumerKey = "Test Consumer Key"; + o.ConsumerSecret = "Test Consumer Secret"; + }); + var transaction = await server.SendAsync("https://example.com/signIn"); + Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); + } + + [Fact] + public async Task SignOutThrows() + { + var server = CreateServer(o => + { + o.ConsumerKey = "Test Consumer Key"; + o.ConsumerSecret = "Test Consumer Secret"; + }); + var transaction = await server.SendAsync("https://example.com/signOut"); + Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); + } + + [Fact] + public async Task ForbidThrows() + { + var server = CreateServer(o => + { + o.ConsumerKey = "Test Consumer Key"; + o.ConsumerSecret = "Test Consumer Secret"; + }); + var transaction = await server.SendAsync("https://example.com/signOut"); + Assert.Equal(HttpStatusCode.OK, transaction.Response.StatusCode); + } + + [Fact] + public async Task ChallengeWillTriggerRedirection() + { + var server = CreateServer(o => + { + o.ConsumerKey = "Test Consumer Key"; + o.ConsumerSecret = "Test Consumer Secret"; + o.BackchannelHttpHandler = new TestHttpMessageHandler + { + Sender = BackchannelRequestToken + }; + }, + async context => + { + await context.ChallengeAsync("Twitter"); + return true; + }); + var transaction = await server.SendAsync("http://example.com/challenge"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + var location = transaction.Response.Headers.Location.AbsoluteUri; + Assert.Contains("https://api.twitter.com/oauth/authenticate?oauth_token=", location); + } + + [Fact] + public async Task HandleRequestAsync_RedirectsToAccessDeniedPathWhenExplicitlySet() + { + var server = CreateServer(o => + { + o.ConsumerKey = "Test Consumer Key"; + o.ConsumerSecret = "Test Consumer Secret"; + o.BackchannelHttpHandler = new TestHttpMessageHandler + { + Sender = BackchannelRequestToken + }; + o.AccessDeniedPath = "/access-denied"; + o.Events.OnRemoteFailure = context => throw new InvalidOperationException("This event should not be called."); + }, + async context => + { + var properties = new AuthenticationProperties(); + properties.Items["testkey"] = "testvalue"; + await context.ChallengeAsync("Twitter", properties); + return true; + }); + var transaction = await server.SendAsync("http://example.com/challenge"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + var location = transaction.Response.Headers.Location.AbsoluteUri; + Assert.Contains("https://api.twitter.com/oauth/authenticate?oauth_token=", location); + Assert.True(transaction.Response.Headers.TryGetValues(HeaderNames.SetCookie, out var setCookie)); + Assert.True(SetCookieHeaderValue.TryParseList(setCookie.ToList(), out var setCookieValues)); + Assert.Single(setCookieValues); + var setCookieValue = setCookieValues.Single(); + var cookie = new CookieHeaderValue(setCookieValue.Name, setCookieValue.Value); + + var request = new HttpRequestMessage(HttpMethod.Get, "/signin-twitter?denied=ABCDEFG"); + request.Headers.Add(HeaderNames.Cookie, cookie.ToString()); + var client = server.CreateClient(); + var response = await client.SendAsync(request); + + Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); + Assert.Equal("/access-denied?ReturnUrl=%2Fchallenge", response.Headers.Location.ToString()); + } + + [Fact] + public async Task BadCallbackCallsAccessDeniedWithState() + { + var server = CreateServer(o => + { + o.ConsumerKey = "Test Consumer Key"; + o.ConsumerSecret = "Test Consumer Secret"; + o.BackchannelHttpHandler = new TestHttpMessageHandler + { + Sender = BackchannelRequestToken + }; + o.Events = new TwitterEvents() + { + OnAccessDenied = context => + { + Assert.NotNull(context.Properties); + Assert.Equal("testvalue", context.Properties.Items["testkey"]); + context.Response.StatusCode = StatusCodes.Status406NotAcceptable; + context.HandleResponse(); + return Task.CompletedTask; + } + }; + }, + async context => + { + var properties = new AuthenticationProperties(); + properties.Items["testkey"] = "testvalue"; + await context.ChallengeAsync("Twitter", properties); + return true; + }); + var transaction = await server.SendAsync("http://example.com/challenge"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + var location = transaction.Response.Headers.Location.AbsoluteUri; + Assert.Contains("https://api.twitter.com/oauth/authenticate?oauth_token=", location); + Assert.True(transaction.Response.Headers.TryGetValues(HeaderNames.SetCookie, out var setCookie)); + Assert.True(SetCookieHeaderValue.TryParseList(setCookie.ToList(), out var setCookieValues)); + Assert.Single(setCookieValues); + var setCookieValue = setCookieValues.Single(); + var cookie = new CookieHeaderValue(setCookieValue.Name, setCookieValue.Value); + + var request = new HttpRequestMessage(HttpMethod.Get, "/signin-twitter?denied=ABCDEFG"); + request.Headers.Add(HeaderNames.Cookie, cookie.ToString()); + var client = server.CreateClient(); + var response = await client.SendAsync(request); + + Assert.Equal(HttpStatusCode.NotAcceptable, response.StatusCode); + } + + [Fact] + public async Task BadCallbackCallsRemoteAuthFailedWithState() + { + var server = CreateServer(o => + { + o.ConsumerKey = "Test Consumer Key"; + o.ConsumerSecret = "Test Consumer Secret"; + o.BackchannelHttpHandler = new TestHttpMessageHandler + { + Sender = BackchannelRequestToken + }; + o.Events = new TwitterEvents() + { + OnRemoteFailure = context => + { + Assert.NotNull(context.Failure); + Assert.Equal("Access was denied by the resource owner or by the remote server.", context.Failure.Message); + Assert.NotNull(context.Properties); + Assert.Equal("testvalue", context.Properties.Items["testkey"]); + context.Response.StatusCode = StatusCodes.Status406NotAcceptable; + context.HandleResponse(); + return Task.CompletedTask; + } + }; + }, + async context => + { + var properties = new AuthenticationProperties(); + properties.Items["testkey"] = "testvalue"; + await context.ChallengeAsync("Twitter", properties); + return true; + }); + var transaction = await server.SendAsync("http://example.com/challenge"); + Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); + var location = transaction.Response.Headers.Location.AbsoluteUri; + Assert.Contains("https://api.twitter.com/oauth/authenticate?oauth_token=", location); + Assert.True(transaction.Response.Headers.TryGetValues(HeaderNames.SetCookie, out var setCookie)); + Assert.True(SetCookieHeaderValue.TryParseList(setCookie.ToList(), out var setCookieValues)); + Assert.Single(setCookieValues); + var setCookieValue = setCookieValues.Single(); + var cookie = new CookieHeaderValue(setCookieValue.Name, setCookieValue.Value); + + var request = new HttpRequestMessage(HttpMethod.Get, "/signin-twitter?denied=ABCDEFG"); + request.Headers.Add(HeaderNames.Cookie, cookie.ToString()); + var client = server.CreateClient(); + var response = await client.SendAsync(request); + + Assert.Equal(HttpStatusCode.NotAcceptable, response.StatusCode); + } + + private static TestServer CreateServer(Action options, Func> handler = null) + { + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseAuthentication(); + app.Use(async (context, next) => + { + var req = context.Request; + var res = context.Response; + if (req.Path == new PathString("/signIn")) + { + await Assert.ThrowsAsync(() => context.SignInAsync("Twitter", new ClaimsPrincipal())); + } + else if (req.Path == new PathString("/signOut")) + { + await Assert.ThrowsAsync(() => context.SignOutAsync("Twitter")); + } + else if (req.Path == new PathString("/forbid")) + { + await Assert.ThrowsAsync(() => context.ForbidAsync("Twitter")); + } + else if (handler == null || ! await handler(context)) + { + await next(); + } + }); + }) + .ConfigureServices(services => + { + Action wrapOptions = o => + { + o.SignInScheme = "External"; + options(o); + }; + services.AddAuthentication() + .AddCookie("External", _ => { }) + .AddTwitter(wrapOptions); + }); + return new TestServer(builder); + } + + private HttpResponseMessage BackchannelRequestToken(HttpRequestMessage req) + { + if (req.RequestUri.AbsoluteUri == "https://api.twitter.com/oauth/request_token") + { + return new HttpResponseMessage(HttpStatusCode.OK) + { + Content = + new StringContent("oauth_callback_confirmed=true&oauth_token=test_oauth_token&oauth_token_secret=test_oauth_token_secret", + Encoding.UTF8, + "application/x-www-form-urlencoded") + }; + } + throw new NotImplementedException(req.RequestUri.AbsoluteUri); + } + } +} diff --git a/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/CustomStateDataFormat.cs b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/CustomStateDataFormat.cs new file mode 100644 index 000000000..0de867d28 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/CustomStateDataFormat.cs @@ -0,0 +1,58 @@ +// 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.IO; +using System.Runtime.Serialization; +using System.Text; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + public class CustomStateDataFormat : ISecureDataFormat + { + public const string ValidStateData = "ValidStateData"; + + private string lastSavedAuthenticationProperties; + private DataContractSerializer serializer = new DataContractSerializer(typeof(AuthenticationProperties)); + + public string Protect(AuthenticationProperties data) + { + lastSavedAuthenticationProperties = Serialize(data); + return ValidStateData; + } + + public string Protect(AuthenticationProperties data, string purpose) + { + return Protect(data); + } + + public AuthenticationProperties Unprotect(string state) + { + return state == ValidStateData ? DeSerialize(lastSavedAuthenticationProperties) : null; + } + + public AuthenticationProperties Unprotect(string protectedText, string purpose) + { + return Unprotect(protectedText); + } + + private string Serialize(AuthenticationProperties data) + { + using (MemoryStream memoryStream = new MemoryStream()) + { + serializer.WriteObject(memoryStream, data); + memoryStream.Position = 0; + return new StreamReader(memoryStream).ReadToEnd(); + } + } + + private AuthenticationProperties DeSerialize(string state) + { + var stateDataAsBytes = Encoding.UTF8.GetBytes(state); + + using (var ms = new MemoryStream(stateDataAsBytes, false)) + { + return (AuthenticationProperties)serializer.ReadObject(ms); + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/InvalidToken.xml b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/InvalidToken.xml new file mode 100644 index 000000000..dfdb0d68d --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/InvalidToken.xml @@ -0,0 +1,83 @@ + + + 2014-04-18T20:21:17.341Z + 2014-04-19T08:21:17.341Z + + + +
http://automation1/
+
+
+ + + https://sts.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/ + + + + + + + + + + + Lkq0wTyTFxLUU2cyx0XybJqhka5RzRGj6kC4aIpFg+g= + + + bPwNswOB/B9xcdAljIkin9A2vjq+u94JdyvK03mf8vZFGUYNu9uN/Q6ims1DvW1FnP7SgFBwhIvW5OjZyW8fdYGhC2bq36izkxH6ulkWbciOcyELkyHDACLudvh8kP/Q+IwpicefKzAeI2Qu/5MFq16vFg5YgI+dovg8u1fYPPEPmmptW893RNTHWeh9mLRpLYnHyg7aLG6emNRkEu7w9rzeoICeMFybb9BvJl/q/8MFCW/Z5WemQhCi6YXFSEwCO6zJzCFi/3T6ChU/xYgXbFykDLqulsNOCQxdgutyqxJzugt+3PH5IKHHuoqe7UZNUIyELJ4BgwE1sXCGYIi24rg== + + + MIIDPjCCAiqgAwIBAgIQVWmXY/+9RqFA/OG9kFulHDAJBgUrDgMCHQUAMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwHhcNMTIwNjA3MDcwMDAwWhcNMTQwNjA3MDcwMDAwWjAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArCz8Sn3GGXmikH2MdTeGY1D711EORX/lVXpr+ecGgqfUWF8MPB07XkYuJ54DAuYT318+2XrzMjOtqkT94VkXmxv6dFGhG8YZ8vNMPd4tdj9c0lpvWQdqXtL1TlFRpD/P6UMEigfN0c9oWDg9U7Ilymgei0UXtf1gtcQbc5sSQU0S4vr9YJp2gLFIGK11Iqg4XSGdcI0QWLLkkC6cBukhVnd6BCYbLjTYy3fNs4DzNdemJlxGl8sLexFytBF6YApvSdus3nFXaMCtBGx16HzkK9ne3lobAwL2o79bP4imEGqg+ibvyNmbrwFGnQrBc1jTF9LyQX9q+louxVfHs6ZiVwIDAQABo2IwYDBeBgNVHQEEVzBVgBCxDDsLd8xkfOLKm4Q/SzjtoS8wLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldIIQVWmXY/+9RqFA/OG9kFulHDAJBgUrDgMCHQUAA4IBAQAkJtxxm/ErgySlNk69+1odTMP8Oy6L0H17z7XGG3w4TqvTUSWaxD4hSFJ0e7mHLQLQD7oV/erACXwSZn2pMoZ89MBDjOMQA+e6QzGB7jmSzPTNmQgMLA8fWCfqPrz6zgH+1F1gNp8hJY57kfeVPBiyjuBmlTEBsBlzolY9dd/55qqfQk6cgSeCbHCy/RU/iep0+UsRMlSgPNNmqhj5gmN2AFVCN96zF694LwuPae5CeR2ZcVknexOWHYjFM0MgUSw0ubnGl0h9AJgGyhvNGcjQqu9vd1xkupFgaN+f7P3p3EVN5csBg5H94jEcQZT7EKeTiZ6bTrpDAnrr8tDCy8ng + + + + + t0ch1TsP0pi5VoW8q5CGWsCXVZoNtpsg0mbMZPOYb4I + + + + + http://Automation1 + + + + + Test + + + Test + + + user1@praburajgmail.onmicrosoft.com + + + 4afbc689-805b-48cf-a24c-d4aa3248a248 + + + c2f0cd49-5e53-4520-8ed9-4e178dc488c5 + + + https://sts.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/ + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:Password + + + + + + + _660ec874-f70a-4997-a9c4-bd591f1c7469 + + + + + _660ec874-f70a-4997-a9c4-bd591f1c7469 + + + http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0 + http://schemas.xmlsoap.org/ws/2005/02/trust/Issue + http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey +
\ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/TestSecurityToken.cs b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/TestSecurityToken.cs new file mode 100644 index 000000000..dfe860724 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/TestSecurityToken.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.IdentityModel.Tokens; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + internal class TestSecurityToken : SecurityToken + { + public override string Id => "id"; + + public override string Issuer => "issuer"; + + public override SecurityKey SecurityKey => throw new NotImplementedException(); + + public override SecurityKey SigningKey + { + get => throw new NotImplementedException(); + set => throw new NotImplementedException(); + } + + public override DateTime ValidFrom => new DateTime(2008, 3, 22); + + public override DateTime ValidTo => new DateTime(2017, 3, 22); + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/TestSecurityTokenValidator.cs b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/TestSecurityTokenValidator.cs new file mode 100644 index 000000000..05882518f --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/TestSecurityTokenValidator.cs @@ -0,0 +1,31 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Security.Claims; +using Microsoft.IdentityModel.Tokens; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + internal class TestSecurityTokenValidator : ISecurityTokenValidator + { + public bool CanValidateToken => true; + + public int MaximumTokenSizeInBytes { get; set; } = 1024 * 5; + + public bool CanReadToken(string securityToken) + { + return true; + } + + public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken) + { + if (!string.IsNullOrEmpty(securityToken) && securityToken.Contains("ThisIsAValidToken")) + { + validatedToken = new TestSecurityToken(); + return new ClaimsPrincipal(new ClaimsIdentity("Test")); + } + + throw new SecurityTokenException("The security token did not contain ThisIsAValidToken"); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/ValidToken.xml b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/ValidToken.xml new file mode 100644 index 000000000..2addae96c --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/ValidToken.xml @@ -0,0 +1,83 @@ + + + 2014-04-18T20:21:17.341Z + 2014-04-19T08:21:17.341Z + + + +
http://automation1/
+
+
+ + + https://sts.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/ + + + + + + + + + + + Lkq0wTyTFxLUU2cyx0XybJqhka5RzRGj6kC4aIpFg+g= + + + bPwNswOB/B9xcdAljIkin9A2vjq+u94JdyvK03mf8vZFGUYNu9uN/Q6ims1DvW1FnP7SgFBwhIvW5OjZyW8fdYGhC2bq36izkxH6ulkWbciOcyELkyHDACLudvh8kP/Q+IwpicefKzAeI2Qu/5MFq16vFg5YgI+dovg8u1fYPPEPmmptW893RNTHWeh9mLRpLYnHyg7aLG6emNRkEu7w9rzeoICeMFybb9BvJl/q/8MFCW/Z5WemQhCi6YXFSEwCO6zJzCFi/3T6ChU/xYgXbFykDLqulsNOCQxdgutyqxJzugt+3PH5IKHHuoqe7UZNUIyELJ4BgwE1sXCGYIi24rg== + + + ThisIsAValidToken + + + + + t0ch1TsP0pi5VoW8q5CGWsCXVZoNtpsg0mbMZPOYb4I + + + + + http://Automation1 + + + + + Test + + + Test + + + user1@praburajgmail.onmicrosoft.com + + + 4afbc689-805b-48cf-a24c-d4aa3248a248 + + + c2f0cd49-5e53-4520-8ed9-4e178dc488c5 + + + https://sts.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/ + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:Password + + + + + + + _660ec874-f70a-4997-a9c4-bd591f1c7469 + + + + + _660ec874-f70a-4997-a9c4-bd591f1c7469 + + + http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0 + http://schemas.xmlsoap.org/ws/2005/02/trust/Issue + http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey +
\ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/WsFederationTest.cs b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/WsFederationTest.cs new file mode 100644 index 000000000..bc1ef757f --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/WsFederationTest.cs @@ -0,0 +1,443 @@ +// 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.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Security.Claims; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.TestHost; +using Microsoft.AspNetCore.WebUtilities; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Microsoft.AspNetCore.Authentication.WsFederation +{ + public class WsFederationTest + { + [Fact] + public async Task VerifySchemeDefaults() + { + var services = new ServiceCollection(); + services.AddAuthentication().AddWsFederation(); + var sp = services.BuildServiceProvider(); + var schemeProvider = sp.GetRequiredService(); + var scheme = await schemeProvider.GetSchemeAsync(WsFederationDefaults.AuthenticationScheme); + Assert.NotNull(scheme); + Assert.Equal("WsFederationHandler", scheme.HandlerType.Name); + Assert.Equal(WsFederationDefaults.AuthenticationScheme, scheme.DisplayName); + } + + [Fact] + public async Task MissingConfigurationThrows() + { + var builder = new WebHostBuilder() + .Configure(ConfigureApp) + .ConfigureServices(services => + { + services.AddAuthentication(sharedOptions => + { + sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; + sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme; + }) + .AddCookie() + .AddWsFederation(); + }); + var server = new TestServer(builder); + var httpClient = server.CreateClient(); + + // Verify if the request is redirected to STS with right parameters + var exception = await Assert.ThrowsAsync(() => httpClient.GetAsync("/")); + Assert.Equal("Provide MetadataAddress, Configuration, or ConfigurationManager to WsFederationOptions", exception.Message); + } + + [Fact] + public async Task ChallengeRedirects() + { + var httpClient = CreateClient(); + + // Verify if the request is redirected to STS with right parameters + var response = await httpClient.GetAsync("/"); + Assert.Equal("https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/wsfed", response.Headers.Location.GetLeftPart(System.UriPartial.Path)); + var queryItems = QueryHelpers.ParseQuery(response.Headers.Location.Query); + + Assert.Equal("http://Automation1", queryItems["wtrealm"]); + Assert.True(queryItems["wctx"].ToString().Equals(CustomStateDataFormat.ValidStateData), "wctx does not equal ValidStateData"); + Assert.Equal(httpClient.BaseAddress + "signin-wsfed", queryItems["wreply"]); + Assert.Equal("wsignin1.0", queryItems["wa"]); + } + + [Fact] + public async Task MapWillNotAffectRedirect() + { + var httpClient = CreateClient(); + + // Verify if the request is redirected to STS with right parameters + var response = await httpClient.GetAsync("/mapped-challenge"); + Assert.Equal("https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/wsfed", response.Headers.Location.GetLeftPart(System.UriPartial.Path)); + var queryItems = QueryHelpers.ParseQuery(response.Headers.Location.Query); + + Assert.Equal("http://Automation1", queryItems["wtrealm"]); + Assert.True(queryItems["wctx"].ToString().Equals(CustomStateDataFormat.ValidStateData), "wctx does not equal ValidStateData"); + Assert.Equal(httpClient.BaseAddress + "signin-wsfed", queryItems["wreply"]); + Assert.Equal("wsignin1.0", queryItems["wa"]); + } + + [Fact] + public async Task PreMappedWillAffectRedirect() + { + var httpClient = CreateClient(); + + // Verify if the request is redirected to STS with right parameters + var response = await httpClient.GetAsync("/premapped-challenge"); + Assert.Equal("https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/wsfed", response.Headers.Location.GetLeftPart(System.UriPartial.Path)); + var queryItems = QueryHelpers.ParseQuery(response.Headers.Location.Query); + + Assert.Equal("http://Automation1", queryItems["wtrealm"]); + Assert.True(queryItems["wctx"].ToString().Equals(CustomStateDataFormat.ValidStateData), "wctx does not equal ValidStateData"); + Assert.Equal(httpClient.BaseAddress + "premapped-challenge/signin-wsfed", queryItems["wreply"]); + Assert.Equal("wsignin1.0", queryItems["wa"]); + } + + [Fact] + public async Task ValidTokenIsAccepted() + { + var httpClient = CreateClient(); + + // Verify if the request is redirected to STS with right parameters + var response = await httpClient.GetAsync("/"); + var queryItems = QueryHelpers.ParseQuery(response.Headers.Location.Query); + + var request = new HttpRequestMessage(HttpMethod.Post, queryItems["wreply"]); + CopyCookies(response, request); + request.Content = CreateSignInContent("WsFederation/ValidToken.xml", queryItems["wctx"]); + response = await httpClient.SendAsync(request); + + Assert.Equal(HttpStatusCode.Found, response.StatusCode); + + request = new HttpRequestMessage(HttpMethod.Get, response.Headers.Location); + CopyCookies(response, request); + response = await httpClient.SendAsync(request); + + // Did the request end in the actual resource requested for + Assert.Equal(WsFederationDefaults.AuthenticationScheme, await response.Content.ReadAsStringAsync()); + } + + [Fact] + public async Task ValidUnsolicitedTokenIsRefused() + { + var httpClient = CreateClient(); + var form = CreateSignInContent("WsFederation/ValidToken.xml", suppressWctx: true); + var exception = await Assert.ThrowsAsync(() => httpClient.PostAsync(httpClient.BaseAddress + "signin-wsfed", form)); + Assert.Contains("Unsolicited logins are not allowed.", exception.InnerException.Message); + } + + [Fact] + public async Task ValidUnsolicitedTokenIsAcceptedWhenAllowed() + { + var httpClient = CreateClient(allowUnsolicited: true); + + var form = CreateSignInContent("WsFederation/ValidToken.xml", suppressWctx: true); + var response = await httpClient.PostAsync(httpClient.BaseAddress + "signin-wsfed", form); + + Assert.Equal(HttpStatusCode.Found, response.StatusCode); + + var request = new HttpRequestMessage(HttpMethod.Get, response.Headers.Location); + CopyCookies(response, request); + response = await httpClient.SendAsync(request); + + // Did the request end in the actual resource requested for + Assert.Equal(WsFederationDefaults.AuthenticationScheme, await response.Content.ReadAsStringAsync()); + } + + [Fact] + public async Task InvalidTokenIsRejected() + { + var httpClient = CreateClient(); + + // Verify if the request is redirected to STS with right parameters + var response = await httpClient.GetAsync("/"); + var queryItems = QueryHelpers.ParseQuery(response.Headers.Location.Query); + + var request = new HttpRequestMessage(HttpMethod.Post, queryItems["wreply"]); + CopyCookies(response, request); + request.Content = CreateSignInContent("WsFederation/InvalidToken.xml", queryItems["wctx"]); + response = await httpClient.SendAsync(request); + + // Did the request end in the actual resource requested for + Assert.Equal("AuthenticationFailed", await response.Content.ReadAsStringAsync()); + } + + [Fact] + public async Task RemoteSignoutRequestTriggersSignout() + { + var httpClient = CreateClient(); + + var response = await httpClient.GetAsync("/signin-wsfed?wa=wsignoutcleanup1.0"); + response.EnsureSuccessStatusCode(); + + var cookie = response.Headers.GetValues(HeaderNames.SetCookie).Single(); + Assert.Equal(".AspNetCore.Cookies=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; samesite=lax", cookie); + Assert.Equal("OnRemoteSignOut", response.Headers.GetValues("EventHeader").Single()); + Assert.Equal("", await response.Content.ReadAsStringAsync()); + } + + [Fact] + public async Task EventsResolvedFromDI() + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.AddSingleton(); + services.AddAuthentication(sharedOptions => + { + sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; + sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme; + }) + .AddCookie() + .AddWsFederation(options => + { + options.Wtrealm = "http://Automation1"; + options.MetadataAddress = "https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/federationmetadata/2007-06/federationmetadata.xml"; + options.BackchannelHttpHandler = new WaadMetadataDocumentHandler(); + options.EventsType = typeof(MyWsFedEvents); + }); + }) + .Configure(app => + { + app.Run(context => context.ChallengeAsync()); + }); + var server = new TestServer(builder); + + var result = await server.CreateClient().GetAsync(""); + Assert.Contains("CustomKey=CustomValue", result.Headers.Location.Query); + } + + private class MyWsFedEvents : WsFederationEvents + { + public override Task RedirectToIdentityProvider(RedirectContext context) + { + context.ProtocolMessage.SetParameter("CustomKey", "CustomValue"); + return base.RedirectToIdentityProvider(context); + } + } + + private FormUrlEncodedContent CreateSignInContent(string tokenFile, string wctx = null, bool suppressWctx = false) + { + var kvps = new List>(); + kvps.Add(new KeyValuePair("wa", "wsignin1.0")); + kvps.Add(new KeyValuePair("wresult", File.ReadAllText(tokenFile))); + if (!string.IsNullOrEmpty(wctx)) + { + kvps.Add(new KeyValuePair("wctx", wctx)); + } + if (suppressWctx) + { + kvps.Add(new KeyValuePair("suppressWctx", "true")); + } + return new FormUrlEncodedContent(kvps); + } + + private void CopyCookies(HttpResponseMessage response, HttpRequestMessage request) + { + var cookies = SetCookieHeaderValue.ParseList(response.Headers.GetValues(HeaderNames.SetCookie).ToList()); + foreach (var cookie in cookies) + { + if (cookie.Value.HasValue) + { + request.Headers.Add(HeaderNames.Cookie, new CookieHeaderValue(cookie.Name, cookie.Value).ToString()); + } + } + } + + private HttpClient CreateClient(bool allowUnsolicited = false) + { + var builder = new WebHostBuilder() + .Configure(ConfigureApp) + .ConfigureServices(services => + { + services.AddAuthentication(sharedOptions => + { + sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; + sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme; + }) + .AddCookie() + .AddWsFederation(options => + { + options.Wtrealm = "http://Automation1"; + options.MetadataAddress = "https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/federationmetadata/2007-06/federationmetadata.xml"; + options.BackchannelHttpHandler = new WaadMetadataDocumentHandler(); + options.StateDataFormat = new CustomStateDataFormat(); + options.SecurityTokenHandlers = new List() { new TestSecurityTokenValidator() }; + options.UseTokenLifetime = false; + options.AllowUnsolicitedLogins = allowUnsolicited; + options.Events = new WsFederationEvents() + { + OnMessageReceived = context => + { + if (!context.ProtocolMessage.Parameters.TryGetValue("suppressWctx", out var suppress)) + { + Assert.True(context.ProtocolMessage.Wctx.Equals("customValue"), "wctx is not my custom value"); + } + context.HttpContext.Items["MessageReceived"] = true; + return Task.FromResult(0); + }, + OnRedirectToIdentityProvider = context => + { + if (context.ProtocolMessage.IsSignInMessage) + { + // Sign in message + context.ProtocolMessage.Wctx = "customValue"; + } + + return Task.FromResult(0); + }, + OnSecurityTokenReceived = context => + { + context.HttpContext.Items["SecurityTokenReceived"] = true; + return Task.FromResult(0); + }, + OnSecurityTokenValidated = context => + { + Assert.True((bool)context.HttpContext.Items["MessageReceived"], "MessageReceived notification not invoked"); + Assert.True((bool)context.HttpContext.Items["SecurityTokenReceived"], "SecurityTokenReceived notification not invoked"); + + if (context.Principal != null) + { + var identity = context.Principal.Identities.Single(); + identity.AddClaim(new Claim("ReturnEndpoint", "true")); + identity.AddClaim(new Claim("Authenticated", "true")); + identity.AddClaim(new Claim(identity.RoleClaimType, "Guest", ClaimValueTypes.String)); + } + + return Task.FromResult(0); + }, + OnAuthenticationFailed = context => + { + context.HttpContext.Items["AuthenticationFailed"] = true; + //Change the request url to something different and skip Wsfed. This new url will handle the request and let us know if this notification was invoked. + context.HttpContext.Request.Path = new PathString("/AuthenticationFailed"); + context.SkipHandler(); + return Task.FromResult(0); + }, + OnRemoteSignOut = context => + { + context.Response.Headers["EventHeader"] = "OnRemoteSignOut"; + return Task.FromResult(0); + } + }; + }); + }); + var server = new TestServer(builder); + return server.CreateClient(); + } + + private void ConfigureApp(IApplicationBuilder app) + { + app.Map("/PreMapped-Challenge", mapped => + { + mapped.UseAuthentication(); + mapped.Run(async context => + { + await context.ChallengeAsync(WsFederationDefaults.AuthenticationScheme); + }); + }); + + app.UseAuthentication(); + + app.Map("/Logout", subApp => + { + subApp.Run(async context => + { + if (context.User.Identity.IsAuthenticated) + { + var authProperties = new AuthenticationProperties() { RedirectUri = context.Request.GetEncodedUrl() }; + await context.SignOutAsync(WsFederationDefaults.AuthenticationScheme, authProperties); + await context.Response.WriteAsync("Signing out..."); + } + else + { + await context.Response.WriteAsync("SignedOut"); + } + }); + }); + + app.Map("/AuthenticationFailed", subApp => + { + subApp.Run(async context => + { + await context.Response.WriteAsync("AuthenticationFailed"); + }); + }); + + app.Map("/signout-wsfed", subApp => + { + subApp.Run(async context => + { + await context.Response.WriteAsync("signout-wsfed"); + }); + }); + + app.Map("/mapped-challenge", subApp => + { + subApp.Run(async context => + { + await context.ChallengeAsync(WsFederationDefaults.AuthenticationScheme); + }); + }); + + app.Run(async context => + { + var result = context.AuthenticateAsync(); + if (context.User == null || !context.User.Identity.IsAuthenticated) + { + await context.ChallengeAsync(WsFederationDefaults.AuthenticationScheme); + await context.Response.WriteAsync("Unauthorized"); + } + else + { + var identity = context.User.Identities.Single(); + if (identity.NameClaimType == "Name_Failed" && identity.RoleClaimType == "Role_Failed") + { + context.Response.StatusCode = 500; + await context.Response.WriteAsync("SignIn_Failed"); + } + else if (!identity.HasClaim("Authenticated", "true") || !identity.HasClaim("ReturnEndpoint", "true") || !identity.HasClaim(identity.RoleClaimType, "Guest")) + { + await context.Response.WriteAsync("Provider not invoked"); + return; + } + else + { + await context.Response.WriteAsync(WsFederationDefaults.AuthenticationScheme); + } + } + }); + } + + private class WaadMetadataDocumentHandler : HttpMessageHandler + { + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var metadata = File.ReadAllText(@"WsFederation/federationmetadata.xml"); + var newResponse = new HttpResponseMessage() { Content = new StringContent(metadata, Encoding.UTF8, "text/xml") }; + return Task.FromResult(newResponse); + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/federationmetadata.xml b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/federationmetadata.xml new file mode 100644 index 000000000..920ed66a4 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authentication.Test/WsFederation/federationmetadata.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + wFJy/A1QstqtLHauYGcqwwHvn3HUW25DcWI/XLOmXOM= + + + R6fPw+BiFS9XYdkhwNJRjGxVftA2j9TdkF5d5jgR8uG1QMyuEA/Eizeq1HnnUj2Yi+sqNG+HzaZQclECeiJfi88Ry+keorDCo9KgdnjlZZc+WFzrJZeHjaDIvFD6B4OAN0mTq5kbpwr7+idzSbvyRXAnpvJxOrViZKE4HpwltGAZGDTkjsVkd8Z/wfoN7ehN4Ei7u/mOAiEU4FkWYFU/BfSVRVIUDyyQ7DGfQFJvCwHWFvsq+M1wfOUzQO5K+M9EU2m4VEP1qqbexXaZMAbcjqyUn4eN7doWjWE59jkXGbn+GR8qgCJqLOaYwXnH5XD0pMjy71aKGyLNaUb3wCwjkA== + + + MIIDPjCCAiqgAwIBAgIQVWmXY/+9RqFA/OG9kFulHDAJBgUrDgMCHQUAMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwHhcNMTIwNjA3MDcwMDAwWhcNMTQwNjA3MDcwMDAwWjAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArCz8Sn3GGXmikH2MdTeGY1D711EORX/lVXpr+ecGgqfUWF8MPB07XkYuJ54DAuYT318+2XrzMjOtqkT94VkXmxv6dFGhG8YZ8vNMPd4tdj9c0lpvWQdqXtL1TlFRpD/P6UMEigfN0c9oWDg9U7Ilymgei0UXtf1gtcQbc5sSQU0S4vr9YJp2gLFIGK11Iqg4XSGdcI0QWLLkkC6cBukhVnd6BCYbLjTYy3fNs4DzNdemJlxGl8sLexFytBF6YApvSdus3nFXaMCtBGx16HzkK9ne3lobAwL2o79bP4imEGqg+ibvyNmbrwFGnQrBc1jTF9LyQX9q+louxVfHs6ZiVwIDAQABo2IwYDBeBgNVHQEEVzBVgBCxDDsLd8xkfOLKm4Q/SzjtoS8wLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldIIQVWmXY/+9RqFA/OG9kFulHDAJBgUrDgMCHQUAA4IBAQAkJtxxm/ErgySlNk69+1odTMP8Oy6L0H17z7XGG3w4TqvTUSWaxD4hSFJ0e7mHLQLQD7oV/erACXwSZn2pMoZ89MBDjOMQA+e6QzGB7jmSzPTNmQgMLA8fWCfqPrz6zgH+1F1gNp8hJY57kfeVPBiyjuBmlTEBsBlzolY9dd/55qqfQk6cgSeCbHCy/RU/iep0+UsRMlSgPNNmqhj5gmN2AFVCN96zF694LwuPae5CeR2ZcVknexOWHYjFM0MgUSw0ubnGl0h9AJgGyhvNGcjQqu9vd1xkupFgaN+f7P3p3EVN5csBg5H94jEcQZT7EKeTiZ6bTrpDAnrr8tDCy8ng + + + + + + + + MIIDPjCCAiqgAwIBAgIQsRiM0jheFZhKk49YD0SK1TAJBgUrDgMCHQUAMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwHhcNMTQwMTAxMDcwMDAwWhcNMTYwMTAxMDcwMDAwWjAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkSCWg6q9iYxvJE2NIhSyOiKvqoWCO2GFipgH0sTSAs5FalHQosk9ZNTztX0ywS/AHsBeQPqYygfYVJL6/EgzVuwRk5txr9e3n1uml94fLyq/AXbwo9yAduf4dCHTP8CWR1dnDR+Qnz/4PYlWVEuuHHONOw/blbfdMjhY+C/BYM2E3pRxbohBb3x//CfueV7ddz2LYiH3wjz0QS/7kjPiNCsXcNyKQEOTkbHFi3mu0u13SQwNddhcynd/GTgWN8A+6SN1r4hzpjFKFLbZnBt77ACSiYx+IHK4Mp+NaVEi5wQtSsjQtI++XsokxRDqYLwus1I1SihgbV/STTg5enufuwIDAQABo2IwYDBeBgNVHQEEVzBVgBDLebM6bK3BjWGqIBrBNFeNoS8wLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldIIQsRiM0jheFZhKk49YD0SK1TAJBgUrDgMCHQUAA4IBAQCJ4JApryF77EKC4zF5bUaBLQHQ1PNtA1uMDbdNVGKCmSf8M65b8h0NwlIjGGGy/unK8P6jWFdm5IlZ0YPTOgzcRZguXDPj7ajyvlVEQ2K2ICvTYiRQqrOhEhZMSSZsTKXFVwNfW6ADDkN3bvVOVbtpty+nBY5UqnI7xbcoHLZ4wYD251uj5+lo13YLnsVrmQ16NCBYq2nQFNPuNJw6t3XUbwBHXpF46aLT1/eGf/7Xx6iy8yPJX4DyrpFTutDz882RWofGEO5t4Cw+zZg70dJ/hH/ODYRMorfXEW+8uKmXMKmX2wyxMKvfiPbTy5LmAU8Jvjs2tLg4rOBcXWLAIarZ + + + + + + + MIIDPjCCAiqgAwIBAgIQVWmXY/+9RqFA/OG9kFulHDAJBgUrDgMCHQUAMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwHhcNMTIwNjA3MDcwMDAwWhcNMTQwNjA3MDcwMDAwWjAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArCz8Sn3GGXmikH2MdTeGY1D711EORX/lVXpr+ecGgqfUWF8MPB07XkYuJ54DAuYT318+2XrzMjOtqkT94VkXmxv6dFGhG8YZ8vNMPd4tdj9c0lpvWQdqXtL1TlFRpD/P6UMEigfN0c9oWDg9U7Ilymgei0UXtf1gtcQbc5sSQU0S4vr9YJp2gLFIGK11Iqg4XSGdcI0QWLLkkC6cBukhVnd6BCYbLjTYy3fNs4DzNdemJlxGl8sLexFytBF6YApvSdus3nFXaMCtBGx16HzkK9ne3lobAwL2o79bP4imEGqg+ibvyNmbrwFGnQrBc1jTF9LyQX9q+louxVfHs6ZiVwIDAQABo2IwYDBeBgNVHQEEVzBVgBCxDDsLd8xkfOLKm4Q/SzjtoS8wLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldIIQVWmXY/+9RqFA/OG9kFulHDAJBgUrDgMCHQUAA4IBAQAkJtxxm/ErgySlNk69+1odTMP8Oy6L0H17z7XGG3w4TqvTUSWaxD4hSFJ0e7mHLQLQD7oV/erACXwSZn2pMoZ89MBDjOMQA+e6QzGB7jmSzPTNmQgMLA8fWCfqPrz6zgH+1F1gNp8hJY57kfeVPBiyjuBmlTEBsBlzolY9dd/55qqfQk6cgSeCbHCy/RU/iep0+UsRMlSgPNNmqhj5gmN2AFVCN96zF694LwuPae5CeR2ZcVknexOWHYjFM0MgUSw0ubnGl0h9AJgGyhvNGcjQqu9vd1xkupFgaN+f7P3p3EVN5csBg5H94jEcQZT7EKeTiZ6bTrpDAnrr8tDCy8ng + + + + + + UPN + UPN of the user + + + Name + The display name for the user + + + Given Name + First name of the user + + + Surname + Last name of the user + + + Authentication Instant + The time (UTC) at which the user authenticated to the identity provider + + + Authentication Method + The method of authentication used by the identity provider + + + TenantId + Identifier for the user's tenant + + + IdentityProvider + Identity provider for the user. + + + + +
https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/wsfed
+
+
+ + +
https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/wsfed
+
+
+
+ + + + + MIIDPjCCAiqgAwIBAgIQsRiM0jheFZhKk49YD0SK1TAJBgUrDgMCHQUAMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwHhcNMTQwMTAxMDcwMDAwWhcNMTYwMTAxMDcwMDAwWjAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkSCWg6q9iYxvJE2NIhSyOiKvqoWCO2GFipgH0sTSAs5FalHQosk9ZNTztX0ywS/AHsBeQPqYygfYVJL6/EgzVuwRk5txr9e3n1uml94fLyq/AXbwo9yAduf4dCHTP8CWR1dnDR+Qnz/4PYlWVEuuHHONOw/blbfdMjhY+C/BYM2E3pRxbohBb3x//CfueV7ddz2LYiH3wjz0QS/7kjPiNCsXcNyKQEOTkbHFi3mu0u13SQwNddhcynd/GTgWN8A+6SN1r4hzpjFKFLbZnBt77ACSiYx+IHK4Mp+NaVEi5wQtSsjQtI++XsokxRDqYLwus1I1SihgbV/STTg5enufuwIDAQABo2IwYDBeBgNVHQEEVzBVgBDLebM6bK3BjWGqIBrBNFeNoS8wLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldIIQsRiM0jheFZhKk49YD0SK1TAJBgUrDgMCHQUAA4IBAQCJ4JApryF77EKC4zF5bUaBLQHQ1PNtA1uMDbdNVGKCmSf8M65b8h0NwlIjGGGy/unK8P6jWFdm5IlZ0YPTOgzcRZguXDPj7ajyvlVEQ2K2ICvTYiRQqrOhEhZMSSZsTKXFVwNfW6ADDkN3bvVOVbtpty+nBY5UqnI7xbcoHLZ4wYD251uj5+lo13YLnsVrmQ16NCBYq2nQFNPuNJw6t3XUbwBHXpF46aLT1/eGf/7Xx6iy8yPJX4DyrpFTutDz882RWofGEO5t4Cw+zZg70dJ/hH/ODYRMorfXEW+8uKmXMKmX2wyxMKvfiPbTy5LmAU8Jvjs2tLg4rOBcXWLAIarZ + + + + + + + MIIDPjCCAiqgAwIBAgIQVWmXY/+9RqFA/OG9kFulHDAJBgUrDgMCHQUAMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwHhcNMTIwNjA3MDcwMDAwWhcNMTQwNjA3MDcwMDAwWjAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArCz8Sn3GGXmikH2MdTeGY1D711EORX/lVXpr+ecGgqfUWF8MPB07XkYuJ54DAuYT318+2XrzMjOtqkT94VkXmxv6dFGhG8YZ8vNMPd4tdj9c0lpvWQdqXtL1TlFRpD/P6UMEigfN0c9oWDg9U7Ilymgei0UXtf1gtcQbc5sSQU0S4vr9YJp2gLFIGK11Iqg4XSGdcI0QWLLkkC6cBukhVnd6BCYbLjTYy3fNs4DzNdemJlxGl8sLexFytBF6YApvSdus3nFXaMCtBGx16HzkK9ne3lobAwL2o79bP4imEGqg+ibvyNmbrwFGnQrBc1jTF9LyQX9q+louxVfHs6ZiVwIDAQABo2IwYDBeBgNVHQEEVzBVgBCxDDsLd8xkfOLKm4Q/SzjtoS8wLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldIIQVWmXY/+9RqFA/OG9kFulHDAJBgUrDgMCHQUAA4IBAQAkJtxxm/ErgySlNk69+1odTMP8Oy6L0H17z7XGG3w4TqvTUSWaxD4hSFJ0e7mHLQLQD7oV/erACXwSZn2pMoZ89MBDjOMQA+e6QzGB7jmSzPTNmQgMLA8fWCfqPrz6zgH+1F1gNp8hJY57kfeVPBiyjuBmlTEBsBlzolY9dd/55qqfQk6cgSeCbHCy/RU/iep0+UsRMlSgPNNmqhj5gmN2AFVCN96zF694LwuPae5CeR2ZcVknexOWHYjFM0MgUSw0ubnGl0h9AJgGyhvNGcjQqu9vd1xkupFgaN+f7P3p3EVN5csBg5H94jEcQZT7EKeTiZ6bTrpDAnrr8tDCy8ng + + + + + +
https://sts.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/
+
+
+ + +
https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/wsfed
+
+
+ + +
https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/wsfed
+
+
+
+ + + + + MIIDPjCCAiqgAwIBAgIQsRiM0jheFZhKk49YD0SK1TAJBgUrDgMCHQUAMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwHhcNMTQwMTAxMDcwMDAwWhcNMTYwMTAxMDcwMDAwWjAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkSCWg6q9iYxvJE2NIhSyOiKvqoWCO2GFipgH0sTSAs5FalHQosk9ZNTztX0ywS/AHsBeQPqYygfYVJL6/EgzVuwRk5txr9e3n1uml94fLyq/AXbwo9yAduf4dCHTP8CWR1dnDR+Qnz/4PYlWVEuuHHONOw/blbfdMjhY+C/BYM2E3pRxbohBb3x//CfueV7ddz2LYiH3wjz0QS/7kjPiNCsXcNyKQEOTkbHFi3mu0u13SQwNddhcynd/GTgWN8A+6SN1r4hzpjFKFLbZnBt77ACSiYx+IHK4Mp+NaVEi5wQtSsjQtI++XsokxRDqYLwus1I1SihgbV/STTg5enufuwIDAQABo2IwYDBeBgNVHQEEVzBVgBDLebM6bK3BjWGqIBrBNFeNoS8wLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldIIQsRiM0jheFZhKk49YD0SK1TAJBgUrDgMCHQUAA4IBAQCJ4JApryF77EKC4zF5bUaBLQHQ1PNtA1uMDbdNVGKCmSf8M65b8h0NwlIjGGGy/unK8P6jWFdm5IlZ0YPTOgzcRZguXDPj7ajyvlVEQ2K2ICvTYiRQqrOhEhZMSSZsTKXFVwNfW6ADDkN3bvVOVbtpty+nBY5UqnI7xbcoHLZ4wYD251uj5+lo13YLnsVrmQ16NCBYq2nQFNPuNJw6t3XUbwBHXpF46aLT1/eGf/7Xx6iy8yPJX4DyrpFTutDz882RWofGEO5t4Cw+zZg70dJ/hH/ODYRMorfXEW+8uKmXMKmX2wyxMKvfiPbTy5LmAU8Jvjs2tLg4rOBcXWLAIarZ + + + + + + + MIIDPjCCAiqgAwIBAgIQVWmXY/+9RqFA/OG9kFulHDAJBgUrDgMCHQUAMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwHhcNMTIwNjA3MDcwMDAwWhcNMTQwNjA3MDcwMDAwWjAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArCz8Sn3GGXmikH2MdTeGY1D711EORX/lVXpr+ecGgqfUWF8MPB07XkYuJ54DAuYT318+2XrzMjOtqkT94VkXmxv6dFGhG8YZ8vNMPd4tdj9c0lpvWQdqXtL1TlFRpD/P6UMEigfN0c9oWDg9U7Ilymgei0UXtf1gtcQbc5sSQU0S4vr9YJp2gLFIGK11Iqg4XSGdcI0QWLLkkC6cBukhVnd6BCYbLjTYy3fNs4DzNdemJlxGl8sLexFytBF6YApvSdus3nFXaMCtBGx16HzkK9ne3lobAwL2o79bP4imEGqg+ibvyNmbrwFGnQrBc1jTF9LyQX9q+louxVfHs6ZiVwIDAQABo2IwYDBeBgNVHQEEVzBVgBCxDDsLd8xkfOLKm4Q/SzjtoS8wLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldIIQVWmXY/+9RqFA/OG9kFulHDAJBgUrDgMCHQUAA4IBAQAkJtxxm/ErgySlNk69+1odTMP8Oy6L0H17z7XGG3w4TqvTUSWaxD4hSFJ0e7mHLQLQD7oV/erACXwSZn2pMoZ89MBDjOMQA+e6QzGB7jmSzPTNmQgMLA8fWCfqPrz6zgH+1F1gNp8hJY57kfeVPBiyjuBmlTEBsBlzolY9dd/55qqfQk6cgSeCbHCy/RU/iep0+UsRMlSgPNNmqhj5gmN2AFVCN96zF694LwuPae5CeR2ZcVknexOWHYjFM0MgUSw0ubnGl0h9AJgGyhvNGcjQqu9vd1xkupFgaN+f7P3p3EVN5csBg5H94jEcQZT7EKeTiZ6bTrpDAnrr8tDCy8ng + + + + + + +
\ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authentication.Test/project.json b/test/Microsoft.AspNetCore.Authentication.Test/project.json deleted file mode 100644 index 7477e93fa..000000000 --- a/test/Microsoft.AspNetCore.Authentication.Test/project.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "buildOptions": { - "warningsAsErrors": true - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Authentication.Cookies": "1.2.0-*", - "Microsoft.AspNetCore.Authentication.Facebook": "1.2.0-*", - "Microsoft.AspNetCore.Authentication.Google": "1.2.0-*", - "Microsoft.AspNetCore.Authentication.JwtBearer": "1.2.0-*", - "Microsoft.AspNetCore.Authentication.MicrosoftAccount": "1.2.0-*", - "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.2.0-*", - "Microsoft.AspNetCore.Authentication.Twitter": "1.2.0-*", - "Microsoft.AspNetCore.TestHost": "1.2.0-*", - "Microsoft.AspNetCore.Testing": "1.2.0-*", - "xunit": "2.2.0-*" - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - }, - "net451": {} - }, - "testRunner": "xunit" -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authorization.Test/AuthorizationAppBuilderExtensionsTests.cs b/test/Microsoft.AspNetCore.Authorization.Test/AuthorizationAppBuilderExtensionsTests.cs new file mode 100644 index 000000000..c6fb596f1 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authorization.Test/AuthorizationAppBuilderExtensionsTests.cs @@ -0,0 +1,65 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization.Test.TestObjects; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder.Internal; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Endpoints; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Microsoft.AspNetCore.Authorization.Test +{ + public class AuthorizationAppBuilderExtensionsTests + { + [Fact] + public async Task UseAuthorization_RegistersMiddleware() + { + // Arrange + var authenticationService = new TestAuthenticationService(); + var services = CreateServices(authenticationService); + + var app = new ApplicationBuilder(services); + + app.UseAuthorization(); + + var appFunc = app.Build(); + + var endpoint = new Endpoint( + null, + new EndpointMetadataCollection(new AuthorizeAttribute()), + "Test endpoint"); + + var httpContext = new DefaultHttpContext(); + httpContext.RequestServices = services; + httpContext.SetEndpoint(endpoint); + + // Act + await appFunc(httpContext); + + // Assert + Assert.True(authenticationService.ChallengeCalled); + } + + private IServiceProvider CreateServices(IAuthenticationService authenticationService) + { + var services = new ServiceCollection(); + + services.AddAuthorization(options => { }); + services.AddAuthorizationPolicyEvaluator(); + services.AddLogging(); + services.AddSingleton(authenticationService); + + var serviceProvder = services.BuildServiceProvider(); + + return serviceProvder; + } + } +} diff --git a/test/Microsoft.AspNetCore.Authorization.Test/AuthorizationEndpointConventionBuilderExtensionsTests.cs b/test/Microsoft.AspNetCore.Authorization.Test/AuthorizationEndpointConventionBuilderExtensionsTests.cs new file mode 100644 index 000000000..a2ab8fa8b --- /dev/null +++ b/test/Microsoft.AspNetCore.Authorization.Test/AuthorizationEndpointConventionBuilderExtensionsTests.cs @@ -0,0 +1,63 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Routing.Patterns; +using Xunit; + +namespace Microsoft.AspNetCore.Authorization.Test +{ + public class AuthorizationEndpointConventionBuilderExtensionsTests + { + [Fact] + public void RequireAuthorization_IAuthorizeData() + { + // Arrange + var builder = new TestEndpointConventionBuilder(); + var metadata = new AuthorizeAttribute(); + + // Act + builder.RequireAuthorization(metadata); + + // Assert + var convention = Assert.Single(builder.Conventions); + + var endpointModel = new RouteEndpointModel((context) => Task.CompletedTask, RoutePatternFactory.Parse("/"), 0); + convention(endpointModel); + + Assert.Equal(metadata, Assert.Single(endpointModel.Metadata)); + } + + [Fact] + public void RequireAuthorization_PolicyName() + { + // Arrange + var builder = new TestEndpointConventionBuilder(); + + // Act + builder.RequireAuthorization("policy"); + + // Assert + var convention = Assert.Single(builder.Conventions); + + var endpointModel = new RouteEndpointModel((context) => Task.CompletedTask, RoutePatternFactory.Parse("/"), 0); + convention(endpointModel); + + Assert.Equal("policy", Assert.IsAssignableFrom(Assert.Single(endpointModel.Metadata)).Policy); + } + + private class TestEndpointConventionBuilder : IEndpointConventionBuilder + { + public IList> Conventions { get; } = new List>(); + + public void Apply(Action convention) + { + Conventions.Add(convention); + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Authorization.Test/AuthorizationMiddlewareTests.cs b/test/Microsoft.AspNetCore.Authorization.Test/AuthorizationMiddlewareTests.cs new file mode 100644 index 000000000..655a4fbf8 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authorization.Test/AuthorizationMiddlewareTests.cs @@ -0,0 +1,459 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization.Infrastructure; +using Microsoft.AspNetCore.Authorization.Test.TestObjects; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Endpoints; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Moq; +using Xunit; + +namespace Microsoft.AspNetCore.Authorization.Test +{ + public class AuthorizationMiddlewareTests + { + [Fact] + public async Task NoEndpoint_AnonymousUser_Allows() + { + // Arrange + var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(anonymous: true); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.True(next.Called); + } + + [Fact] + public async Task NoEndpointWithRequired_AnonymousUser_Challenges() + { + // Arrange + var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetRequiredPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(anonymous: true); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.False(next.Called); + } + + [Fact] + public async Task HasEndpointWithoutAuth_AnonymousUser_Allows() + { + // Arrange + var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(anonymous: true, endpoint: CreateEndpoint()); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.True(next.Called); + } + + [Fact] + public async Task HasEndpointWithRequiredWithoutAuth_AnonymousUser_Challenges() + { + // Arrange + var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + policyProvider.Setup(p => p.GetRequiredPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(anonymous: true, endpoint: CreateEndpoint()); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.False(next.Called); + } + + [Fact] + public async Task HasEndpointWithAuth_AnonymousUser_Challenges() + { + // Arrange + var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + var authenticationService = new TestAuthenticationService(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(anonymous: true, endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.False(next.Called); + Assert.True(authenticationService.ChallengeCalled); + } + + [Fact] + public async Task HasEndpointWithAuth_AnonymousUser_ChallengePerScheme() + { + // Arrange + var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().AddAuthenticationSchemes("schema1", "schema2").Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + var authenticationService = new TestAuthenticationService(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(anonymous: true, endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.False(next.Called); + Assert.Equal(2, authenticationService.ChallengeCount); + } + + [Fact] + public async Task OnAuthorizationAsync_WillCallPolicyProvider() + { + // Arrange + var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build(); + var policyProvider = new Mock(); + var getPolicyCount = 0; + var getRequiredPolicyCount = 0; + policyProvider.Setup(p => p.GetPolicyAsync(It.IsAny())).ReturnsAsync(policy) + .Callback(() => getPolicyCount++); + policyProvider.Setup(p => p.GetRequiredPolicyAsync()).ReturnsAsync(policy) + .Callback(() => getRequiredPolicyCount++); + var next = new TestRequestDelegate(); + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(anonymous: true, endpoint: CreateEndpoint(new AuthorizeAttribute("whatever"))); + + // Act & Assert + await middleware.Invoke(context); + Assert.Equal(1, getPolicyCount); + Assert.Equal(1, getRequiredPolicyCount); + Assert.Equal(1, next.CalledCount); + + await middleware.Invoke(context); + Assert.Equal(2, getPolicyCount); + Assert.Equal(2, getRequiredPolicyCount); + Assert.Equal(2, next.CalledCount); + + await middleware.Invoke(context); + Assert.Equal(3, getPolicyCount); + Assert.Equal(3, getRequiredPolicyCount); + Assert.Equal(3, next.CalledCount); + } + + [Fact] + public async Task Invoke_ValidClaimShouldNotFail() + { + // Arrange + var policy = new AuthorizationPolicyBuilder().RequireClaim("Permission", "CanViewPage").Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute())); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.True(next.Called); + } + + [Fact] + public async Task HasEndpointWithAuthAndAllowAnonymous_AnonymousUser_Allows() + { + // Arrange + var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + var authenticationService = new TestAuthenticationService(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(anonymous: true, endpoint: CreateEndpoint(new AuthorizeAttribute(), new AllowAnonymousAttribute()), authenticationService: authenticationService); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.True(next.Called); + Assert.False(authenticationService.ChallengeCalled); + } + + [Fact] + public async Task HasEndpointWithAuth_AuthenticatedUser_Allows() + { + // Arrange + var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + var authenticationService = new TestAuthenticationService(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.True(next.Called); + Assert.False(authenticationService.ChallengeCalled); + } + + [Fact] + public async Task Invoke_AuthSchemesFailShouldSetEmptyPrincipalOnContext() + { + // Arrange + var policy = new AuthorizationPolicyBuilder("Fails").RequireAuthenticatedUser().Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + var authenticationService = new TestAuthenticationService(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.False(next.Called); + Assert.NotNull(context.User?.Identity); + Assert.True(authenticationService.AuthenticateCalled); + Assert.True(authenticationService.ChallengeCalled); + } + + [Fact] + public async Task Invoke_SingleValidClaimShouldSucceed() + { + // Arrange + var policy = new AuthorizationPolicyBuilder().RequireClaim("Permission", "CanViewComment", "CanViewPage").Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute())); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.True(next.Called); + } + + [Fact] + public async Task AuthZResourceShouldBeEndpoint() + { + // Arrange + object resource = null; + var policy = new AuthorizationPolicyBuilder().RequireAssertion(c => + { + resource = c.Resource; + return true; + }).Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var endpoint = CreateEndpoint(new AuthorizeAttribute()); + var context = GetHttpContext(endpoint: endpoint); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.Equal(endpoint, resource); + } + + [Fact] + public async Task Invoke_RequireUnknownRoleShouldForbid() + { + // Arrange + var policy = new AuthorizationPolicyBuilder().RequireRole("Wut").Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + var authenticationService = new TestAuthenticationService(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.False(next.Called); + Assert.False(authenticationService.ChallengeCalled); + Assert.True(authenticationService.ForbidCalled); + } + + [Fact] + public async Task Invoke_RequireUnknownRole_ForbidPerScheme() + { + // Arrange + var policy = new AuthorizationPolicyBuilder().RequireRole("Wut").AddAuthenticationSchemes("Basic", "Bearer").Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + var authenticationService = new TestAuthenticationService(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.False(next.Called); + Assert.Equal(2, authenticationService.ForbidCount); + } + + [Fact] + public async Task Invoke_InvalidClaimShouldForbid() + { + // Arrange + var policy = new AuthorizationPolicyBuilder() + .RequireClaim("Permission", "CanViewComment") + .Build(); + var policyProvider = new Mock(); + policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy); + var next = new TestRequestDelegate(); + var authenticationService = new TestAuthenticationService(); + + var middleware = CreateMiddleware(next.Invoke, policyProvider.Object); + var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService); + + // Act + await middleware.Invoke(context); + + // Assert + Assert.False(next.Called); + Assert.False(authenticationService.ChallengeCalled); + Assert.True(authenticationService.ForbidCalled); + } + + private AuthorizationMiddleware CreateMiddleware(RequestDelegate requestDelegate = null, IAuthorizationPolicyProvider policyProvider = null) + { + requestDelegate = requestDelegate ?? ((context) => Task.CompletedTask); + + return new AuthorizationMiddleware(requestDelegate, policyProvider); + } + + private Endpoint CreateEndpoint(params object[] metadata) + { + return new Endpoint(context => Task.CompletedTask, new EndpointMetadataCollection(metadata), "Test endpoint"); + } + + private HttpContext GetHttpContext( + bool anonymous = false, + Action registerServices = null, + Endpoint endpoint = null, + IAuthenticationService authenticationService = null) + { + var basicPrincipal = new ClaimsPrincipal( + new ClaimsIdentity( + new Claim[] { + new Claim("Permission", "CanViewPage"), + new Claim(ClaimTypes.Role, "Administrator"), + new Claim(ClaimTypes.Role, "User"), + new Claim(ClaimTypes.NameIdentifier, "John")}, + "Basic")); + + var validUser = basicPrincipal; + + var bearerIdentity = new ClaimsIdentity( + new Claim[] { + new Claim("Permission", "CupBearer"), + new Claim(ClaimTypes.Role, "Token"), + new Claim(ClaimTypes.NameIdentifier, "John Bear")}, + "Bearer"); + + validUser.AddIdentity(bearerIdentity); + + // ServiceProvider + var serviceCollection = new ServiceCollection(); + + authenticationService = authenticationService ?? Mock.Of(); + + serviceCollection.AddSingleton(authenticationService); + serviceCollection.AddOptions(); + serviceCollection.AddLogging(); + serviceCollection.AddAuthorization(); + serviceCollection.AddAuthorizationPolicyEvaluator(); + registerServices?.Invoke(serviceCollection); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + + //// HttpContext + var httpContext = new DefaultHttpContext(); + if (endpoint != null) + { + httpContext.SetEndpoint(endpoint); + } + httpContext.RequestServices = serviceProvider; + if (!anonymous) + { + httpContext.User = validUser; + } + + return httpContext; + } + + private class TestRequestDelegate + { + private readonly int _statusCode; + + public bool Called => CalledCount > 0; + public int CalledCount { get; private set; } + + public TestRequestDelegate(int statusCode = 200) + { + _statusCode = statusCode; + } + + public Task Invoke(HttpContext context) + { + CalledCount++; + context.Response.StatusCode = _statusCode; + return Task.CompletedTask; + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authorization.Test/AuthorizationPolicyFacts.cs b/test/Microsoft.AspNetCore.Authorization.Test/AuthorizationPolicyFacts.cs index 6825dd868..143be1b9b 100644 --- a/test/Microsoft.AspNetCore.Authorization.Test/AuthorizationPolicyFacts.cs +++ b/test/Microsoft.AspNetCore.Authorization.Test/AuthorizationPolicyFacts.cs @@ -9,7 +9,7 @@ using Microsoft.Extensions.Options; using Xunit; -namespace Microsoft.AspNetCore.Authroization.Test +namespace Microsoft.AspNetCore.Authorization.Test { public class AuthorizationPolicyFacts { @@ -25,9 +25,9 @@ public async Task CanCombineAuthorizeAttributes() // Arrange var attributes = new AuthorizeAttribute[] { new AuthorizeAttribute(), - new AuthorizeAttribute("1") { ActiveAuthenticationSchemes = "dupe" }, - new AuthorizeAttribute("2") { ActiveAuthenticationSchemes = "dupe" }, - new AuthorizeAttribute { Roles = "r1,r2", ActiveAuthenticationSchemes = "roles" }, + new AuthorizeAttribute("1") { AuthenticationSchemes = "dupe" }, + new AuthorizeAttribute("2") { AuthenticationSchemes = "dupe" }, + new AuthorizeAttribute { Roles = "r1,r2", AuthenticationSchemes = "roles" }, }; var options = new AuthorizationOptions(); options.AddPolicy("1", policy => policy.RequireClaim("1")); @@ -40,12 +40,12 @@ public async Task CanCombineAuthorizeAttributes() // Assert Assert.Equal(2, combined.AuthenticationSchemes.Count()); - Assert.True(combined.AuthenticationSchemes.Contains("dupe")); - Assert.True(combined.AuthenticationSchemes.Contains("roles")); + Assert.Contains("dupe", combined.AuthenticationSchemes); + Assert.Contains("roles", combined.AuthenticationSchemes); Assert.Equal(4, combined.Requirements.Count()); - Assert.True(combined.Requirements.Any(r => r is DenyAnonymousAuthorizationRequirement)); + Assert.Contains(combined.Requirements, r => r is DenyAnonymousAuthorizationRequirement); Assert.Equal(2, combined.Requirements.OfType().Count()); - Assert.Equal(1, combined.Requirements.OfType().Count()); + Assert.Single(combined.Requirements.OfType()); } [Fact] @@ -54,7 +54,7 @@ public async Task CanReplaceDefaultPolicy() // Arrange var attributes = new AuthorizeAttribute[] { new AuthorizeAttribute(), - new AuthorizeAttribute("2") { ActiveAuthenticationSchemes = "dupe" } + new AuthorizeAttribute("2") { AuthenticationSchemes = "dupe" } }; var options = new AuthorizationOptions(); options.DefaultPolicy = new AuthorizationPolicyBuilder("default").RequireClaim("default").Build(); @@ -67,10 +67,10 @@ public async Task CanReplaceDefaultPolicy() // Assert Assert.Equal(2, combined.AuthenticationSchemes.Count()); - Assert.True(combined.AuthenticationSchemes.Contains("dupe")); - Assert.True(combined.AuthenticationSchemes.Contains("default")); + Assert.Contains("dupe", combined.AuthenticationSchemes); + Assert.Contains("default", combined.AuthenticationSchemes); Assert.Equal(2, combined.Requirements.Count()); - Assert.False(combined.Requirements.Any(r => r is DenyAnonymousAuthorizationRequirement)); + Assert.DoesNotContain(combined.Requirements, r => r is DenyAnonymousAuthorizationRequirement); Assert.Equal(2, combined.Requirements.OfType().Count()); } @@ -88,11 +88,11 @@ public async Task CombineMustTrimRoles() var combined = await AuthorizationPolicy.CombineAsync(provider, attributes); // Assert - Assert.True(combined.Requirements.Any(r => r is RolesAuthorizationRequirement)); + Assert.Contains(combined.Requirements, r => r is RolesAuthorizationRequirement); var rolesAuthorizationRequirement = combined.Requirements.OfType().First(); Assert.Equal(2, rolesAuthorizationRequirement.AllowedRoles.Count()); - Assert.True(rolesAuthorizationRequirement.AllowedRoles.Any(r => r.Equals("r1"))); - Assert.True(rolesAuthorizationRequirement.AllowedRoles.Any(r => r.Equals("r2"))); + Assert.Contains(rolesAuthorizationRequirement.AllowedRoles, r => r.Equals("r1")); + Assert.Contains(rolesAuthorizationRequirement.AllowedRoles, r => r.Equals("r2")); } [Fact] @@ -100,7 +100,7 @@ public async Task CombineMustTrimAuthenticationScheme() { // Arrange var attributes = new AuthorizeAttribute[] { - new AuthorizeAttribute() { ActiveAuthenticationSchemes = "a1 , a2" } + new AuthorizeAttribute() { AuthenticationSchemes = "a1 , a2" } }; var options = new AuthorizationOptions(); @@ -111,8 +111,8 @@ public async Task CombineMustTrimAuthenticationScheme() // Assert Assert.Equal(2, combined.AuthenticationSchemes.Count()); - Assert.True(combined.AuthenticationSchemes.Any(a => a.Equals("a1"))); - Assert.True(combined.AuthenticationSchemes.Any(a => a.Equals("a2"))); + Assert.Contains(combined.AuthenticationSchemes, a => a.Equals("a1")); + Assert.Contains(combined.AuthenticationSchemes, a => a.Equals("a2")); } [Fact] @@ -120,7 +120,7 @@ public async Task CombineMustIgnoreEmptyAuthenticationScheme() { // Arrange var attributes = new AuthorizeAttribute[] { - new AuthorizeAttribute() { ActiveAuthenticationSchemes = "a1 , , ,,, a2" } + new AuthorizeAttribute() { AuthenticationSchemes = "a1 , , ,,, a2" } }; var options = new AuthorizationOptions(); @@ -131,8 +131,8 @@ public async Task CombineMustIgnoreEmptyAuthenticationScheme() // Assert Assert.Equal(2, combined.AuthenticationSchemes.Count()); - Assert.True(combined.AuthenticationSchemes.Any(a => a.Equals("a1"))); - Assert.True(combined.AuthenticationSchemes.Any(a => a.Equals("a2"))); + Assert.Contains(combined.AuthenticationSchemes, a => a.Equals("a1")); + Assert.Contains(combined.AuthenticationSchemes, a => a.Equals("a2")); } [Fact] @@ -149,11 +149,11 @@ public async Task CombineMustIgnoreEmptyRoles() var combined = await AuthorizationPolicy.CombineAsync(provider, attributes); // Assert - Assert.True(combined.Requirements.Any(r => r is RolesAuthorizationRequirement)); + Assert.Contains(combined.Requirements, r => r is RolesAuthorizationRequirement); var rolesAuthorizationRequirement = combined.Requirements.OfType().First(); Assert.Equal(2, rolesAuthorizationRequirement.AllowedRoles.Count()); - Assert.True(rolesAuthorizationRequirement.AllowedRoles.Any(r => r.Equals("r1"))); - Assert.True(rolesAuthorizationRequirement.AllowedRoles.Any(r => r.Equals("r2"))); + Assert.Contains(rolesAuthorizationRequirement.AllowedRoles, r => r.Equals("r1")); + Assert.Contains(rolesAuthorizationRequirement.AllowedRoles, r => r.Equals("r2")); } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authorization.Test/DefaultAuthorizationServiceTests.cs b/test/Microsoft.AspNetCore.Authorization.Test/DefaultAuthorizationServiceTests.cs index 7b0fc8c8b..230e95c4c 100644 --- a/test/Microsoft.AspNetCore.Authorization.Test/DefaultAuthorizationServiceTests.cs +++ b/test/Microsoft.AspNetCore.Authorization.Test/DefaultAuthorizationServiceTests.cs @@ -53,7 +53,7 @@ public async Task Authorize_ShouldAllowIfClaimIsPresent() var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -76,7 +76,7 @@ public async Task Authorize_ShouldAllowIfClaimIsPresentWithSpecifiedAuthType() var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -103,9 +103,10 @@ public async Task Authorize_ShouldAllowIfClaimIsAmongValues() var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } + [Fact] public async Task Authorize_ShouldInvokeAllHandlersByDefault() { // Arrange @@ -125,7 +126,8 @@ public async Task Authorize_ShouldInvokeAllHandlersByDefault() var allowed = await authorizationService.AuthorizeAsync(new ClaimsPrincipal(), "Custom"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); + Assert.True(allowed.Failure.FailCalled); Assert.True(handler1.Invoked); Assert.True(handler2.Invoked); } @@ -153,7 +155,7 @@ public async Task Authorize_ShouldInvokeAllHandlersDependingOnSetting(bool invok var allowed = await authorizationService.AuthorizeAsync(new ClaimsPrincipal(), "Custom"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); Assert.True(handler1.Invoked); Assert.Equal(invokeAllHandlers, handler2.Invoked); } @@ -170,8 +172,6 @@ public Task HandleAsync(AuthorizationHandlerContext context) } } - - [Fact] public async Task Authorize_ShouldFailWhenAllRequirementsNotHandled() { @@ -195,7 +195,8 @@ public async Task Authorize_ShouldFailWhenAllRequirementsNotHandled() var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); + Assert.IsType(allowed.Failure.FailedRequirements.First()); } [Fact] @@ -221,7 +222,7 @@ public async Task Authorize_ShouldNotAllowIfClaimTypeIsNotPresent() var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); } [Fact] @@ -247,7 +248,7 @@ public async Task Authorize_ShouldNotAllowIfClaimValueIsNotPresent() var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); } [Fact] @@ -271,7 +272,7 @@ public async Task Authorize_ShouldNotAllowIfNoClaims() var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); } [Fact] @@ -290,7 +291,7 @@ public async Task Authorize_ShouldNotAllowIfUserIsNull() var allowed = await authorizationService.AuthorizeAsync(null, null, "Basic"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); } [Fact] @@ -310,7 +311,7 @@ public async Task Authorize_ShouldNotAllowIfNotCorrectAuthType() var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); } [Fact] @@ -336,7 +337,7 @@ public async Task Authorize_ShouldAllowWithNoAuthType() var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -371,7 +372,7 @@ public async Task Authorize_CustomRolePolicy() var allowed = await authorizationService.AuthorizeAsync(user, policy.Build()); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -392,7 +393,7 @@ public async Task Authorize_HasAnyClaimOfTypePolicy() var allowed = await authorizationService.AuthorizeAsync(user, policy.Build()); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -409,7 +410,7 @@ public async Task Authorize_PolicyCanAuthenticationSchemeWithNameClaim() var allowed = await authorizationService.AuthorizeAsync(user, policy.Build()); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -426,7 +427,7 @@ public async Task RolePolicyCanRequireSingleRole() var allowed = await authorizationService.AuthorizeAsync(user, null, policy.Build()); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -442,7 +443,7 @@ public async Task RolePolicyCanRequireOneOfManyRoles() var allowed = await authorizationService.AuthorizeAsync(user, policy.Build()); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -463,7 +464,7 @@ public async Task RolePolicyCanBlockWrongRole() var allowed = await authorizationService.AuthorizeAsync(user, policy.Build()); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); } [Fact] @@ -488,7 +489,7 @@ public async Task RolePolicyCanBlockNoRole() var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); } [Fact] @@ -526,7 +527,7 @@ public async Task RequireUserNameFailsForWrongUserName() var allowed = await authorizationService.AuthorizeAsync(user, "Hao"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); } [Fact] @@ -552,7 +553,7 @@ public async Task CanRequireUserName() var allowed = await authorizationService.AuthorizeAsync(user, "Hao"); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -574,7 +575,7 @@ public async Task CanRequireUserNameWithDiffClaimType() var allowed = await authorizationService.AuthorizeAsync(user, "Hao"); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -596,7 +597,7 @@ public async Task CanRequireRoleWithDiffClaimType() var allowed = await authorizationService.AuthorizeAsync(user, "Hao"); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -621,7 +622,7 @@ public async Task CanApproveAnyAuthenticatedUser() var allowed = await authorizationService.AuthorizeAsync(user, null, "Any"); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -641,7 +642,7 @@ public async Task CanBlockNonAuthenticatedUser() var allowed = await authorizationService.AuthorizeAsync(user, null, "Any"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); } public class CustomRequirement : IAuthorizationRequirement { } @@ -674,7 +675,7 @@ public async Task CustomReqWithNoHandlerFails() var allowed = await authorizationService.AuthorizeAsync(user, null, "Custom"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); } [Fact] @@ -695,7 +696,7 @@ public async Task CustomReqWithHandlerSucceeds() var allowed = await authorizationService.AuthorizeAsync(user, null, "Custom"); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } public class PassThroughRequirement : AuthorizationHandler, IAuthorizationRequirement @@ -735,7 +736,7 @@ public async Task PassThroughRequirementWillSucceedWithoutCustomHandler(bool sho var allowed = await authorizationService.AuthorizeAsync(user, null, "Passthrough"); // Assert - Assert.Equal(shouldSucceed, allowed); + Assert.Equal(shouldSucceed, allowed.Succeeded); } [Fact] @@ -763,7 +764,7 @@ public async Task CanCombinePolicies() var allowed = await authorizationService.AuthorizeAsync(user, null, "Combined"); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -790,7 +791,7 @@ public async Task CombinePoliciesWillFailIfBasePolicyFails() var allowed = await authorizationService.AuthorizeAsync(user, null, "Combined"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); } [Fact] @@ -817,7 +818,7 @@ public async Task CombinedPoliciesWillFailIfExtraRequirementFails() var allowed = await authorizationService.AuthorizeAsync(user, null, "Combined"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); } public class ExpenseReport { } @@ -879,9 +880,9 @@ public async Task CanAuthorizeAllSuperuserOperations() // Act // Assert - Assert.True(await authorizationService.AuthorizeAsync(user, null, Operations.Edit)); - Assert.True(await authorizationService.AuthorizeAsync(user, null, Operations.Delete)); - Assert.True(await authorizationService.AuthorizeAsync(user, null, Operations.Create)); + Assert.True((await authorizationService.AuthorizeAsync(user, null, Operations.Edit)).Succeeded); + Assert.True((await authorizationService.AuthorizeAsync(user, null, Operations.Delete)).Succeeded); + Assert.True((await authorizationService.AuthorizeAsync(user, null, Operations.Create)).Succeeded); } public class NotCalledHandler : AuthorizationHandler @@ -921,8 +922,8 @@ public async Task CanUseValueTypeResource() // Act // Assert - Assert.False(await authorizationService.AuthorizeAsync(user, 1, Operations.Edit)); - Assert.True(await authorizationService.AuthorizeAsync(user, 2, Operations.Edit)); + Assert.False((await authorizationService.AuthorizeAsync(user, 1, Operations.Edit)).Succeeded); + Assert.True((await authorizationService.AuthorizeAsync(user, 2, Operations.Edit)).Succeeded); } @@ -944,7 +945,7 @@ public async Task DoesNotCallHandlerWithWrongResourceType() // Act // Assert - Assert.False(await authorizationService.AuthorizeAsync(user, 1, Operations.Edit)); + Assert.False((await authorizationService.AuthorizeAsync(user, 1, Operations.Edit)).Succeeded); } [Fact] @@ -959,9 +960,9 @@ public async Task CanAuthorizeOnlyAllowedOperations() // Act // Assert - Assert.True(await authorizationService.AuthorizeAsync(user, new ExpenseReport(), Operations.Edit)); - Assert.False(await authorizationService.AuthorizeAsync(user, new ExpenseReport(), Operations.Delete)); - Assert.False(await authorizationService.AuthorizeAsync(user, new ExpenseReport(), Operations.Create)); + Assert.True((await authorizationService.AuthorizeAsync(user, new ExpenseReport(), Operations.Edit)).Succeeded); + Assert.False((await authorizationService.AuthorizeAsync(user, new ExpenseReport(), Operations.Delete)).Succeeded); + Assert.False((await authorizationService.AuthorizeAsync(user, new ExpenseReport(), Operations.Create)).Succeeded); } [Fact] @@ -976,7 +977,7 @@ public async Task AuthorizeHandlerNotCalledWithNullResource() // Act // Assert - Assert.False(await authorizationService.AuthorizeAsync(user, null, Operations.Edit)); + Assert.False((await authorizationService.AuthorizeAsync(user, null, Operations.Edit)).Succeeded); } [Fact] @@ -995,7 +996,7 @@ public async Task CanAuthorizeWithAssertionRequirement() var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } [Fact] @@ -1014,7 +1015,7 @@ public async Task CanAuthorizeWithAsyncAssertionRequirement() var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); // Assert - Assert.True(allowed); + Assert.True(allowed.Succeeded); } public class StaticPolicyProvider : IAuthorizationPolicyProvider @@ -1024,6 +1025,11 @@ public Task GetDefaultPolicyAsync() return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build()); } + public Task GetRequiredPolicyAsync() + { + return Task.FromResult(null); + } + public Task GetPolicyAsync(string policyName) { return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build()); @@ -1048,7 +1054,7 @@ public async Task CanReplaceDefaultPolicyProvider() var allowed = await authorizationService.AuthorizeAsync(user, "Basic"); // Assert - Assert.False(allowed); + Assert.False(allowed.Succeeded); } public class DynamicPolicyProvider : IAuthorizationPolicyProvider @@ -1058,6 +1064,11 @@ public Task GetDefaultPolicyAsync() return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build()); } + public Task GetRequiredPolicyAsync() + { + return Task.FromResult(null); + } + public Task GetPolicyAsync(string policyName) { return Task.FromResult(new AuthorizationPolicyBuilder().RequireClaim(policyName).Build()); @@ -1080,23 +1091,15 @@ public async Task CanUseDynamicPolicyProvider() // Act // Assert - Assert.False(await authorizationService.AuthorizeAsync(user, "0")); - Assert.True(await authorizationService.AuthorizeAsync(user, "1")); - Assert.True(await authorizationService.AuthorizeAsync(user, "2")); - Assert.False(await authorizationService.AuthorizeAsync(user, "3")); + Assert.False((await authorizationService.AuthorizeAsync(user, "0")).Succeeded); + Assert.True((await authorizationService.AuthorizeAsync(user, "1")).Succeeded); + Assert.True((await authorizationService.AuthorizeAsync(user, "2")).Succeeded); + Assert.False((await authorizationService.AuthorizeAsync(user, "3")).Succeeded); } public class SuccessEvaluator : IAuthorizationEvaluator { - public bool HasFailed(AuthorizationHandlerContext context) - { - return false; - } - - public bool HasSucceeded(AuthorizationHandlerContext context) - { - return true; - } + public AuthorizationResult Evaluate(AuthorizationHandlerContext context) => AuthorizationResult.Success(); } [Fact] @@ -1107,7 +1110,8 @@ public async Task CanUseCustomEvaluatorThatOverridesRequirement() services.AddSingleton(); services.AddAuthorization(options => options.AddPolicy("Fail", p => p.RequireAssertion(c => false))); }); - Assert.True(await authorizationService.AuthorizeAsync(null, "Fail")); + var result = await authorizationService.AuthorizeAsync(null, "Fail"); + Assert.True(result.Succeeded); } @@ -1148,8 +1152,27 @@ public async Task CanUseCustomContextThatAlwaysFails() services.AddSingleton(); services.AddAuthorization(options => options.AddPolicy("Success", p => p.RequireAssertion(c => true))); }); - Assert.False(await authorizationService.AuthorizeAsync(null, "Success")); + Assert.False((await authorizationService.AuthorizeAsync(null, "Success")).Succeeded); + } + + public class SadHandlerProvider : IAuthorizationHandlerProvider + { + public Task> GetHandlersAsync(AuthorizationHandlerContext context) + { + return Task.FromResult>(new IAuthorizationHandler[1] { new FailHandler() }); + } + } + + [Fact] + public async Task CanUseCustomHandlerProvider() + { + var authorizationService = BuildAuthorizationService(services => + { + services.AddSingleton(); + services.AddAuthorization(options => options.AddPolicy("Success", p => p.RequireAssertion(c => true))); + }); + Assert.False((await authorizationService.AuthorizeAsync(null, "Success")).Succeeded); } } -} \ No newline at end of file +} diff --git a/test/Microsoft.AspNetCore.Authorization.Test/Microsoft.AspNetCore.Authorization.Test.csproj b/test/Microsoft.AspNetCore.Authorization.Test/Microsoft.AspNetCore.Authorization.Test.csproj new file mode 100644 index 000000000..9ff42a070 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authorization.Test/Microsoft.AspNetCore.Authorization.Test.csproj @@ -0,0 +1,21 @@ + + + + netcoreapp3.0 + $(NoWarn);NU1605 + + + + + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Authorization.Test/Microsoft.AspNetCore.Authorization.Test.xproj b/test/Microsoft.AspNetCore.Authorization.Test/Microsoft.AspNetCore.Authorization.Test.xproj deleted file mode 100644 index 59bcbc9c4..000000000 --- a/test/Microsoft.AspNetCore.Authorization.Test/Microsoft.AspNetCore.Authorization.Test.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 7af5ad96-eb6e-4d0e-8abe-c0b543c0f4c2 - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authorization.Test/PolicyEvaluatorTests.cs b/test/Microsoft.AspNetCore.Authorization.Test/PolicyEvaluatorTests.cs new file mode 100644 index 000000000..2384e6db5 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authorization.Test/PolicyEvaluatorTests.cs @@ -0,0 +1,209 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Microsoft.AspNetCore.Authorization.Policy.Test +{ + public class PolicyEvaluatorTests + { + [Fact] + public async Task AuthenticateFailsIfNoPrincipalReturned() + { + // Arrange + var evaluator = BuildEvaluator(); + var context = new DefaultHttpContext(); + var services = new ServiceCollection().AddSingleton(); + context.RequestServices = services.BuildServiceProvider(); + var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build(); + + // Act + var result = await evaluator.AuthenticateAsync(policy, context); + + // Assert + Assert.False(result.Succeeded); + } + + [Fact] + public async Task AuthenticateMergeSchemes() + { + // Arrange + var evaluator = BuildEvaluator(); + var context = new DefaultHttpContext(); + var services = new ServiceCollection().AddSingleton(); + context.RequestServices = services.BuildServiceProvider(); + var policy = new AuthorizationPolicyBuilder().AddAuthenticationSchemes("A","B","C").RequireAssertion(_ => true).Build(); + + // Act + var result = await evaluator.AuthenticateAsync(policy, context); + + // Assert + Assert.True(result.Succeeded); + Assert.Equal(3, result.Principal.Identities.Count()); + } + + + [Fact] + public async Task AuthorizeSucceedsEvenIfAuthenticationFails() + { + // Arrange + var evaluator = BuildEvaluator(); + var context = new DefaultHttpContext(); + var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build(); + + // Act + var result = await evaluator.AuthorizeAsync(policy, AuthenticateResult.Fail("Nooo"), context, resource: null); + + // Assert + Assert.True(result.Succeeded); + Assert.False(result.Challenged); + Assert.False(result.Forbidden); + } + + [Fact] + public async Task AuthorizeSucceedsOnlyIfResourceSpecified() + { + // Arrange + var evaluator = BuildEvaluator(); + var context = new DefaultHttpContext(); + var policy = new AuthorizationPolicyBuilder().RequireAssertion(c => c.Resource != null).Build(); + var success = AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(), "whatever")); + + // Act + var result = await evaluator.AuthorizeAsync(policy, success, context, resource: null); + var result2 = await evaluator.AuthorizeAsync(policy, success, context, resource: new object()); + + // Assert + Assert.False(result.Succeeded); + Assert.True(result2.Succeeded); + } + + [Fact] + public async Task AuthorizeChallengesIfAuthenticationFails() + { + // Arrange + var evaluator = BuildEvaluator(); + var context = new DefaultHttpContext(); + var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => false).Build(); + + // Act + var result = await evaluator.AuthorizeAsync(policy, AuthenticateResult.Fail("Nooo"), context, resource: null); + + // Assert + Assert.False(result.Succeeded); + Assert.True(result.Challenged); + Assert.False(result.Forbidden); + } + + [Fact] + public async Task AuthorizeForbidsIfAuthenticationSuceeds() + { + // Arrange + var evaluator = BuildEvaluator(); + var context = new DefaultHttpContext(); + var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => false).Build(); + + // Act + var result = await evaluator.AuthorizeAsync(policy, AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(), "scheme")), context, resource: null); + + // Assert + Assert.False(result.Succeeded); + Assert.False(result.Challenged); + Assert.True(result.Forbidden); + } + + private IPolicyEvaluator BuildEvaluator(Action setupServices = null) + { + var services = new ServiceCollection() + .AddAuthorization() + .AddAuthorizationPolicyEvaluator() + .AddLogging() + .AddOptions(); + setupServices?.Invoke(services); + return services.BuildServiceProvider().GetRequiredService(); + } + + public class HappyAuthorization : IAuthorizationService + { + public Task AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable requirements) + => Task.FromResult(AuthorizationResult.Success()); + + public Task AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName) + => Task.FromResult(AuthorizationResult.Success()); + } + + public class SadAuthorization : IAuthorizationService + { + public Task AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable requirements) + => Task.FromResult(AuthorizationResult.Failed()); + + public Task AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName) + => Task.FromResult(AuthorizationResult.Failed()); + } + + public class SadAuthentication : IAuthenticationService + { + public Task AuthenticateAsync(HttpContext context, string scheme) + { + return Task.FromResult(AuthenticateResult.Fail("Sad.")); + } + + public Task ChallengeAsync(HttpContext context, string scheme, AuthenticationProperties properties) + { + throw new System.NotImplementedException(); + } + + public Task ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties) + { + throw new System.NotImplementedException(); + } + + public Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties) + { + throw new System.NotImplementedException(); + } + + public Task SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties) + { + throw new System.NotImplementedException(); + } + } + + public class EchoAuthentication : IAuthenticationService + { + public Task AuthenticateAsync(HttpContext context, string scheme) + { + return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(new ClaimsIdentity(scheme)), scheme))); + } + + public Task ChallengeAsync(HttpContext context, string scheme, AuthenticationProperties properties) + { + throw new System.NotImplementedException(); + } + + public Task ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties) + { + throw new System.NotImplementedException(); + } + + public Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties) + { + throw new System.NotImplementedException(); + } + + public Task SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties) + { + throw new System.NotImplementedException(); + } + } + + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authorization.Test/TestObjects/TestAuthenticationService.cs b/test/Microsoft.AspNetCore.Authorization.Test/TestObjects/TestAuthenticationService.cs new file mode 100644 index 000000000..0c17693d1 --- /dev/null +++ b/test/Microsoft.AspNetCore.Authorization.Test/TestObjects/TestAuthenticationService.cs @@ -0,0 +1,58 @@ +// 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.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Authorization.Test.TestObjects +{ + public class TestAuthenticationService : IAuthenticationService + { + public bool ChallengeCalled => ChallengeCount > 0; + public bool ForbidCalled => ForbidCount > 0; + public bool AuthenticateCalled => AuthenticateCount > 0; + + public int ChallengeCount { get; private set; } + public int ForbidCount { get; private set; } + public int AuthenticateCount { get; private set; } + + public Task AuthenticateAsync(HttpContext context, string scheme) + { + AuthenticateCount++; + + var identity = context.User.Identities.SingleOrDefault(i => i.AuthenticationType == scheme); + if (identity != null) + { + return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(identity), scheme))); + } + + return Task.FromResult(AuthenticateResult.Fail("Denied")); + } + + public Task ChallengeAsync(HttpContext context, string scheme, AuthenticationProperties properties) + { + ChallengeCount++; + return Task.CompletedTask; + } + + public Task ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties) + { + ForbidCount++; + return Task.CompletedTask; + } + + public Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + + public Task SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Authorization.Test/project.json b/test/Microsoft.AspNetCore.Authorization.Test/project.json deleted file mode 100644 index dfb4e7288..000000000 --- a/test/Microsoft.AspNetCore.Authorization.Test/project.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "buildOptions": { - "warningsAsErrors": true - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Authorization": "1.2.0-*", - "Microsoft.AspNetCore.Testing": "1.2.0-*", - "Microsoft.Extensions.DependencyInjection": "1.2.0-*", - "Microsoft.Extensions.Logging": "1.2.0-*", - "xunit": "2.2.0-*" - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - }, - "net451": {} - }, - "testRunner": "xunit" -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/CookieChunkingTests.cs b/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/CookieChunkingTests.cs index c978d169e..e645745b3 100644 --- a/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/CookieChunkingTests.cs +++ b/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/CookieChunkingTests.cs @@ -17,8 +17,8 @@ public void AppendLargeCookie_Appended() string testString = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; new ChunkingCookieManager() { ChunkSize = null }.AppendResponseCookie(context, "TestCookie", testString, new CookieOptions()); var values = context.Response.Headers["Set-Cookie"]; - Assert.Equal(1, values.Count); - Assert.Equal("TestCookie=" + testString + "; path=/", values[0]); + Assert.Single(values); + Assert.Equal("TestCookie=" + testString + "; path=/; samesite=lax", values[0]); } [Fact] @@ -27,20 +27,20 @@ public void AppendLargeCookieWithLimit_Chunked() HttpContext context = new DefaultHttpContext(); string testString = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - new ChunkingCookieManager() { ChunkSize = 30 }.AppendResponseCookie(context, "TestCookie", testString, new CookieOptions()); + new ChunkingCookieManager() { ChunkSize = 44 }.AppendResponseCookie(context, "TestCookie", testString, new CookieOptions()); var values = context.Response.Headers["Set-Cookie"]; Assert.Equal(9, values.Count); Assert.Equal(new[] { - "TestCookie=chunks-8; path=/", - "TestCookieC1=abcdefgh; path=/", - "TestCookieC2=ijklmnop; path=/", - "TestCookieC3=qrstuvwx; path=/", - "TestCookieC4=yz012345; path=/", - "TestCookieC5=6789ABCD; path=/", - "TestCookieC6=EFGHIJKL; path=/", - "TestCookieC7=MNOPQRST; path=/", - "TestCookieC8=UVWXYZ; path=/", + "TestCookie=chunks-8; path=/; samesite=lax", + "TestCookieC1=abcdefgh; path=/; samesite=lax", + "TestCookieC2=ijklmnop; path=/; samesite=lax", + "TestCookieC3=qrstuvwx; path=/; samesite=lax", + "TestCookieC4=yz012345; path=/; samesite=lax", + "TestCookieC5=6789ABCD; path=/; samesite=lax", + "TestCookieC6=EFGHIJKL; path=/; samesite=lax", + "TestCookieC7=MNOPQRST; path=/; samesite=lax", + "TestCookieC8=UVWXYZ; path=/; samesite=lax", }, values); } @@ -81,7 +81,8 @@ public void GetLargeChunkedCookieWithMissingChunk_ThrowingEnabled_Throws() "TestCookieC7=STUVWXYZ" }; - Assert.Throws(() => new ChunkingCookieManager().GetRequestCookie(context, "TestCookie")); + Assert.Throws(() => new ChunkingCookieManager() { ThrowForPartialCookies = true } + .GetRequestCookie(context, "TestCookie")); } [Fact] @@ -116,14 +117,14 @@ public void DeleteChunkedCookieWithOptions_AllDeleted() Assert.Equal(8, cookies.Count); Assert.Equal(new[] { - "TestCookie=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/", - "TestCookieC1=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/", - "TestCookieC2=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/", - "TestCookieC3=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/", - "TestCookieC4=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/", - "TestCookieC5=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/", - "TestCookieC6=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/", - "TestCookieC7=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/", + "TestCookie=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; samesite=lax", + "TestCookieC1=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; samesite=lax", + "TestCookieC2=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; samesite=lax", + "TestCookieC3=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; samesite=lax", + "TestCookieC4=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; samesite=lax", + "TestCookieC5=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; samesite=lax", + "TestCookieC6=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; samesite=lax", + "TestCookieC7=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=foo.com; path=/; samesite=lax", }, cookies); } } diff --git a/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.csproj b/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.csproj new file mode 100644 index 000000000..2f38abff9 --- /dev/null +++ b/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.csproj @@ -0,0 +1,15 @@ + + + + netcoreapp3.0 + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.xproj b/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.xproj deleted file mode 100644 index d95a6c128..000000000 --- a/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0.25420 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 51563775-c659-4907-9baf-9995bab87d01 - Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/project.json b/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/project.json deleted file mode 100644 index d8761ffa3..000000000 --- a/test/Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test/project.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "buildOptions": { - "warningsAsErrors": true - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.ChunkingCookieManager.Sources": { - "version": "1.2.0-*", - "type": "build" - }, - "Microsoft.AspNetCore.Http": "1.2.0-*", - "xunit": "2.2.0-*" - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - }, - "net451": {} - }, - "testRunner": "xunit" -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.CookiePolicy.Test/CookieConsentTests.cs b/test/Microsoft.AspNetCore.CookiePolicy.Test/CookieConsentTests.cs new file mode 100644 index 000000000..fffb8cc88 --- /dev/null +++ b/test/Microsoft.AspNetCore.CookiePolicy.Test/CookieConsentTests.cs @@ -0,0 +1,660 @@ +// 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.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Microsoft.AspNetCore.CookiePolicy.Test +{ + public class CookieConsentTests + { + [Fact] + public async Task ConsentChecksOffByDefault() + { + var httpContext = await RunTestAsync(options => { }, requestContext => { }, context => + { + var feature = context.Features.Get(); + Assert.False(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.True(feature.CanTrack); + context.Response.Cookies.Append("Test", "Value"); + return Task.CompletedTask; + }); + Assert.Equal("Test=Value; path=/; samesite=lax", httpContext.Response.Headers[HeaderNames.SetCookie]); + } + + [Fact] + public async Task ConsentEnabledForTemplateScenario() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + }, + requestContext => { }, context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + context.Response.Cookies.Append("Test", "Value"); + return Task.CompletedTask; + }); + Assert.Empty(httpContext.Response.Headers[HeaderNames.SetCookie]); + } + + [Fact] + public async Task NonEssentialCookiesWithOptionsExcluded() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + }, + requestContext => { }, context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + context.Response.Cookies.Append("Test", "Value", new CookieOptions() { IsEssential = false }); + return Task.CompletedTask; + }); + Assert.Empty(httpContext.Response.Headers[HeaderNames.SetCookie]); + } + + [Fact] + public async Task NonEssentialCookiesCanBeAllowedViaOnAppendCookie() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + options.OnAppendCookie = context => + { + Assert.True(context.IsConsentNeeded); + Assert.False(context.HasConsent); + Assert.False(context.IssueCookie); + context.IssueCookie = true; + }; + }, + requestContext => { }, context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + context.Response.Cookies.Append("Test", "Value", new CookieOptions() { IsEssential = false }); + return Task.CompletedTask; + }); + Assert.Equal("Test=Value; path=/; samesite=lax", httpContext.Response.Headers[HeaderNames.SetCookie]); + } + + [Fact] + public async Task NeedsConsentDoesNotPreventEssentialCookies() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + }, + requestContext => { }, context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + context.Response.Cookies.Append("Test", "Value", new CookieOptions() { IsEssential = true }); + return Task.CompletedTask; + }); + Assert.Equal("Test=Value; path=/; samesite=lax", httpContext.Response.Headers[HeaderNames.SetCookie]); + } + + [Fact] + public async Task EssentialCookiesCanBeExcludedByOnAppendCookie() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + options.OnAppendCookie = context => + { + Assert.True(context.IsConsentNeeded); + Assert.True(context.HasConsent); + Assert.True(context.IssueCookie); + context.IssueCookie = false; + }; + }, + requestContext => + { + requestContext.Request.Headers[HeaderNames.Cookie] = ".AspNet.Consent=yes"; + }, + context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.True(feature.HasConsent); + Assert.True(feature.CanTrack); + context.Response.Cookies.Append("Test", "Value", new CookieOptions() { IsEssential = true }); + return Task.CompletedTask; + }); + Assert.Empty(httpContext.Response.Headers[HeaderNames.SetCookie]); + } + + [Fact] + public async Task HasConsentReadsRequestCookie() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + }, + requestContext => + { + requestContext.Request.Headers[HeaderNames.Cookie] = ".AspNet.Consent=yes"; + }, + context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.True(feature.HasConsent); + Assert.True(feature.CanTrack); + context.Response.Cookies.Append("Test", "Value"); + return Task.CompletedTask; + }); + Assert.Equal("Test=Value; path=/; samesite=lax", httpContext.Response.Headers[HeaderNames.SetCookie]); + } + + [Fact] + public async Task HasConsentIgnoresInvalidRequestCookie() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + }, + requestContext => + { + requestContext.Request.Headers[HeaderNames.Cookie] = ".AspNet.Consent=IAmATeapot"; + }, + context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + context.Response.Cookies.Append("Test", "Value"); + return Task.CompletedTask; + }); + Assert.Empty(httpContext.Response.Headers[HeaderNames.SetCookie]); + } + + [Fact] + public async Task GrantConsentSetsCookie() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + }, + requestContext => { }, + context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + + feature.GrantConsent(); + + Assert.True(feature.IsConsentNeeded); + Assert.True(feature.HasConsent); + Assert.True(feature.CanTrack); + + context.Response.Cookies.Append("Test", "Value"); + return Task.CompletedTask; + }); + + var cookies = SetCookieHeaderValue.ParseList(httpContext.Response.Headers[HeaderNames.SetCookie]); + Assert.Equal(2, cookies.Count); + var consentCookie = cookies[0]; + Assert.Equal(".AspNet.Consent", consentCookie.Name); + Assert.Equal("yes", consentCookie.Value); + Assert.True(consentCookie.Expires.HasValue); + Assert.True(consentCookie.Expires.Value > DateTimeOffset.Now + TimeSpan.FromDays(364)); + Assert.Equal(Net.Http.Headers.SameSiteMode.Lax, consentCookie.SameSite); + Assert.NotNull(consentCookie.Expires); + var testCookie = cookies[1]; + Assert.Equal("Test", testCookie.Name); + Assert.Equal("Value", testCookie.Value); + Assert.Equal(Net.Http.Headers.SameSiteMode.Lax, testCookie.SameSite); + Assert.Null(testCookie.Expires); + } + + [Fact] + public async Task GrantConsentAppliesPolicyToConsentCookie() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + options.MinimumSameSitePolicy = Http.SameSiteMode.Strict; + options.OnAppendCookie = context => + { + Assert.Equal(".AspNet.Consent", context.CookieName); + Assert.Equal("yes", context.CookieValue); + Assert.Equal(Http.SameSiteMode.Strict, context.CookieOptions.SameSite); + context.CookieName += "1"; + context.CookieValue += "1"; + }; + }, + requestContext => { }, + context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + + feature.GrantConsent(); + + Assert.True(feature.IsConsentNeeded); + Assert.True(feature.HasConsent); + Assert.True(feature.CanTrack); + + return Task.CompletedTask; + }); + + var cookies = SetCookieHeaderValue.ParseList(httpContext.Response.Headers[HeaderNames.SetCookie]); + Assert.Equal(1, cookies.Count); + var consentCookie = cookies[0]; + Assert.Equal(".AspNet.Consent1", consentCookie.Name); + Assert.Equal("yes1", consentCookie.Value); + Assert.Equal(Net.Http.Headers.SameSiteMode.Strict, consentCookie.SameSite); + Assert.NotNull(consentCookie.Expires); + } + + [Fact] + public async Task GrantConsentWhenAlreadyHasItDoesNotSetCookie() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + }, + requestContext => + { + requestContext.Request.Headers[HeaderNames.Cookie] = ".AspNet.Consent=yes"; + }, + context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.True(feature.HasConsent); + Assert.True(feature.CanTrack); + + feature.GrantConsent(); + + Assert.True(feature.IsConsentNeeded); + Assert.True(feature.HasConsent); + Assert.True(feature.CanTrack); + + context.Response.Cookies.Append("Test", "Value"); + return Task.CompletedTask; + }); + + Assert.Equal("Test=Value; path=/; samesite=lax", httpContext.Response.Headers[HeaderNames.SetCookie]); + } + + [Fact] + public async Task GrantConsentAfterResponseStartsSetsHasConsentButDoesNotSetCookie() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + }, + requestContext => { }, + async context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + + await context.Response.WriteAsync("Started."); + + feature.GrantConsent(); + + Assert.True(feature.IsConsentNeeded); + Assert.True(feature.HasConsent); + Assert.True(feature.CanTrack); + + Assert.Throws(() => context.Response.Cookies.Append("Test", "Value")); + + await context.Response.WriteAsync("Granted."); + }); + + var reader = new StreamReader(httpContext.Response.Body); + Assert.Equal("Started.Granted.", await reader.ReadToEndAsync()); + Assert.Empty(httpContext.Response.Headers[HeaderNames.SetCookie]); + } + + [Fact] + public async Task WithdrawConsentWhenNotHasConsentNoOps() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + }, + requestContext => { }, + context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + + feature.WithdrawConsent(); + + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + + context.Response.Cookies.Append("Test", "Value"); + return Task.CompletedTask; + }); + + Assert.Empty(httpContext.Response.Headers[HeaderNames.SetCookie]); + } + + [Fact] + public async Task WithdrawConsentDeletesCookie() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + }, + requestContext => + { + requestContext.Request.Headers[HeaderNames.Cookie] = ".AspNet.Consent=yes"; + }, + context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.True(feature.HasConsent); + Assert.True(feature.CanTrack); + context.Response.Cookies.Append("Test", "Value1"); + + feature.WithdrawConsent(); + + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + + context.Response.Cookies.Append("Test", "Value2"); + return Task.CompletedTask; + }); + + var cookies = SetCookieHeaderValue.ParseList(httpContext.Response.Headers[HeaderNames.SetCookie]); + Assert.Equal(2, cookies.Count); + var testCookie = cookies[0]; + Assert.Equal("Test", testCookie.Name); + Assert.Equal("Value1", testCookie.Value); + Assert.Equal(Net.Http.Headers.SameSiteMode.Lax, testCookie.SameSite); + Assert.Null(testCookie.Expires); + var consentCookie = cookies[1]; + Assert.Equal(".AspNet.Consent", consentCookie.Name); + Assert.Equal("", consentCookie.Value); + Assert.Equal(Net.Http.Headers.SameSiteMode.Lax, consentCookie.SameSite); + Assert.NotNull(consentCookie.Expires); + } + + [Fact] + public async Task WithdrawConsentAppliesPolicyToDeleteCookie() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + options.MinimumSameSitePolicy = Http.SameSiteMode.Strict; + options.OnDeleteCookie = context => + { + Assert.Equal(".AspNet.Consent", context.CookieName); + context.CookieName += "1"; + }; + }, + requestContext => + { + requestContext.Request.Headers[HeaderNames.Cookie] = ".AspNet.Consent=yes"; + }, + context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.True(feature.HasConsent); + Assert.True(feature.CanTrack); + + feature.WithdrawConsent(); + + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + + return Task.CompletedTask; + }); + + var cookies = SetCookieHeaderValue.ParseList(httpContext.Response.Headers[HeaderNames.SetCookie]); + Assert.Equal(1, cookies.Count); + var consentCookie = cookies[0]; + Assert.Equal(".AspNet.Consent1", consentCookie.Name); + Assert.Equal("", consentCookie.Value); + Assert.Equal(Net.Http.Headers.SameSiteMode.Strict, consentCookie.SameSite); + Assert.NotNull(consentCookie.Expires); + } + + [Fact] + public async Task WithdrawConsentAfterResponseHasStartedDoesNotDeleteCookie() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + }, + requestContext => + { + requestContext.Request.Headers[HeaderNames.Cookie] = ".AspNet.Consent=yes"; + }, + async context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.True(feature.HasConsent); + Assert.True(feature.CanTrack); + context.Response.Cookies.Append("Test", "Value1"); + + await context.Response.WriteAsync("Started."); + + feature.WithdrawConsent(); + + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + + // Doesn't throw the normal InvalidOperationException because the cookie is never written + context.Response.Cookies.Append("Test", "Value2"); + + await context.Response.WriteAsync("Withdrawn."); + }); + + var reader = new StreamReader(httpContext.Response.Body); + Assert.Equal("Started.Withdrawn.", await reader.ReadToEndAsync()); + Assert.Equal("Test=Value1; path=/; samesite=lax", httpContext.Response.Headers[HeaderNames.SetCookie]); + } + + [Fact] + public async Task DeleteCookieDoesNotRequireConsent() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + }, + requestContext => { }, + context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + context.Response.Cookies.Delete("Test"); + return Task.CompletedTask; + }); + + var cookies = SetCookieHeaderValue.ParseList(httpContext.Response.Headers[HeaderNames.SetCookie]); + Assert.Equal(1, cookies.Count); + var testCookie = cookies[0]; + Assert.Equal("Test", testCookie.Name); + Assert.Equal("", testCookie.Value); + Assert.Equal(Net.Http.Headers.SameSiteMode.Lax, testCookie.SameSite); + Assert.NotNull(testCookie.Expires); + } + + [Fact] + public async Task OnDeleteCookieCanSuppressCookie() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + options.OnDeleteCookie = context => + { + Assert.True(context.IsConsentNeeded); + Assert.False(context.HasConsent); + Assert.True(context.IssueCookie); + context.IssueCookie = false; + }; + }, + requestContext => { }, + context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + context.Response.Cookies.Delete("Test"); + return Task.CompletedTask; + }); + + Assert.Empty(httpContext.Response.Headers[HeaderNames.SetCookie]); + } + + [Fact] + public async Task CreateConsentCookieMatchesGrantConsentCookie() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + }, + requestContext => { }, + context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + + feature.GrantConsent(); + + Assert.True(feature.IsConsentNeeded); + Assert.True(feature.HasConsent); + Assert.True(feature.CanTrack); + + var cookie = feature.CreateConsentCookie(); + context.Response.Headers["ManualCookie"] = cookie; + + return Task.CompletedTask; + }); + + var cookies = SetCookieHeaderValue.ParseList(httpContext.Response.Headers[HeaderNames.SetCookie]); + Assert.Equal(1, cookies.Count); + var consentCookie = cookies[0]; + Assert.Equal(".AspNet.Consent", consentCookie.Name); + Assert.Equal("yes", consentCookie.Value); + Assert.Equal(Net.Http.Headers.SameSiteMode.Lax, consentCookie.SameSite); + Assert.NotNull(consentCookie.Expires); + + cookies = SetCookieHeaderValue.ParseList(httpContext.Response.Headers["ManualCookie"]); + Assert.Equal(1, cookies.Count); + var manualCookie = cookies[0]; + Assert.Equal(consentCookie.Name, manualCookie.Name); + Assert.Equal(consentCookie.Value, manualCookie.Value); + Assert.Equal(consentCookie.SameSite, manualCookie.SameSite); + Assert.NotNull(manualCookie.Expires); // Expires may not exactly match to the second. + } + + [Fact] + public async Task CreateConsentCookieAppliesPolicy() + { + var httpContext = await RunTestAsync(options => + { + options.CheckConsentNeeded = context => true; + options.MinimumSameSitePolicy = Http.SameSiteMode.Strict; + options.OnAppendCookie = context => + { + Assert.Equal(".AspNet.Consent", context.CookieName); + Assert.Equal("yes", context.CookieValue); + Assert.Equal(Http.SameSiteMode.Strict, context.CookieOptions.SameSite); + context.CookieName += "1"; + context.CookieValue += "1"; + }; + }, + requestContext => { }, + context => + { + var feature = context.Features.Get(); + Assert.True(feature.IsConsentNeeded); + Assert.False(feature.HasConsent); + Assert.False(feature.CanTrack); + + feature.GrantConsent(); + + Assert.True(feature.IsConsentNeeded); + Assert.True(feature.HasConsent); + Assert.True(feature.CanTrack); + + var cookie = feature.CreateConsentCookie(); + context.Response.Headers["ManualCookie"] = cookie; + + return Task.CompletedTask; + }); + + var cookies = SetCookieHeaderValue.ParseList(httpContext.Response.Headers[HeaderNames.SetCookie]); + Assert.Equal(1, cookies.Count); + var consentCookie = cookies[0]; + Assert.Equal(".AspNet.Consent1", consentCookie.Name); + Assert.Equal("yes1", consentCookie.Value); + Assert.Equal(Net.Http.Headers.SameSiteMode.Strict, consentCookie.SameSite); + Assert.NotNull(consentCookie.Expires); + + cookies = SetCookieHeaderValue.ParseList(httpContext.Response.Headers["ManualCookie"]); + Assert.Equal(1, cookies.Count); + var manualCookie = cookies[0]; + Assert.Equal(consentCookie.Name, manualCookie.Name); + Assert.Equal(consentCookie.Value, manualCookie.Value); + Assert.Equal(consentCookie.SameSite, manualCookie.SameSite); + Assert.NotNull(manualCookie.Expires); // Expires may not exactly match to the second. + } + + private Task RunTestAsync(Action configureOptions, Action configureRequest, RequestDelegate handleRequest) + { + var builder = new WebHostBuilder() + .ConfigureServices(services => + { + services.Configure(configureOptions); + }) + .Configure(app => + { + app.UseCookiePolicy(); + app.Run(handleRequest); + }); + var server = new TestServer(builder); + return server.SendAsync(configureRequest); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.CookiePolicy.Test/CookiePolicyTests.cs b/test/Microsoft.AspNetCore.CookiePolicy.Test/CookiePolicyTests.cs index 34d967617..a2592e557 100644 --- a/test/Microsoft.AspNetCore.CookiePolicy.Test/CookiePolicyTests.cs +++ b/test/Microsoft.AspNetCore.CookiePolicy.Test/CookiePolicyTests.cs @@ -5,6 +5,7 @@ using System.Security.Claims; using System.Security.Principal; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -35,6 +36,15 @@ public class CookiePolicyTests context.Response.Cookies.Append("D", "D", new CookieOptions { HttpOnly = true }); return Task.FromResult(0); }; + private RequestDelegate SameSiteCookieAppends = context => + { + context.Response.Cookies.Append("A", "A"); + context.Response.Cookies.Append("B", "B", new CookieOptions { SameSite = Http.SameSiteMode.None }); + context.Response.Cookies.Append("C", "C", new CookieOptions()); + context.Response.Cookies.Append("D", "D", new CookieOptions { SameSite = Http.SameSiteMode.Lax }); + context.Response.Cookies.Append("E", "E", new CookieOptions { SameSite = Http.SameSiteMode.Strict }); + return Task.FromResult(0); + }; [Fact] public async Task SecureAlwaysSetsSecure() @@ -49,10 +59,10 @@ await RunTest("/secureAlways", transaction => { Assert.NotNull(transaction.SetCookie); - Assert.Equal("A=A; path=/; secure", transaction.SetCookie[0]); - Assert.Equal("B=B; path=/; secure", transaction.SetCookie[1]); - Assert.Equal("C=C; path=/; secure", transaction.SetCookie[2]); - Assert.Equal("D=D; path=/; secure", transaction.SetCookie[3]); + Assert.Equal("A=A; path=/; secure; samesite=lax", transaction.SetCookie[0]); + Assert.Equal("B=B; path=/; secure; samesite=lax", transaction.SetCookie[1]); + Assert.Equal("C=C; path=/; secure; samesite=lax", transaction.SetCookie[2]); + Assert.Equal("D=D; path=/; secure; samesite=lax", transaction.SetCookie[3]); })); } @@ -69,10 +79,10 @@ await RunTest("/secureNone", transaction => { Assert.NotNull(transaction.SetCookie); - Assert.Equal("A=A; path=/", transaction.SetCookie[0]); - Assert.Equal("B=B; path=/", transaction.SetCookie[1]); - Assert.Equal("C=C; path=/", transaction.SetCookie[2]); - Assert.Equal("D=D; path=/; secure", transaction.SetCookie[3]); + Assert.Equal("A=A; path=/; samesite=lax", transaction.SetCookie[0]); + Assert.Equal("B=B; path=/; samesite=lax", transaction.SetCookie[1]); + Assert.Equal("C=C; path=/; samesite=lax", transaction.SetCookie[2]); + Assert.Equal("D=D; path=/; secure; samesite=lax", transaction.SetCookie[3]); })); } @@ -89,19 +99,19 @@ await RunTest("/secureSame", transaction => { Assert.NotNull(transaction.SetCookie); - Assert.Equal("A=A; path=/", transaction.SetCookie[0]); - Assert.Equal("B=B; path=/", transaction.SetCookie[1]); - Assert.Equal("C=C; path=/", transaction.SetCookie[2]); - Assert.Equal("D=D; path=/", transaction.SetCookie[3]); + Assert.Equal("A=A; path=/; samesite=lax", transaction.SetCookie[0]); + Assert.Equal("B=B; path=/; samesite=lax", transaction.SetCookie[1]); + Assert.Equal("C=C; path=/; samesite=lax", transaction.SetCookie[2]); + Assert.Equal("D=D; path=/; secure; samesite=lax", transaction.SetCookie[3]); }), new RequestTest("https://example.com/secureSame", transaction => { Assert.NotNull(transaction.SetCookie); - Assert.Equal("A=A; path=/; secure", transaction.SetCookie[0]); - Assert.Equal("B=B; path=/; secure", transaction.SetCookie[1]); - Assert.Equal("C=C; path=/; secure", transaction.SetCookie[2]); - Assert.Equal("D=D; path=/; secure", transaction.SetCookie[3]); + Assert.Equal("A=A; path=/; secure; samesite=lax", transaction.SetCookie[0]); + Assert.Equal("B=B; path=/; secure; samesite=lax", transaction.SetCookie[1]); + Assert.Equal("C=C; path=/; secure; samesite=lax", transaction.SetCookie[2]); + Assert.Equal("D=D; path=/; secure; samesite=lax", transaction.SetCookie[3]); })); } @@ -118,10 +128,10 @@ await RunTest("/httpOnlyAlways", transaction => { Assert.NotNull(transaction.SetCookie); - Assert.Equal("A=A; path=/; httponly", transaction.SetCookie[0]); - Assert.Equal("B=B; path=/; httponly", transaction.SetCookie[1]); - Assert.Equal("C=C; path=/; httponly", transaction.SetCookie[2]); - Assert.Equal("D=D; path=/; httponly", transaction.SetCookie[3]); + Assert.Equal("A=A; path=/; samesite=lax; httponly", transaction.SetCookie[0]); + Assert.Equal("B=B; path=/; samesite=lax; httponly", transaction.SetCookie[1]); + Assert.Equal("C=C; path=/; samesite=lax; httponly", transaction.SetCookie[2]); + Assert.Equal("D=D; path=/; samesite=lax; httponly", transaction.SetCookie[3]); })); } @@ -136,12 +146,75 @@ await RunTest("/httpOnlyNone", HttpCookieAppends, new RequestTest("http://example.com/httpOnlyNone", transaction => + { + Assert.NotNull(transaction.SetCookie); + Assert.Equal("A=A; path=/; samesite=lax", transaction.SetCookie[0]); + Assert.Equal("B=B; path=/; samesite=lax", transaction.SetCookie[1]); + Assert.Equal("C=C; path=/; samesite=lax", transaction.SetCookie[2]); + Assert.Equal("D=D; path=/; samesite=lax; httponly", transaction.SetCookie[3]); + })); + } + + [Fact] + public async Task SameSiteStrictSetsItAlways() + { + await RunTest("/sameSiteStrict", + new CookiePolicyOptions + { + MinimumSameSitePolicy = Http.SameSiteMode.Strict + }, + SameSiteCookieAppends, + new RequestTest("http://example.com/sameSiteStrict", + transaction => + { + Assert.NotNull(transaction.SetCookie); + Assert.Equal("A=A; path=/; samesite=strict", transaction.SetCookie[0]); + Assert.Equal("B=B; path=/; samesite=strict", transaction.SetCookie[1]); + Assert.Equal("C=C; path=/; samesite=strict", transaction.SetCookie[2]); + Assert.Equal("D=D; path=/; samesite=strict", transaction.SetCookie[3]); + Assert.Equal("E=E; path=/; samesite=strict", transaction.SetCookie[4]); + })); + } + + [Fact] + public async Task SameSiteLaxSetsItAlways() + { + await RunTest("/sameSiteLax", + new CookiePolicyOptions + { + MinimumSameSitePolicy = Http.SameSiteMode.Lax + }, + SameSiteCookieAppends, + new RequestTest("http://example.com/sameSiteLax", + transaction => + { + Assert.NotNull(transaction.SetCookie); + Assert.Equal("A=A; path=/; samesite=lax", transaction.SetCookie[0]); + Assert.Equal("B=B; path=/; samesite=lax", transaction.SetCookie[1]); + Assert.Equal("C=C; path=/; samesite=lax", transaction.SetCookie[2]); + Assert.Equal("D=D; path=/; samesite=lax", transaction.SetCookie[3]); + Assert.Equal("E=E; path=/; samesite=strict", transaction.SetCookie[4]); + })); + } + + [Fact] + public async Task SameSiteNoneLeavesItAlone() + { + await RunTest("/sameSiteNone", + new CookiePolicyOptions + { + MinimumSameSitePolicy = Http.SameSiteMode.None + }, + SameSiteCookieAppends, + new RequestTest("http://example.com/sameSiteNone", + transaction => { Assert.NotNull(transaction.SetCookie); Assert.Equal("A=A; path=/", transaction.SetCookie[0]); Assert.Equal("B=B; path=/", transaction.SetCookie[1]); - Assert.Equal("C=C; path=/", transaction.SetCookie[2]); - Assert.Equal("D=D; path=/; httponly", transaction.SetCookie[3]); + Assert.Equal("C=C; path=/; samesite=lax", transaction.SetCookie[2]); + Assert.Equal("D=D; path=/; samesite=lax", transaction.SetCookie[3]); + Assert.Equal("E=E; path=/; samesite=strict", transaction.SetCookie[4]); })); } @@ -169,10 +242,10 @@ public async Task CookiePolicyCanHijackAppend() var transaction = await server.SendAsync("http://example.com/login"); Assert.NotNull(transaction.SetCookie); - Assert.Equal("Hao=Hao; path=/", transaction.SetCookie[0]); - Assert.Equal("Hao=Hao; path=/", transaction.SetCookie[1]); - Assert.Equal("Hao=Hao; path=/", transaction.SetCookie[2]); - Assert.Equal("Hao=Hao; path=/; secure", transaction.SetCookie[3]); + Assert.Equal("Hao=Hao; path=/; samesite=lax", transaction.SetCookie[0]); + Assert.Equal("Hao=Hao; path=/; samesite=lax", transaction.SetCookie[1]); + Assert.Equal("Hao=Hao; path=/; samesite=lax", transaction.SetCookie[2]); + Assert.Equal("Hao=Hao; path=/; secure; samesite=lax", transaction.SetCookie[3]); } [Fact] @@ -200,7 +273,7 @@ public async Task CookiePolicyCanHijackDelete() Assert.NotNull(transaction.SetCookie); Assert.Equal(1, transaction.SetCookie.Count); - Assert.Equal("A=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/", transaction.SetCookie[0]); + Assert.Equal("A=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; secure; samesite=lax", transaction.SetCookie[0]); } [Fact] @@ -239,7 +312,12 @@ public async Task CookiePolicyAppliesToCookieAuth() var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddAuthentication(); + services.AddAuthentication().AddCookie(o => + { + o.Cookie.Name = "TestCookie"; + o.Cookie.HttpOnly = false; + o.Cookie.SecurePolicy = CookieSecurePolicy.None; + }); }) .Configure(app => { @@ -248,15 +326,10 @@ public async Task CookiePolicyAppliesToCookieAuth() HttpOnly = HttpOnlyPolicy.Always, Secure = CookieSecurePolicy.Always, }); - app.UseCookieAuthentication(new CookieAuthenticationOptions() - { - CookieName = "TestCookie", - CookieHttpOnly = false, - CookieSecure = CookieSecurePolicy.None, - }); + app.UseAuthentication(); app.Run(context => { - return context.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, + return context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("TestUser", "Cookies")))); }); }); @@ -279,7 +352,12 @@ public async Task CookiePolicyAppliesToCookieAuthChunks() var builder = new WebHostBuilder() .ConfigureServices(services => { - services.AddAuthentication(); + services.AddAuthentication().AddCookie(o => + { + o.Cookie.Name = "TestCookie"; + o.Cookie.HttpOnly = false; + o.Cookie.SecurePolicy = CookieSecurePolicy.None; + }); }) .Configure(app => { @@ -288,15 +366,10 @@ public async Task CookiePolicyAppliesToCookieAuthChunks() HttpOnly = HttpOnlyPolicy.Always, Secure = CookieSecurePolicy.Always, }); - app.UseCookieAuthentication(new CookieAuthenticationOptions() - { - CookieName = "TestCookie", - CookieHttpOnly = false, - CookieSecure = CookieSecurePolicy.None, - }); + app.UseAuthentication(); app.Run(context => { - return context.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, + return context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity(new string('c', 1024 * 5), "Cookies")))); }); }); diff --git a/test/Microsoft.AspNetCore.CookiePolicy.Test/Microsoft.AspNetCore.CookiePolicy.Test.csproj b/test/Microsoft.AspNetCore.CookiePolicy.Test/Microsoft.AspNetCore.CookiePolicy.Test.csproj new file mode 100644 index 000000000..3dc3df2e2 --- /dev/null +++ b/test/Microsoft.AspNetCore.CookiePolicy.Test/Microsoft.AspNetCore.CookiePolicy.Test.csproj @@ -0,0 +1,17 @@ + + + + netcoreapp3.0 + + + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.CookiePolicy.Test/Microsoft.AspNetCore.CookiePolicy.Test.xproj b/test/Microsoft.AspNetCore.CookiePolicy.Test/Microsoft.AspNetCore.CookiePolicy.Test.xproj deleted file mode 100644 index 06582d576..000000000 --- a/test/Microsoft.AspNetCore.CookiePolicy.Test/Microsoft.AspNetCore.CookiePolicy.Test.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 1790e052-646f-4529-b90e-6fea95520d69 - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.CookiePolicy.Test/project.json b/test/Microsoft.AspNetCore.CookiePolicy.Test/project.json deleted file mode 100644 index d849b6bc2..000000000 --- a/test/Microsoft.AspNetCore.CookiePolicy.Test/project.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "buildOptions": { - "warningsAsErrors": true - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Authentication.Cookies": "1.2.0-*", - "Microsoft.AspNetCore.CookiePolicy": "1.2.0-*", - "Microsoft.AspNetCore.TestHost": "1.2.0-*", - "Microsoft.Extensions.DependencyInjection": "1.2.0-*", - "xunit": "2.2.0-*" - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.2.0-*", - "type": "platform" - } - } - }, - "net451": {} - }, - "testRunner": "xunit" -} \ No newline at end of file diff --git a/test/Microsoft.Owin.Security.Interop.Test/CookieInteropTests.cs b/test/Microsoft.Owin.Security.Interop.Test/CookieInteropTests.cs index 79288b026..24bf09722 100644 --- a/test/Microsoft.Owin.Security.Interop.Test/CookieInteropTests.cs +++ b/test/Microsoft.Owin.Security.Interop.Test/CookieInteropTests.cs @@ -1,6 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +/* See https://github.com/aspnet/AspNetCore/issues/4074. + +This test is was disabled as a part of changing frameworks. This test will need to be re-written using separate .NET Core and .NET Framework processes. + using System.Collections.Generic; using System.IO; using System.Linq; @@ -13,6 +17,8 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Net.Http.Headers; @@ -34,7 +40,7 @@ public async Task AspNetCoreWithInteropCookieContainsIdentity() var dataProtection = DataProtectionProvider.Create(new DirectoryInfo("..\\..\\artifacts")); var dataProtector = dataProtection.CreateProtector( "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", // full name of the ASP.NET Core type - CookieAuthenticationDefaults.AuthenticationType, "v2"); + Cookies.CookieAuthenticationDefaults.AuthenticationType, "v2"); var interopServer = TestServer.Create(app => { @@ -59,17 +65,14 @@ public async Task AspNetCoreWithInteropCookieContainsIdentity() var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new AspNetCore.Builder.CookieAuthenticationOptions - { - DataProtectionProvider = dataProtection - }); + app.UseAuthentication(); app.Run(async context => { - var result = await context.Authentication.AuthenticateAsync("Cookies"); - await context.Response.WriteAsync(result.Identity.Name); + var result = await context.AuthenticateAsync("Cookies"); + await context.Response.WriteAsync(result.Ticket.Principal.Identity.Name); }); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie(o => o.DataProtectionProvider = dataProtection)); var newServer = new AspNetCore.TestHost.TestServer(builder); var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/login"); @@ -91,7 +94,7 @@ public async Task AspNetCoreWithLargeInteropCookieContainsIdentity() var dataProtection = DataProtectionProvider.Create(new DirectoryInfo("..\\..\\artifacts")); var dataProtector = dataProtection.CreateProtector( "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", // full name of the ASP.NET Core type - CookieAuthenticationDefaults.AuthenticationType, "v2"); + Cookies.CookieAuthenticationDefaults.AuthenticationType, "v2"); var interopServer = TestServer.Create(app => { @@ -117,17 +120,14 @@ public async Task AspNetCoreWithLargeInteropCookieContainsIdentity() var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new AspNetCore.Builder.CookieAuthenticationOptions - { - DataProtectionProvider = dataProtection - }); + app.UseAuthentication(); app.Run(async context => { - var result = await context.Authentication.AuthenticateAsync("Cookies"); - await context.Response.WriteAsync(result.Identity.Name); + var result = await context.AuthenticateAsync("Cookies"); + await context.Response.WriteAsync(result.Ticket.Principal.Identity.Name); }); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie(o => o.DataProtectionProvider = dataProtection)); var newServer = new AspNetCore.TestHost.TestServer(builder); var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/login"); @@ -151,18 +151,15 @@ public async Task InteropWithNewCookieContainsIdentity() var dataProtection = DataProtectionProvider.Create(new DirectoryInfo("..\\..\\artifacts")); var dataProtector = dataProtection.CreateProtector( "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", // full name of the ASP.NET Core type - CookieAuthenticationDefaults.AuthenticationType, "v2"); + Cookies.CookieAuthenticationDefaults.AuthenticationType, "v2"); var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new AspNetCore.Builder.CookieAuthenticationOptions - { - DataProtectionProvider = dataProtection - }); - app.Run(context => context.Authentication.SignInAsync("Cookies", user)); + app.UseAuthentication(); + app.Run(context => context.SignInAsync("Cookies", user)); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie(o => o.DataProtectionProvider = dataProtection)); var newServer = new AspNetCore.TestHost.TestServer(builder); var cookies = await SendAndGetCookies(newServer, "http://example.com/login"); @@ -201,18 +198,15 @@ public async Task InteropWithLargeNewCookieContainsIdentity() var dataProtection = DataProtectionProvider.Create(new DirectoryInfo("..\\..\\artifacts")); var dataProtector = dataProtection.CreateProtector( "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", // full name of the ASP.NET Core type - CookieAuthenticationDefaults.AuthenticationType, "v2"); + Cookies.CookieAuthenticationDefaults.AuthenticationType, "v2"); var builder = new WebHostBuilder() .Configure(app => { - app.UseCookieAuthentication(new AspNetCore.Builder.CookieAuthenticationOptions - { - DataProtectionProvider = dataProtection - }); - app.Run(context => context.Authentication.SignInAsync("Cookies", user)); + app.UseAuthentication(); + app.Run(context => context.SignInAsync("Cookies", user)); }) - .ConfigureServices(services => services.AddAuthentication()); + .ConfigureServices(services => services.AddAuthentication().AddCookie(o => o.DataProtectionProvider = dataProtection)); var newServer = new AspNetCore.TestHost.TestServer(builder); var cookies = await SendAndGetCookies(newServer, "http://example.com/login"); @@ -340,3 +334,4 @@ private class Transaction } } +*/ diff --git a/test/Microsoft.Owin.Security.Interop.Test/Microsoft.Owin.Security.Interop.Test.csproj b/test/Microsoft.Owin.Security.Interop.Test/Microsoft.Owin.Security.Interop.Test.csproj new file mode 100644 index 000000000..57b224ef6 --- /dev/null +++ b/test/Microsoft.Owin.Security.Interop.Test/Microsoft.Owin.Security.Interop.Test.csproj @@ -0,0 +1,19 @@ + + + + net461 + + false + + + + + + + + + + + + + diff --git a/test/Microsoft.Owin.Security.Interop.Test/Microsoft.Owin.Security.Interop.Test.xproj b/test/Microsoft.Owin.Security.Interop.Test/Microsoft.Owin.Security.Interop.Test.xproj deleted file mode 100644 index d7f7c9d95..000000000 --- a/test/Microsoft.Owin.Security.Interop.Test/Microsoft.Owin.Security.Interop.Test.xproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - a2b5dc39-68d5-4145-a8cc-6aeab7d33a24 - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Microsoft.Owin.Security.Interop.Test/TicketInteropTests.cs b/test/Microsoft.Owin.Security.Interop.Test/TicketInteropTests.cs index 7b2d261bb..ccff1e936 100644 --- a/test/Microsoft.Owin.Security.Interop.Test/TicketInteropTests.cs +++ b/test/Microsoft.Owin.Security.Interop.Test/TicketInteropTests.cs @@ -1,6 +1,8 @@ // 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; @@ -35,7 +37,7 @@ public void NewSerializerCanReadInteropTicket() var newTicket = newSerializer.Deserialize(bytes); Assert.NotNull(newTicket); - Assert.Equal(1, newTicket.Principal.Identities.Count()); + Assert.Single(newTicket.Principal.Identities); var newIdentity = newTicket.Principal.Identity as ClaimsIdentity; Assert.NotNull(newIdentity); Assert.Equal("scheme", newIdentity.AuthenticationType); @@ -58,7 +60,7 @@ public void InteropSerializerCanReadNewTicket() var expires = DateTime.Today; var issued = new DateTime(1979, 11, 11); - var properties = new AspNetCore.Http.Authentication.AuthenticationProperties(); + var properties = new AspNetCore.Authentication.AuthenticationProperties(); properties.IsPersistent = true; properties.RedirectUri = "/redirect"; properties.Items["key"] = "value"; @@ -87,5 +89,6 @@ public void InteropSerializerCanReadNewTicket() } } } +*/ diff --git a/test/Microsoft.Owin.Security.Interop.Test/project.json b/test/Microsoft.Owin.Security.Interop.Test/project.json deleted file mode 100644 index 43738eba9..000000000 --- a/test/Microsoft.Owin.Security.Interop.Test/project.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "buildOptions": { - "warningsAsErrors": true - }, - "dependencies": { - "dotnet-test-xunit": "2.2.0-*", - "Microsoft.AspNetCore.Authentication.Cookies": "1.2.0-*", - "Microsoft.AspNetCore.TestHost": "1.2.0-*", - "Microsoft.Owin.Security.Cookies": "3.0.1", - "Microsoft.Owin.Security.Interop": "1.2.0-*", - "Microsoft.Owin.Testing": "3.0.1", - "NETStandard.Library": "1.6.2-*", - "xunit": "2.2.0-*" - }, - "frameworks": { - "net451": {} - }, - "testRunner": "xunit" -} \ No newline at end of file diff --git a/version.props b/version.props new file mode 100644 index 000000000..71a78cddd --- /dev/null +++ b/version.props @@ -0,0 +1,12 @@ + + + 3.0.0 + alpha1 + $(VersionPrefix) + $(VersionPrefix)-$(VersionSuffix)-final + t000 + a- + $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-')) + $(VersionSuffix)-$(BuildNumber) + +