├── .gitattributes ├── .gitignore ├── .travis.yml ├── AspNet.Security.OAuth.Extensions.sln ├── NuGet.config ├── README.md ├── build.cmd ├── build.ps1 ├── build.sh ├── build ├── common.props ├── dependencies.props ├── key.snk ├── packages.props ├── repo.props └── version.props ├── korebuild-lock.txt ├── korebuild.json ├── run.cmd ├── run.ps1 ├── run.sh ├── src ├── AspNet.Security.OAuth.Introspection │ ├── AspNet.Security.OAuth.Introspection.csproj │ ├── Events │ │ ├── ApplyChallengeContext.cs │ │ ├── CreateTicketContext.cs │ │ ├── RetrieveTokenContext.cs │ │ ├── SendIntrospectionRequestContext.cs │ │ └── ValidateTokenContext.cs │ ├── OAuthIntrospectionConfiguration.cs │ ├── OAuthIntrospectionConstants.cs │ ├── OAuthIntrospectionDefaults.cs │ ├── OAuthIntrospectionError.cs │ ├── OAuthIntrospectionEvents.cs │ ├── OAuthIntrospectionExtensions.cs │ ├── OAuthIntrospectionFeature.cs │ ├── OAuthIntrospectionHandler.cs │ ├── OAuthIntrospectionHelpers.cs │ ├── OAuthIntrospectionInitializer.cs │ └── OAuthIntrospectionOptions.cs ├── AspNet.Security.OAuth.Validation │ ├── AspNet.Security.OAuth.Validation.csproj │ ├── Events │ │ ├── ApplyChallengeContext.cs │ │ ├── CreateTicketContext.cs │ │ ├── DecryptTokenContext.cs │ │ ├── RetrieveTokenContext.cs │ │ └── ValidateTokenContext.cs │ ├── OAuthValidationConstants.cs │ ├── OAuthValidationDefaults.cs │ ├── OAuthValidationError.cs │ ├── OAuthValidationEvents.cs │ ├── OAuthValidationExtensions.cs │ ├── OAuthValidationFeature.cs │ ├── OAuthValidationHandler.cs │ ├── OAuthValidationHelpers.cs │ ├── OAuthValidationInitializer.cs │ └── OAuthValidationOptions.cs ├── Owin.Security.OAuth.Introspection │ ├── Events │ │ ├── ApplyChallengeContext.cs │ │ ├── CreateTicketContext.cs │ │ ├── RetrieveTokenContext.cs │ │ ├── SendIntrospectionRequestContext.cs │ │ └── ValidateTokenContext.cs │ ├── OAuthIntrospectionConfiguration.cs │ ├── OAuthIntrospectionConstants.cs │ ├── OAuthIntrospectionDefaults.cs │ ├── OAuthIntrospectionError.cs │ ├── OAuthIntrospectionEvents.cs │ ├── OAuthIntrospectionExtensions.cs │ ├── OAuthIntrospectionHandler.cs │ ├── OAuthIntrospectionHelpers.cs │ ├── OAuthIntrospectionMiddleware.cs │ ├── OAuthIntrospectionOptions.cs │ └── Owin.Security.OAuth.Introspection.csproj └── Owin.Security.OAuth.Validation │ ├── Events │ ├── ApplyChallengeContext.cs │ ├── CreateTicketContext.cs │ ├── DecryptTokenContext.cs │ ├── RetrieveTokenContext.cs │ └── ValidateTokenContext.cs │ ├── OAuthValidationConstants.cs │ ├── OAuthValidationDefaults.cs │ ├── OAuthValidationError.cs │ ├── OAuthValidationEvents.cs │ ├── OAuthValidationExtensions.cs │ ├── OAuthValidationHandler.cs │ ├── OAuthValidationHelpers.cs │ ├── OAuthValidationMiddleware.cs │ ├── OAuthValidationOptions.cs │ └── Owin.Security.OAuth.Validation.csproj └── test ├── AspNet.Security.OAuth.Introspection.Tests ├── AspNet.Security.OAuth.Introspection.Tests.csproj ├── OAuthIntrospectionHandlerTests.cs └── OAuthIntrospectionInitializerTests.cs ├── AspNet.Security.OAuth.Validation.Tests ├── AspNet.Security.OAuth.Validation.Tests.csproj └── OAuthValidationHandlerTests.cs ├── Owin.Security.OAuth.Introspection.Tests ├── OAuthIntrospectionHandlerTests.cs ├── OAuthIntrospectionMiddlewareTests.cs └── Owin.Security.OAuth.Introspection.Tests.csproj └── Owin.Security.OAuth.Validation.Tests ├── OAuthValidationHandlerTests.cs ├── OAuthValidationMiddlewareTests.cs └── Owin.Security.OAuth.Validation.Tests.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # VS 14 temporary folder 5 | *.sln.ide/ 6 | target/ 7 | .nuget/ 8 | .vs/ 9 | .build/ 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | project.lock.json 16 | 17 | # Build results 18 | 19 | [Dd]ebug/ 20 | [Rr]elease/ 21 | x64/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 26 | !packages/*/build/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | *_i.c 33 | *_p.c 34 | *.ilk 35 | *.meta 36 | *.obj 37 | *.pch 38 | *.pdb 39 | *.pgc 40 | *.pgd 41 | *.rsp 42 | *.sbr 43 | *.tlb 44 | *.tli 45 | *.tlh 46 | *.tmp 47 | *.tmp_proj 48 | *.log 49 | *.vspscc 50 | *.vssscc 51 | .builds 52 | *.pidb 53 | *.log 54 | *.scc 55 | 56 | # Visual C++ cache files 57 | ipch/ 58 | *.aps 59 | *.ncb 60 | *.opensdf 61 | *.sdf 62 | *.cachefile 63 | 64 | # Visual Studio profiler 65 | *.psess 66 | *.vsp 67 | *.vspx 68 | 69 | # Guidance Automation Toolkit 70 | *.gpState 71 | 72 | # ReSharper is a .NET coding add-in 73 | _ReSharper*/ 74 | *.[Rr]e[Ss]harper 75 | 76 | # TeamCity is a build add-in 77 | _TeamCity* 78 | 79 | # DotCover is a Code Coverage Tool 80 | *.dotCover 81 | 82 | # NCrunch 83 | *.ncrunch* 84 | .*crunch*.local.xml 85 | 86 | # Installshield output folder 87 | [Ee]xpress/ 88 | 89 | # DocProject is a documentation generator add-in 90 | DocProject/buildhelp/ 91 | DocProject/Help/*.HxT 92 | DocProject/Help/*.HxC 93 | DocProject/Help/*.hhc 94 | DocProject/Help/*.hhk 95 | DocProject/Help/*.hhp 96 | DocProject/Help/Html2 97 | DocProject/Help/html 98 | 99 | # Click-Once directory 100 | publish/ 101 | 102 | # Publish Web Output 103 | *.Publish.xml 104 | 105 | # NuGet Packages Directory 106 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 107 | packages/ 108 | 109 | # Windows Azure Build Output 110 | csx 111 | *.build.csdef 112 | 113 | # Windows Store app package directory 114 | AppPackages/ 115 | 116 | # Others 117 | sql/ 118 | *.Cache 119 | ClientBin/ 120 | [Ss]tyle[Cc]op.* 121 | ~$* 122 | *~ 123 | *.dbmdl 124 | *.[Pp]ublish.xml 125 | *.publishsettings 126 | 127 | # RIA/Silverlight projects 128 | Generated_Code/ 129 | 130 | # Backup & report files from converting an old project file to a newer 131 | # Visual Studio version. Backup files are not needed, because we have git ;-) 132 | _UpgradeReport_Files/ 133 | Backup*/ 134 | UpgradeLog*.XML 135 | UpgradeLog*.htm 136 | 137 | # SQL Server files 138 | *.mdf 139 | *.ldf 140 | 141 | 142 | #LightSwitch generated files 143 | GeneratedArtifacts/ 144 | _Pvt_Extensions/ 145 | ModelManifest.xml 146 | 147 | # ========================= 148 | # Windows detritus 149 | # ========================= 150 | 151 | # Windows image file caches 152 | Thumbs.db 153 | ehthumbs.db 154 | 155 | # Folder config file 156 | Desktop.ini 157 | 158 | # Recycle Bin used on file shares 159 | $RECYCLE.BIN/ 160 | 161 | # Mac desktop service store files 162 | .DS_Store 163 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | sudo: false 3 | dist: trusty 4 | addons: 5 | apt: 6 | packages: 7 | - gettext 8 | - libcurl4-openssl-dev 9 | - libicu-dev 10 | - libssl-dev 11 | - libunwind8 12 | - zlib1g 13 | env: 14 | global: 15 | - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true 16 | - DOTNET_CLI_TELEMETRY_OPTOUT: 1 17 | mono: none 18 | os: 19 | - linux 20 | - osx 21 | osx_image: xcode8.2 22 | before_install: 23 | - 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 24 | script: 25 | - ./build.sh -------------------------------------------------------------------------------- /AspNet.Security.OAuth.Extensions.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26228.4 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{2CFA7432-2FA7-4CF3-87DC-217C1363E11D}" 7 | ProjectSection(SolutionItems) = preProject 8 | build\common.props = build\common.props 9 | build\dependencies.props = build\dependencies.props 10 | build\key.snk = build\key.snk 11 | build\packages.props = build\packages.props 12 | build\repo.props = build\repo.props 13 | build\version.props = build\version.props 14 | EndProjectSection 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{7AADF737-9B13-4E5C-8F32-8BF21429E093}" 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{2B1B08E0-E9A3-40C0-B200-DE09952AF0E7}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNet.Security.OAuth.Introspection", "src\AspNet.Security.OAuth.Introspection\AspNet.Security.OAuth.Introspection.csproj", "{A8569260-142C-427A-8B14-A8DF56CC15B7}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNet.Security.OAuth.Introspection.Tests", "test\AspNet.Security.OAuth.Introspection.Tests\AspNet.Security.OAuth.Introspection.Tests.csproj", "{4070DC46-0FD5-4ADD-95B3-E9908AD82407}" 23 | EndProject 24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNet.Security.OAuth.Validation", "src\AspNet.Security.OAuth.Validation\AspNet.Security.OAuth.Validation.csproj", "{043FD757-9C69-4A68-93BF-EAD2672BBD78}" 25 | EndProject 26 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNet.Security.OAuth.Validation.Tests", "test\AspNet.Security.OAuth.Validation.Tests\AspNet.Security.OAuth.Validation.Tests.csproj", "{FC99E58D-86BC-4EAD-B282-C9F1491CCF96}" 27 | EndProject 28 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Owin.Security.OAuth.Introspection", "src\Owin.Security.OAuth.Introspection\Owin.Security.OAuth.Introspection.csproj", "{F9031F69-74BF-4321-88D5-2A606D3DA4E4}" 29 | EndProject 30 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Owin.Security.OAuth.Introspection.Tests", "test\Owin.Security.OAuth.Introspection.Tests\Owin.Security.OAuth.Introspection.Tests.csproj", "{A6B08CB3-0B3E-444D-BCF1-E9E41CEEC984}" 31 | EndProject 32 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Owin.Security.OAuth.Validation", "src\Owin.Security.OAuth.Validation\Owin.Security.OAuth.Validation.csproj", "{719AF040-773B-4DA5-B53E-28B26D1121FF}" 33 | EndProject 34 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Owin.Security.OAuth.Validation.Tests", "test\Owin.Security.OAuth.Validation.Tests\Owin.Security.OAuth.Validation.Tests.csproj", "{6DC60DCF-B34B-4F14-9E73-BE466059A9B2}" 35 | EndProject 36 | Global 37 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 38 | Debug|Any CPU = Debug|Any CPU 39 | Release|Any CPU = Release|Any CPU 40 | EndGlobalSection 41 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 42 | {A8569260-142C-427A-8B14-A8DF56CC15B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {A8569260-142C-427A-8B14-A8DF56CC15B7}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {A8569260-142C-427A-8B14-A8DF56CC15B7}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {A8569260-142C-427A-8B14-A8DF56CC15B7}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {4070DC46-0FD5-4ADD-95B3-E9908AD82407}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {4070DC46-0FD5-4ADD-95B3-E9908AD82407}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {4070DC46-0FD5-4ADD-95B3-E9908AD82407}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {4070DC46-0FD5-4ADD-95B3-E9908AD82407}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {043FD757-9C69-4A68-93BF-EAD2672BBD78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {043FD757-9C69-4A68-93BF-EAD2672BBD78}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {043FD757-9C69-4A68-93BF-EAD2672BBD78}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {043FD757-9C69-4A68-93BF-EAD2672BBD78}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {FC99E58D-86BC-4EAD-B282-C9F1491CCF96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {FC99E58D-86BC-4EAD-B282-C9F1491CCF96}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {FC99E58D-86BC-4EAD-B282-C9F1491CCF96}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {FC99E58D-86BC-4EAD-B282-C9F1491CCF96}.Release|Any CPU.Build.0 = Release|Any CPU 58 | {F9031F69-74BF-4321-88D5-2A606D3DA4E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 59 | {F9031F69-74BF-4321-88D5-2A606D3DA4E4}.Debug|Any CPU.Build.0 = Debug|Any CPU 60 | {F9031F69-74BF-4321-88D5-2A606D3DA4E4}.Release|Any CPU.ActiveCfg = Release|Any CPU 61 | {F9031F69-74BF-4321-88D5-2A606D3DA4E4}.Release|Any CPU.Build.0 = Release|Any CPU 62 | {A6B08CB3-0B3E-444D-BCF1-E9E41CEEC984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 63 | {A6B08CB3-0B3E-444D-BCF1-E9E41CEEC984}.Debug|Any CPU.Build.0 = Debug|Any CPU 64 | {A6B08CB3-0B3E-444D-BCF1-E9E41CEEC984}.Release|Any CPU.ActiveCfg = Release|Any CPU 65 | {A6B08CB3-0B3E-444D-BCF1-E9E41CEEC984}.Release|Any CPU.Build.0 = Release|Any CPU 66 | {719AF040-773B-4DA5-B53E-28B26D1121FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 67 | {719AF040-773B-4DA5-B53E-28B26D1121FF}.Debug|Any CPU.Build.0 = Debug|Any CPU 68 | {719AF040-773B-4DA5-B53E-28B26D1121FF}.Release|Any CPU.ActiveCfg = Release|Any CPU 69 | {719AF040-773B-4DA5-B53E-28B26D1121FF}.Release|Any CPU.Build.0 = Release|Any CPU 70 | {6DC60DCF-B34B-4F14-9E73-BE466059A9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 71 | {6DC60DCF-B34B-4F14-9E73-BE466059A9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU 72 | {6DC60DCF-B34B-4F14-9E73-BE466059A9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU 73 | {6DC60DCF-B34B-4F14-9E73-BE466059A9B2}.Release|Any CPU.Build.0 = Release|Any CPU 74 | EndGlobalSection 75 | GlobalSection(SolutionProperties) = preSolution 76 | HideSolutionNode = FALSE 77 | EndGlobalSection 78 | GlobalSection(NestedProjects) = preSolution 79 | {A8569260-142C-427A-8B14-A8DF56CC15B7} = {7AADF737-9B13-4E5C-8F32-8BF21429E093} 80 | {4070DC46-0FD5-4ADD-95B3-E9908AD82407} = {2B1B08E0-E9A3-40C0-B200-DE09952AF0E7} 81 | {043FD757-9C69-4A68-93BF-EAD2672BBD78} = {7AADF737-9B13-4E5C-8F32-8BF21429E093} 82 | {FC99E58D-86BC-4EAD-B282-C9F1491CCF96} = {2B1B08E0-E9A3-40C0-B200-DE09952AF0E7} 83 | {F9031F69-74BF-4321-88D5-2A606D3DA4E4} = {7AADF737-9B13-4E5C-8F32-8BF21429E093} 84 | {A6B08CB3-0B3E-444D-BCF1-E9E41CEEC984} = {2B1B08E0-E9A3-40C0-B200-DE09952AF0E7} 85 | {719AF040-773B-4DA5-B53E-28B26D1121FF} = {7AADF737-9B13-4E5C-8F32-8BF21429E093} 86 | {6DC60DCF-B34B-4F14-9E73-BE466059A9B2} = {2B1B08E0-E9A3-40C0-B200-DE09952AF0E7} 87 | EndGlobalSection 88 | GlobalSection(ExtensibilityGlobals) = postSolution 89 | SolutionGuid = {7DD610CB-5D2D-4AEB-B5D3-4DEEB694AA36} 90 | EndGlobalSection 91 | EndGlobal 92 | -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AspNet.Security.OAuth.Extensions 2 | ================================ 3 | 4 | > :warning: **This project has been merged into OpenIddict. For more information, read [Introducing OpenIddict 3.0 beta1](https://kevinchalet.com/2020/06/11/introducing-openiddict-3-0-beta1/)**. 5 | 6 | **AspNet.Security.OAuth.Extensions** is a collection of **token validation middleware** for ASP.NET Core 1.0 and OWIN/Katana. 7 | 8 | **The latest nightly builds can be found on [MyGet](https://www.myget.org/gallery/aspnet-contrib)**. 9 | 10 | [![Build status](https://ci.appveyor.com/api/projects/status/aa7t5nfxpiri1e85/branch/release?svg=true)](https://ci.appveyor.com/project/aspnet-contrib/aspnet-security-oauth-extensions/branch/release) 11 | [![Build status](https://travis-ci.org/aspnet-contrib/AspNet.Security.OAuth.Extensions.svg?branch=release)](https://travis-ci.org/aspnet-contrib/AspNet.Security.OAuth.Extensions) 12 | 13 | ## Get started 14 | 15 | ```csharp 16 | app.UseOAuthValidation(options => 17 | { 18 | options.Audiences.Add("resource_server"); 19 | }); 20 | ``` 21 | 22 | ```csharp 23 | app.UseOAuthIntrospection(options => 24 | { 25 | options.Authority = new Uri("https://openid.yourapp.com/"); 26 | options.Audiences.Add("resource_server"); 27 | options.ClientId = "resource_server"; 28 | options.ClientSecret = "875sqd4s5d748z78z7ds1ff8zz8814ff88ed8ea4z4zzd"; 29 | }); 30 | ``` 31 | 32 | ## Support 33 | 34 | **Need help or wanna share your thoughts?** Don't hesitate to join us on Gitter or ask your question on StackOverflow: 35 | 36 | - **Gitter: [https://gitter.im/aspnet-contrib/AspNet.Security.OAuth.Extensions](https://gitter.im/aspnet-contrib/AspNet.Security.OAuth.Extensions)** 37 | - **StackOverflow: [https://stackoverflow.com/questions/tagged/aspnet-contrib](https://stackoverflow.com/questions/tagged/aspnet-contrib)** 38 | 39 | ## Contributors 40 | 41 | **AspNet.Security.OAuth.Extensions** is actively maintained by **[Kévin Chalet](https://github.com/kevinchalet)**. Contributions are welcome and can be submitted using pull requests. 42 | 43 | ## License 44 | 45 | This project is licensed under the **Apache License**. This means that you can use, modify and distribute it freely. See [http://www.apache.org/licenses/LICENSE-2.0.html](http://www.apache.org/licenses/LICENSE-2.0.html) for more details. -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE" 3 | -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | 3 | function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries) 4 | { 5 | while($true) 6 | { 7 | try 8 | { 9 | Invoke-WebRequest $url -OutFile $downloadLocation 10 | break 11 | } 12 | catch 13 | { 14 | $exceptionMessage = $_.Exception.Message 15 | Write-Host "Failed to download '$url': $exceptionMessage" 16 | if ($retries -gt 0) { 17 | $retries-- 18 | Write-Host "Waiting 10 seconds before retrying. Retries left: $retries" 19 | Start-Sleep -Seconds 10 20 | 21 | } 22 | else 23 | { 24 | $exception = $_.Exception 25 | throw $exception 26 | } 27 | } 28 | } 29 | } 30 | 31 | cd $PSScriptRoot 32 | 33 | $repoFolder = $PSScriptRoot 34 | $env:REPO_FOLDER = $repoFolder 35 | 36 | $koreBuildZip="https://github.com/aspnet/KoreBuild/archive/dev.zip" 37 | if ($env:KOREBUILD_ZIP) 38 | { 39 | $koreBuildZip=$env:KOREBUILD_ZIP 40 | } 41 | 42 | $buildFolder = ".build" 43 | $buildFile="$buildFolder\KoreBuild.ps1" 44 | 45 | if (!(Test-Path $buildFolder)) { 46 | Write-Host "Downloading KoreBuild from $koreBuildZip" 47 | 48 | $tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid() 49 | New-Item -Path "$tempFolder" -Type directory | Out-Null 50 | 51 | $localZipFile="$tempFolder\korebuild.zip" 52 | 53 | DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6 54 | 55 | Add-Type -AssemblyName System.IO.Compression.FileSystem 56 | [System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder) 57 | 58 | New-Item -Path "$buildFolder" -Type directory | Out-Null 59 | copy-item "$tempFolder\**\build\*" $buildFolder -Recurse 60 | 61 | # Cleanup 62 | if (Test-Path $tempFolder) { 63 | Remove-Item -Recurse -Force $tempFolder 64 | } 65 | } 66 | 67 | &"$buildFile" @args 68 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 5 | 6 | # Call "sync" between "chmod" and execution to prevent "text file busy" error in Docker (aufs) 7 | chmod +x "$DIR/run.sh"; sync 8 | "$DIR/run.sh" default-build "$@" 9 | -------------------------------------------------------------------------------- /build/common.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | latest 8 | $(NoWarn);CS1591 9 | true 10 | true 11 | portable 12 | 13 | 14 | 15 | 16 | <_GenerateBindingRedirectsIntermediateAppConfig>$(IntermediateOutputPath)$(TargetFileName).config 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /build/dependencies.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2.0.0 5 | 4.4.0 6 | 5.2.0-preview1-408290725 7 | 2.1.4 8 | 10.3.0 9 | 10.0.2 10 | 4.7.63 11 | 4.3.2 12 | 2.0.0 13 | 2.0.0 14 | 4.0.0-alpha1 15 | 2.0.0 16 | 15.3.0 17 | 2.3.1 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /build/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aspnet-contrib/AspNet.Security.OAuth.Extensions/a413b870fa15ade0fd0c1a215a42bbe5871de223/build/key.snk -------------------------------------------------------------------------------- /build/packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | true 7 | $(MSBuildThisFileDirectory)key.snk 8 | true 9 | true 10 | true 11 | true 12 | 13 | 14 | 15 | aspnet-contrib 16 | https://avatars3.githubusercontent.com/u/7998081?s=64 17 | https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions 18 | http://www.apache.org/licenses/LICENSE-2.0.html 19 | git 20 | git://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /build/repo.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /build/version.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2.0.0 5 | rtm 6 | $(VersionSuffix)-$(BuildNumber) 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /korebuild-lock.txt: -------------------------------------------------------------------------------- 1 | version:2.1.0-rtm-15783 2 | commithash:5fc2b2f607f542a2ffde11c19825e786fc1a3774 3 | -------------------------------------------------------------------------------- /korebuild.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json", 3 | "channel": "release/2.1" 4 | } 5 | -------------------------------------------------------------------------------- /run.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE" 3 | -------------------------------------------------------------------------------- /run.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env powershell 2 | #requires -version 4 3 | 4 | <# 5 | .SYNOPSIS 6 | Executes KoreBuild commands. 7 | 8 | .DESCRIPTION 9 | Downloads korebuild if required. Then executes the KoreBuild command. To see available commands, execute with `-Command help`. 10 | 11 | .PARAMETER Command 12 | The KoreBuild command to run. 13 | 14 | .PARAMETER Path 15 | The folder to build. Defaults to the folder containing this script. 16 | 17 | .PARAMETER Channel 18 | The channel of KoreBuild to download. Overrides the value from the config file. 19 | 20 | .PARAMETER DotNetHome 21 | The directory where .NET Core tools will be stored. 22 | 23 | .PARAMETER ToolsSource 24 | The base url where build tools can be downloaded. Overrides the value from the config file. 25 | 26 | .PARAMETER Update 27 | Updates KoreBuild to the latest version even if a lock file is present. 28 | 29 | .PARAMETER ConfigFile 30 | The path to the configuration file that stores values. Defaults to korebuild.json. 31 | 32 | .PARAMETER ToolsSourceSuffix 33 | The Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores. 34 | 35 | .PARAMETER Arguments 36 | Arguments to be passed to the command 37 | 38 | .NOTES 39 | This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be. 40 | When the lockfile is not present, KoreBuild will create one using latest available version from $Channel. 41 | 42 | 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 43 | in the file are overridden by command line parameters. 44 | 45 | .EXAMPLE 46 | Example config file: 47 | ```json 48 | { 49 | "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json", 50 | "channel": "dev", 51 | "toolsSource": "https://aspnetcore.blob.core.windows.net/buildtools" 52 | } 53 | ``` 54 | #> 55 | [CmdletBinding(PositionalBinding = $false)] 56 | param( 57 | [Parameter(Mandatory = $true, Position = 0)] 58 | [string]$Command, 59 | [string]$Path = $PSScriptRoot, 60 | [Alias('c')] 61 | [string]$Channel, 62 | [Alias('d')] 63 | [string]$DotNetHome, 64 | [Alias('s')] 65 | [string]$ToolsSource, 66 | [Alias('u')] 67 | [switch]$Update, 68 | [string]$ConfigFile, 69 | [string]$ToolsSourceSuffix, 70 | [Parameter(ValueFromRemainingArguments = $true)] 71 | [string[]]$Arguments 72 | ) 73 | 74 | Set-StrictMode -Version 2 75 | $ErrorActionPreference = 'Stop' 76 | 77 | # 78 | # Functions 79 | # 80 | 81 | function Get-KoreBuild { 82 | 83 | $lockFile = Join-Path $Path 'korebuild-lock.txt' 84 | 85 | if (!(Test-Path $lockFile) -or $Update) { 86 | Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile $ToolsSourceSuffix 87 | } 88 | 89 | $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1 90 | if (!$version) { 91 | Write-Error "Failed to parse version from $lockFile. Expected a line that begins with 'version:'" 92 | } 93 | $version = $version.TrimStart('version:').Trim() 94 | $korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version) 95 | 96 | if (!(Test-Path $korebuildPath)) { 97 | Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version" 98 | New-Item -ItemType Directory -Path $korebuildPath | Out-Null 99 | $remotePath = "$ToolsSource/korebuild/artifacts/$version/korebuild.$version.zip" 100 | 101 | try { 102 | $tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip" 103 | Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix 104 | if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) { 105 | # Use built-in commands where possible as they are cross-plat compatible 106 | Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath 107 | } 108 | else { 109 | # Fallback to old approach for old installations of PowerShell 110 | Add-Type -AssemblyName System.IO.Compression.FileSystem 111 | [System.IO.Compression.ZipFile]::ExtractToDirectory($tmpfile, $korebuildPath) 112 | } 113 | } 114 | catch { 115 | Remove-Item -Recurse -Force $korebuildPath -ErrorAction Ignore 116 | throw 117 | } 118 | finally { 119 | Remove-Item $tmpfile -ErrorAction Ignore 120 | } 121 | } 122 | 123 | return $korebuildPath 124 | } 125 | 126 | function Join-Paths([string]$path, [string[]]$childPaths) { 127 | $childPaths | ForEach-Object { $path = Join-Path $path $_ } 128 | return $path 129 | } 130 | 131 | function Get-RemoteFile([string]$RemotePath, [string]$LocalPath, [string]$RemoteSuffix) { 132 | if ($RemotePath -notlike 'http*') { 133 | Copy-Item $RemotePath $LocalPath 134 | return 135 | } 136 | 137 | $retries = 10 138 | while ($retries -gt 0) { 139 | $retries -= 1 140 | try { 141 | Invoke-WebRequest -UseBasicParsing -Uri $($RemotePath + $RemoteSuffix) -OutFile $LocalPath 142 | return 143 | } 144 | catch { 145 | Write-Verbose "Request failed. $retries retries remaining" 146 | } 147 | } 148 | 149 | Write-Error "Download failed: '$RemotePath'." 150 | } 151 | 152 | # 153 | # Main 154 | # 155 | 156 | # Load configuration or set defaults 157 | 158 | $Path = Resolve-Path $Path 159 | if (!$ConfigFile) { $ConfigFile = Join-Path $Path 'korebuild.json' } 160 | 161 | if (Test-Path $ConfigFile) { 162 | try { 163 | $config = Get-Content -Raw -Encoding UTF8 -Path $ConfigFile | ConvertFrom-Json 164 | if ($config) { 165 | if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel } 166 | if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource} 167 | } 168 | } 169 | catch { 170 | Write-Warning "$ConfigFile could not be read. Its settings will be ignored." 171 | Write-Warning $Error[0] 172 | } 173 | } 174 | 175 | if (!$DotNetHome) { 176 | $DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } ` 177 | elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} ` 178 | elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}` 179 | else { Join-Path $PSScriptRoot '.dotnet'} 180 | } 181 | 182 | if (!$Channel) { $Channel = 'dev' } 183 | if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' } 184 | 185 | # Execute 186 | 187 | $korebuildPath = Get-KoreBuild 188 | Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1') 189 | 190 | try { 191 | Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile 192 | Invoke-KoreBuildCommand $Command @Arguments 193 | } 194 | finally { 195 | Remove-Module 'KoreBuild' -ErrorAction Ignore 196 | } 197 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | # 6 | # variables 7 | # 8 | 9 | RESET="\033[0m" 10 | RED="\033[0;31m" 11 | YELLOW="\033[0;33m" 12 | MAGENTA="\033[0;95m" 13 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 14 | [ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" 15 | verbose=false 16 | update=false 17 | repo_path="$DIR" 18 | channel='' 19 | tools_source='' 20 | tools_source_suffix='' 21 | 22 | # 23 | # Functions 24 | # 25 | __usage() { 26 | echo "Usage: $(basename "${BASH_SOURCE[0]}") command [options] [[--] ...]" 27 | echo "" 28 | echo "Arguments:" 29 | echo " command The command to be run." 30 | echo " ... Arguments passed to the command. Variable number of arguments allowed." 31 | echo "" 32 | echo "Options:" 33 | echo " --verbose Show verbose output." 34 | echo " -c|--channel The channel of KoreBuild to download. Overrides the value from the config file.." 35 | echo " --config-file The path to the configuration file that stores values. Defaults to korebuild.json." 36 | echo " -d|--dotnet-home The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet." 37 | echo " --path The directory to build. Defaults to the directory containing the script." 38 | echo " -s|--tools-source|-ToolsSource The base url where build tools can be downloaded. Overrides the value from the config file." 39 | echo " --tools-source-suffix|-ToolsSourceSuffix The suffix to append to tools-source. Useful for query strings." 40 | echo " -u|--update Update to the latest KoreBuild even if the lock file is present." 41 | echo "" 42 | echo "Description:" 43 | 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." 44 | echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel." 45 | 46 | if [[ "${1:-}" != '--no-exit' ]]; then 47 | exit 2 48 | fi 49 | } 50 | 51 | get_korebuild() { 52 | local version 53 | local lock_file="$repo_path/korebuild-lock.txt" 54 | if [ ! -f "$lock_file" ] || [ "$update" = true ]; then 55 | __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lock_file" "$tools_source_suffix" 56 | fi 57 | version="$(grep 'version:*' -m 1 "$lock_file")" 58 | if [[ "$version" == '' ]]; then 59 | __error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'" 60 | return 1 61 | fi 62 | version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" 63 | local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" 64 | 65 | { 66 | if [ ! -d "$korebuild_path" ]; then 67 | mkdir -p "$korebuild_path" 68 | local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" 69 | tmpfile="$(mktemp)" 70 | echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" 71 | if __get_remote_file "$remote_path" "$tmpfile" "$tools_source_suffix"; then 72 | unzip -q -d "$korebuild_path" "$tmpfile" 73 | fi 74 | rm "$tmpfile" || true 75 | fi 76 | 77 | source "$korebuild_path/KoreBuild.sh" 78 | } || { 79 | if [ -d "$korebuild_path" ]; then 80 | echo "Cleaning up after failed installation" 81 | rm -rf "$korebuild_path" || true 82 | fi 83 | return 1 84 | } 85 | } 86 | 87 | __error() { 88 | echo -e "${RED}error: $*${RESET}" 1>&2 89 | } 90 | 91 | __warn() { 92 | echo -e "${YELLOW}warning: $*${RESET}" 93 | } 94 | 95 | __machine_has() { 96 | hash "$1" > /dev/null 2>&1 97 | return $? 98 | } 99 | 100 | __get_remote_file() { 101 | local remote_path=$1 102 | local local_path=$2 103 | local remote_path_suffix=$3 104 | 105 | if [[ "$remote_path" != 'http'* ]]; then 106 | cp "$remote_path" "$local_path" 107 | return 0 108 | fi 109 | 110 | local failed=false 111 | if __machine_has wget; then 112 | wget --tries 10 --quiet -O "$local_path" "${remote_path}${remote_path_suffix}" || failed=true 113 | else 114 | failed=true 115 | fi 116 | 117 | if [ "$failed" = true ] && __machine_has curl; then 118 | failed=false 119 | curl --retry 10 -sSL -f --create-dirs -o "$local_path" "${remote_path}${remote_path_suffix}" || failed=true 120 | fi 121 | 122 | if [ "$failed" = true ]; then 123 | __error "Download failed: $remote_path" 1>&2 124 | return 1 125 | fi 126 | } 127 | 128 | # 129 | # main 130 | # 131 | 132 | command="${1:-}" 133 | shift 134 | 135 | while [[ $# -gt 0 ]]; do 136 | case $1 in 137 | -\?|-h|--help) 138 | __usage --no-exit 139 | exit 0 140 | ;; 141 | -c|--channel|-Channel) 142 | shift 143 | channel="${1:-}" 144 | [ -z "$channel" ] && __usage 145 | ;; 146 | --config-file|-ConfigFile) 147 | shift 148 | config_file="${1:-}" 149 | [ -z "$config_file" ] && __usage 150 | if [ ! -f "$config_file" ]; then 151 | __error "Invalid value for --config-file. $config_file does not exist." 152 | exit 1 153 | fi 154 | ;; 155 | -d|--dotnet-home|-DotNetHome) 156 | shift 157 | DOTNET_HOME="${1:-}" 158 | [ -z "$DOTNET_HOME" ] && __usage 159 | ;; 160 | --path|-Path) 161 | shift 162 | repo_path="${1:-}" 163 | [ -z "$repo_path" ] && __usage 164 | ;; 165 | -s|--tools-source|-ToolsSource) 166 | shift 167 | tools_source="${1:-}" 168 | [ -z "$tools_source" ] && __usage 169 | ;; 170 | --tools-source-suffix|-ToolsSourceSuffix) 171 | shift 172 | tools_source_suffix="${1:-}" 173 | [ -z "$tools_source_suffix" ] && __usage 174 | ;; 175 | -u|--update|-Update) 176 | update=true 177 | ;; 178 | --verbose|-Verbose) 179 | verbose=true 180 | ;; 181 | --) 182 | shift 183 | break 184 | ;; 185 | *) 186 | break 187 | ;; 188 | esac 189 | shift 190 | done 191 | 192 | if ! __machine_has unzip; then 193 | __error 'Missing required command: unzip' 194 | exit 1 195 | fi 196 | 197 | if ! __machine_has curl && ! __machine_has wget; then 198 | __error 'Missing required command. Either wget or curl is required.' 199 | exit 1 200 | fi 201 | 202 | [ -z "${config_file:-}" ] && config_file="$repo_path/korebuild.json" 203 | if [ -f "$config_file" ]; then 204 | if __machine_has jq ; then 205 | if jq '.' "$config_file" >/dev/null ; then 206 | config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" 207 | config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" 208 | else 209 | __warn "$config_file is invalid JSON. Its settings will be ignored." 210 | fi 211 | elif __machine_has python ; then 212 | if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then 213 | 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 '')")" 214 | 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 '')")" 215 | else 216 | __warn "$config_file is invalid JSON. Its settings will be ignored." 217 | fi 218 | else 219 | __warn 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.' 220 | fi 221 | 222 | [ ! -z "${config_channel:-}" ] && channel="$config_channel" 223 | [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source" 224 | fi 225 | 226 | [ -z "$channel" ] && channel='dev' 227 | [ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools' 228 | 229 | get_korebuild 230 | set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" 231 | invoke_korebuild_command "$command" "$@" 232 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/AspNet.Security.OAuth.Introspection.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | netstandard2.0 7 | 8 | 9 | 10 | OAuth2 introspection middleware for ASP.NET Core. 11 | Kévin Chalet 12 | aspnetcore;authentication;jwt;openidconnect;security 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/Events/ApplyChallengeContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.AspNetCore.Authentication; 9 | using Microsoft.AspNetCore.Http; 10 | 11 | namespace AspNet.Security.OAuth.Introspection 12 | { 13 | /// 14 | /// Allows customization of the challenge process. 15 | /// 16 | public class ApplyChallengeContext : PropertiesContext 17 | { 18 | public ApplyChallengeContext( 19 | [NotNull] HttpContext context, 20 | [NotNull] AuthenticationScheme scheme, 21 | [NotNull] OAuthIntrospectionOptions options, 22 | [NotNull] AuthenticationProperties properties) 23 | : base(context, scheme, options, properties) 24 | { 25 | } 26 | 27 | /// 28 | /// Gets or sets the "error" value returned to the caller as part 29 | /// of the WWW-Authenticate header. This property may be null when 30 | /// is set to false. 31 | /// 32 | public string Error { get; set; } 33 | 34 | /// 35 | /// Gets or sets the "error_description" value returned to the caller as part 36 | /// of the WWW-Authenticate header. This property may be null when 37 | /// is set to false. 38 | /// 39 | public string ErrorDescription { get; set; } 40 | 41 | /// 42 | /// Gets or sets the "error_uri" value returned to the caller as part of the 43 | /// WWW-Authenticate header. This property is always null unless explicitly set. 44 | /// 45 | public string ErrorUri { get; set; } 46 | 47 | /// 48 | /// Gets or sets the "realm" value returned to 49 | /// the caller as part of the WWW-Authenticate header. 50 | /// 51 | public string Realm { get; set; } 52 | 53 | /// 54 | /// Gets or sets the "scope" value returned to 55 | /// the caller as part of the WWW-Authenticate header. 56 | /// 57 | public string Scope { get; set; } 58 | 59 | /// 60 | /// Gets a boolean indicating if the operation was handled from user code. 61 | /// 62 | public bool Handled { get; private set; } 63 | 64 | /// 65 | /// Marks the operation as handled to prevent the default logic from being applied. 66 | /// 67 | public void HandleResponse() => Handled = true; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/Events/CreateTicketContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System.Security.Claims; 8 | using JetBrains.Annotations; 9 | using Microsoft.AspNetCore.Authentication; 10 | using Microsoft.AspNetCore.Http; 11 | using Newtonsoft.Json.Linq; 12 | 13 | namespace AspNet.Security.OAuth.Introspection 14 | { 15 | /// 16 | /// Allows interception of the AuthenticationTicket creation process. 17 | /// 18 | public class CreateTicketContext : ResultContext 19 | { 20 | public CreateTicketContext( 21 | [NotNull] HttpContext context, 22 | [NotNull] AuthenticationScheme scheme, 23 | [NotNull] OAuthIntrospectionOptions options, 24 | [NotNull] AuthenticationTicket ticket, 25 | [NotNull] JObject payload) 26 | : base(context, scheme, options) 27 | { 28 | Principal = ticket.Principal; 29 | Properties = ticket.Properties; 30 | Payload = payload; 31 | } 32 | 33 | /// 34 | /// Gets the identity containing the user claims. 35 | /// 36 | public ClaimsIdentity Identity => Principal?.Identity as ClaimsIdentity; 37 | 38 | /// 39 | /// Gets the payload extracted from the introspection response. 40 | /// 41 | public JObject Payload { get; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/Events/RetrieveTokenContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.AspNetCore.Authentication; 9 | using Microsoft.AspNetCore.Http; 10 | 11 | namespace AspNet.Security.OAuth.Introspection 12 | { 13 | /// 14 | /// Allows custom parsing of access tokens from requests. 15 | /// 16 | public class RetrieveTokenContext : ResultContext 17 | { 18 | public RetrieveTokenContext( 19 | [NotNull] HttpContext context, 20 | [NotNull] AuthenticationScheme scheme, 21 | [NotNull] OAuthIntrospectionOptions options) 22 | : base(context, scheme, options) 23 | { 24 | } 25 | 26 | /// 27 | /// Gets or sets the access token. 28 | /// 29 | public string Token { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/Events/SendIntrospectionRequestContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System.Net.Http; 8 | using JetBrains.Annotations; 9 | using Microsoft.AspNetCore.Authentication; 10 | using Microsoft.AspNetCore.Http; 11 | 12 | namespace AspNet.Security.OAuth.Introspection 13 | { 14 | /// 15 | /// Allows for custom handling of the call to the Authorization Server's Introspection endpoint. 16 | /// 17 | public class SendIntrospectionRequestContext : BaseContext 18 | { 19 | public SendIntrospectionRequestContext( 20 | [NotNull] HttpContext context, 21 | [NotNull] AuthenticationScheme scheme, 22 | [NotNull] OAuthIntrospectionOptions options, 23 | [NotNull] HttpRequestMessage request, 24 | [NotNull] string token) 25 | : base(context, scheme, options) 26 | { 27 | Request = request; 28 | Token = token; 29 | } 30 | 31 | /// 32 | /// An for use by the application to call the authorization server. 33 | /// 34 | public HttpClient Client => Options.HttpClient; 35 | 36 | /// 37 | /// Gets the HTTP request sent to the introspection endpoint. 38 | /// 39 | public new HttpRequestMessage Request { get; } 40 | 41 | /// 42 | /// Gets or sets the HTTP response returned by the introspection endpoint. 43 | /// 44 | public new HttpResponseMessage Response { get; set; } 45 | 46 | /// 47 | /// The access token parsed from the client request. 48 | /// 49 | public string Token { get; } 50 | 51 | /// 52 | /// Gets a boolean indicating if the operation was handled from user code. 53 | /// 54 | public bool Handled { get; private set; } 55 | 56 | /// 57 | /// Marks the operation as handled to prevent the default logic from being applied. 58 | /// 59 | public void HandleResponse() => Handled = true; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/Events/ValidateTokenContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.AspNetCore.Authentication; 9 | using Microsoft.AspNetCore.Http; 10 | 11 | namespace AspNet.Security.OAuth.Introspection 12 | { 13 | /// 14 | /// Allows customization of the token validation logic. 15 | /// 16 | public class ValidateTokenContext : ResultContext 17 | { 18 | public ValidateTokenContext( 19 | [NotNull] HttpContext context, 20 | [NotNull] AuthenticationScheme scheme, 21 | [NotNull] OAuthIntrospectionOptions options, 22 | [NotNull] AuthenticationTicket ticket) 23 | : base(context, scheme, options) 24 | { 25 | Principal = ticket.Principal; 26 | Properties = ticket.Properties; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/OAuthIntrospectionConfiguration.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | using JetBrains.Annotations; 12 | using Microsoft.IdentityModel.Protocols; 13 | using Microsoft.IdentityModel.Protocols.OpenIdConnect; 14 | using Newtonsoft.Json; 15 | 16 | namespace AspNet.Security.OAuth.Introspection 17 | { 18 | /// 19 | /// Represents an OAuth2 introspection configuration. 20 | /// 21 | [JsonObject(MemberSerialization = MemberSerialization.OptIn)] 22 | public class OAuthIntrospectionConfiguration : OpenIdConnectConfiguration 23 | { 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | public OAuthIntrospectionConfiguration() 28 | : base() { } 29 | 30 | /// 31 | /// Initializes a new instance of the class. 32 | /// 33 | /// The JSON payload used to initialize the current instance. 34 | public OAuthIntrospectionConfiguration([NotNull] string json) 35 | : base(json) { } 36 | 37 | /// 38 | /// Gets or sets the introspection endpoint address. 39 | /// 40 | [JsonProperty( 41 | DefaultValueHandling = DefaultValueHandling.Ignore, 42 | NullValueHandling = NullValueHandling.Ignore, 43 | PropertyName = OAuthIntrospectionConstants.Metadata.IntrospectionEndpoint)] 44 | public string IntrospectionEndpoint { get; set; } 45 | 46 | /// 47 | /// Gets the list of authentication methods supported by the introspection endpoint. 48 | /// 49 | [JsonProperty( 50 | DefaultValueHandling = DefaultValueHandling.Ignore, 51 | NullValueHandling = NullValueHandling.Ignore, 52 | PropertyName = OAuthIntrospectionConstants.Metadata.IntrospectionEndpointAuthMethodsSupported)] 53 | public ISet IntrospectionEndpointAuthMethodsSupported { get; } = new HashSet(); 54 | 55 | /// 56 | /// Represents a configuration retriever able to deserialize 57 | /// instances. 58 | /// 59 | public class Retriever : IConfigurationRetriever 60 | { 61 | /// 62 | /// Retrieves the OAuth2 introspection configuration from the specified address. 63 | /// 64 | /// The address of the discovery document. 65 | /// The object used to retrieve the discovery document. 66 | /// The that can be used to abort the operation. 67 | /// An instance. 68 | public async Task GetConfigurationAsync( 69 | [NotNull] string address, [NotNull] IDocumentRetriever retriever, CancellationToken cancellationToken) 70 | { 71 | if (string.IsNullOrEmpty(address)) 72 | { 73 | throw new ArgumentException("The address cannot be null or empty.", nameof(address)); 74 | } 75 | 76 | if (retriever == null) 77 | { 78 | throw new ArgumentNullException(nameof(retriever)); 79 | } 80 | 81 | return new OAuthIntrospectionConfiguration(await retriever.GetDocumentAsync(address, cancellationToken)); 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/OAuthIntrospectionConstants.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace AspNet.Security.OAuth.Introspection 8 | { 9 | public static class OAuthIntrospectionConstants 10 | { 11 | public static class Claims 12 | { 13 | public const string Active = "active"; 14 | public const string Audience = "aud"; 15 | public const string ExpiresAt = "exp"; 16 | public const string IssuedAt = "iat"; 17 | public const string JwtId = "jti"; 18 | public const string Name = "name"; 19 | public const string NotBefore = "nbf"; 20 | public const string Role = "role"; 21 | public const string Scope = "scope"; 22 | public const string Subject = "sub"; 23 | public const string TokenType = "token_type"; 24 | public const string TokenUsage = "token_usage"; 25 | public const string Username = "username"; 26 | } 27 | 28 | public static class ClaimValueTypes 29 | { 30 | public const string Json = "JSON"; 31 | public const string JsonArray = "JSON_ARRAY"; 32 | } 33 | 34 | public static class ClientAuthenticationMethods 35 | { 36 | public const string ClientSecretBasic = "client_secret_basic"; 37 | public const string ClientSecretPost = "client_secret_post"; 38 | } 39 | 40 | public static class Errors 41 | { 42 | public const string InsufficientScope = "insufficient_scope"; 43 | public const string InvalidRequest = "invalid_request"; 44 | public const string InvalidToken = "invalid_token"; 45 | } 46 | 47 | public static class Metadata 48 | { 49 | public const string IntrospectionEndpoint = "introspection_endpoint"; 50 | public const string IntrospectionEndpointAuthMethodsSupported = "introspection_endpoint_auth_methods_supported"; 51 | } 52 | 53 | public static class Parameters 54 | { 55 | public const string ClientId = "client_id"; 56 | public const string ClientSecret = "client_secret"; 57 | public const string Error = "error"; 58 | public const string ErrorDescription = "error_description"; 59 | public const string ErrorUri = "error_uri"; 60 | public const string Realm = "realm"; 61 | public const string Scope = "scope"; 62 | public const string Token = "token"; 63 | public const string TokenTypeHint = "token_type_hint"; 64 | } 65 | 66 | public static class Properties 67 | { 68 | public const string AccessToken = "access_token"; 69 | public const string Audiences = ".audiences"; 70 | public const string Error = ".error"; 71 | public const string ErrorDescription = ".error_description"; 72 | public const string ErrorUri = ".error_uri"; 73 | public const string Realm = ".realm"; 74 | public const string Scope = ".scope"; 75 | public const string Scopes = ".scopes"; 76 | public const string TokenId = ".token_id"; 77 | public const string TokenUsage = ".token_usage"; 78 | } 79 | 80 | public static class Schemes 81 | { 82 | public const string Basic = "Basic"; 83 | public const string Bearer = "Bearer"; 84 | } 85 | 86 | public static class Separators 87 | { 88 | public static readonly char[] Space = { ' ' }; 89 | } 90 | 91 | public static class TokenTypeHints 92 | { 93 | public const string AccessToken = "access_token"; 94 | } 95 | 96 | public static class TokenUsages 97 | { 98 | public const string AccessToken = "access_token"; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/OAuthIntrospectionDefaults.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace AspNet.Security.OAuth.Introspection 8 | { 9 | public static class OAuthIntrospectionDefaults 10 | { 11 | /// 12 | /// Gets the default scheme used by the introspection middleware. 13 | /// 14 | public const string AuthenticationScheme = "Bearer"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/OAuthIntrospectionError.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace AspNet.Security.OAuth.Introspection 8 | { 9 | /// 10 | /// Represents an OAuth2 introspection error. 11 | /// 12 | public class OAuthIntrospectionError 13 | { 14 | /// 15 | /// Gets or sets the error code. 16 | /// 17 | public string Error { get; set; } 18 | 19 | /// 20 | /// Gets or sets the error_description. 21 | /// 22 | public string ErrorDescription { get; set; } 23 | 24 | /// 25 | /// Gets or sets the error_uri. 26 | /// 27 | public string ErrorUri { get; set; } 28 | 29 | /// 30 | /// Gets or sets the realm. 31 | /// 32 | public string Realm { get; set; } 33 | 34 | /// 35 | /// Gets or sets the scope. 36 | /// 37 | public string Scope { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/OAuthIntrospectionEvents.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Threading.Tasks; 9 | 10 | namespace AspNet.Security.OAuth.Introspection 11 | { 12 | /// 13 | /// Allows customization of introspection handling within the middleware. 14 | /// 15 | public class OAuthIntrospectionEvents 16 | { 17 | /// 18 | /// Invoked when a challenge response is returned to the caller. 19 | /// 20 | public Func OnApplyChallenge { get; set; } = context => Task.CompletedTask; 21 | 22 | /// 23 | /// Invoked when a ticket is to be created from an introspection response. 24 | /// 25 | public Func OnCreateTicket { get; set; } = context => Task.CompletedTask; 26 | 27 | /// 28 | /// Invoked when a token is to be sent to the authorization server for introspection. 29 | /// 30 | public Func OnSendIntrospectionRequest { get; set; } = context => Task.CompletedTask; 31 | 32 | /// 33 | /// Invoked when a token is to be parsed from a newly-received request. 34 | /// 35 | public Func OnRetrieveToken { get; set; } = context => Task.CompletedTask; 36 | 37 | /// 38 | /// Invoked when a token is to be validated, before final processing. 39 | /// 40 | public Func OnValidateToken { get; set; } = context => Task.CompletedTask; 41 | 42 | /// 43 | /// Invoked when a challenge response is returned to the caller. 44 | /// 45 | public virtual Task ApplyChallenge(ApplyChallengeContext context) => OnApplyChallenge(context); 46 | 47 | /// 48 | /// Invoked when a ticket is to be created from an introspection response. 49 | /// 50 | public virtual Task CreateTicket(CreateTicketContext context) => OnCreateTicket(context); 51 | 52 | /// 53 | /// Invoked when a token is to be sent to the authorization server for introspection. 54 | /// 55 | public virtual Task SendIntrospectionRequest(SendIntrospectionRequestContext context) => OnSendIntrospectionRequest(context); 56 | 57 | /// 58 | /// Invoked when a token is to be parsed from a newly-received request. 59 | /// 60 | public virtual Task RetrieveToken(RetrieveTokenContext context) => OnRetrieveToken(context); 61 | 62 | /// 63 | /// Invoked when a token is to be validated, before final processing. 64 | /// 65 | public virtual Task ValidateToken(ValidateTokenContext context) => OnValidateToken(context); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/OAuthIntrospectionExtensions.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.ComponentModel; 9 | using AspNet.Security.OAuth.Introspection; 10 | using JetBrains.Annotations; 11 | using Microsoft.AspNetCore.Authentication; 12 | using Microsoft.Extensions.DependencyInjection.Extensions; 13 | using Microsoft.Extensions.Options; 14 | 15 | namespace Microsoft.Extensions.DependencyInjection 16 | { 17 | /// 18 | /// Provides extension methods used to configure the OAuth2 19 | /// introspection middleware in an ASP.NET Core pipeline. 20 | /// 21 | public static class OAuthIntrospectionExtensions 22 | { 23 | /// 24 | /// Adds a new instance of the OAuth2 introspection middleware in the ASP.NET Core pipeline. 25 | /// 26 | /// The authentication builder. 27 | /// The authentication builder. 28 | public static AuthenticationBuilder AddOAuthIntrospection([NotNull] this AuthenticationBuilder builder) 29 | { 30 | return builder.AddOAuthIntrospection(OAuthIntrospectionDefaults.AuthenticationScheme); 31 | } 32 | 33 | /// 34 | /// Adds a new instance of the OAuth2 introspection middleware in the ASP.NET Core pipeline. 35 | /// 36 | /// The authentication builder. 37 | /// The delegate used to configure the introspection options. 38 | /// The authentication builder. 39 | public static AuthenticationBuilder AddOAuthIntrospection( 40 | [NotNull] this AuthenticationBuilder builder, 41 | [NotNull] Action configuration) 42 | { 43 | return builder.AddOAuthIntrospection(OAuthIntrospectionDefaults.AuthenticationScheme, configuration); 44 | } 45 | 46 | /// 47 | /// Adds a new instance of the OAuth2 introspection middleware in the ASP.NET Core pipeline. 48 | /// 49 | /// The authentication builder. 50 | /// The authentication scheme associated with this instance. 51 | /// The authentication builder. 52 | [EditorBrowsable(EditorBrowsableState.Advanced)] 53 | public static AuthenticationBuilder AddOAuthIntrospection( 54 | [NotNull] this AuthenticationBuilder builder, [NotNull] string scheme) 55 | { 56 | return builder.AddOAuthIntrospection(scheme, options => { }); 57 | } 58 | 59 | /// 60 | /// Adds a new instance of the OAuth2 introspection middleware in the ASP.NET Core pipeline. 61 | /// 62 | /// The authentication builder. 63 | /// The authentication scheme associated with this instance. 64 | /// The delegate used to configure the introspection options. 65 | /// The authentication builder. 66 | [EditorBrowsable(EditorBrowsableState.Advanced)] 67 | public static AuthenticationBuilder AddOAuthIntrospection( 68 | [NotNull] this AuthenticationBuilder builder, [NotNull] string scheme, 69 | [NotNull] Action configuration) 70 | { 71 | if (builder == null) 72 | { 73 | throw new ArgumentNullException(nameof(builder)); 74 | } 75 | 76 | if (configuration == null) 77 | { 78 | throw new ArgumentNullException(nameof(configuration)); 79 | } 80 | 81 | if (string.IsNullOrEmpty(scheme)) 82 | { 83 | throw new ArgumentException("The scheme cannot be null or empty.", nameof(scheme)); 84 | } 85 | 86 | // Note: TryAddEnumerable() is used here to ensure the initializer is only registered once. 87 | builder.Services.TryAddEnumerable( 88 | ServiceDescriptor.Singleton, 89 | OAuthIntrospectionInitializer>()); 90 | 91 | return builder.AddScheme(scheme, configuration); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/OAuthIntrospectionFeature.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace AspNet.Security.OAuth.Introspection 8 | { 9 | /// 10 | /// Exposes the OAuth2 introspection details 11 | /// associated with the current request. 12 | /// 13 | public class OAuthIntrospectionFeature 14 | { 15 | /// 16 | /// Gets or sets the error details returned 17 | /// as part of the challenge response. 18 | /// 19 | public OAuthIntrospectionError Error { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/OAuthIntrospectionHelpers.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using JetBrains.Annotations; 9 | using Microsoft.AspNetCore.Authentication; 10 | 11 | namespace AspNet.Security.OAuth.Introspection 12 | { 13 | /// 14 | /// Defines a set of commonly used helpers. 15 | /// 16 | internal static class OAuthIntrospectionHelpers 17 | { 18 | /// 19 | /// Gets a given property from the authentication properties. 20 | /// 21 | /// The authentication properties. 22 | /// The specific property to look for. 23 | /// The value corresponding to the property, or null if the property cannot be found. 24 | public static string GetProperty([NotNull] this AuthenticationProperties properties, [NotNull] string property) 25 | { 26 | if (properties == null) 27 | { 28 | throw new ArgumentNullException(nameof(properties)); 29 | } 30 | 31 | if (string.IsNullOrEmpty(property)) 32 | { 33 | throw new ArgumentException("The property name cannot be null or empty.", nameof(property)); 34 | } 35 | 36 | if (!properties.Items.TryGetValue(property, out string value)) 37 | { 38 | return null; 39 | } 40 | 41 | return value; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/OAuthIntrospectionInitializer.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.ComponentModel; 9 | using System.Net.Http; 10 | using JetBrains.Annotations; 11 | using Microsoft.AspNetCore.Authentication; 12 | using Microsoft.AspNetCore.DataProtection; 13 | using Microsoft.Extensions.Caching.Distributed; 14 | using Microsoft.Extensions.Options; 15 | using Microsoft.IdentityModel.Protocols; 16 | 17 | namespace AspNet.Security.OAuth.Introspection 18 | { 19 | /// 20 | /// Contains the methods required to ensure that the configuration used by 21 | /// the OAuth2 introspection handler is in a consistent and valid state. 22 | /// 23 | [EditorBrowsable(EditorBrowsableState.Never)] 24 | public class OAuthIntrospectionInitializer : IPostConfigureOptions 25 | { 26 | private readonly IDistributedCache _cache; 27 | private readonly IDataProtectionProvider _dataProtectionProvider; 28 | 29 | /// 30 | /// Creates a new instance of the class. 31 | /// 32 | public OAuthIntrospectionInitializer( 33 | [NotNull] IDistributedCache cache, 34 | [NotNull] IDataProtectionProvider dataProtectionProvider) 35 | { 36 | _cache = cache; 37 | _dataProtectionProvider = dataProtectionProvider; 38 | } 39 | 40 | /// 41 | /// Populates the default OAuth2 introspection options and ensure 42 | /// that the configuration is in a consistent and valid state. 43 | /// 44 | /// The authentication scheme associated with the handler instance. 45 | /// The options instance to initialize. 46 | public void PostConfigure([NotNull] string name, [NotNull] OAuthIntrospectionOptions options) 47 | { 48 | if (options == null) 49 | { 50 | throw new ArgumentNullException(nameof(options)); 51 | } 52 | 53 | if (string.IsNullOrEmpty(name)) 54 | { 55 | throw new ArgumentException("The options instance name cannot be null or empty.", nameof(name)); 56 | } 57 | 58 | if (string.IsNullOrEmpty(options.ClientId) || string.IsNullOrEmpty(options.ClientSecret)) 59 | { 60 | throw new InvalidOperationException("Client credentials must be configured."); 61 | } 62 | 63 | if (options.Events == null) 64 | { 65 | options.Events = new OAuthIntrospectionEvents(); 66 | } 67 | 68 | if (options.DataProtectionProvider == null) 69 | { 70 | options.DataProtectionProvider = _dataProtectionProvider; 71 | } 72 | 73 | if (options.AccessTokenFormat == null) 74 | { 75 | var protector = options.DataProtectionProvider.CreateProtector( 76 | nameof(OAuthIntrospectionHandler), 77 | nameof(options.AccessTokenFormat), name); 78 | 79 | options.AccessTokenFormat = new TicketDataFormat(protector); 80 | } 81 | 82 | if (options.Cache == null) 83 | { 84 | options.Cache = _cache; 85 | } 86 | 87 | if (options.HttpClient == null) 88 | { 89 | options.HttpClient = new HttpClient 90 | { 91 | Timeout = TimeSpan.FromSeconds(15), 92 | MaxResponseContentBufferSize = 1024 * 1024 * 10 93 | }; 94 | 95 | options.HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd("ASP.NET Core OAuth2 introspection middleware"); 96 | } 97 | 98 | if (options.ConfigurationManager == null) 99 | { 100 | if (options.Configuration != null) 101 | { 102 | if (string.IsNullOrEmpty(options.Configuration.IntrospectionEndpoint)) 103 | { 104 | throw new InvalidOperationException("The introspection endpoint address cannot be null or empty."); 105 | } 106 | 107 | options.ConfigurationManager = new StaticConfigurationManager(options.Configuration); 108 | } 109 | 110 | else 111 | { 112 | if (options.Authority == null && options.MetadataAddress == null) 113 | { 114 | throw new InvalidOperationException("The authority or an absolute metadata endpoint address must be provided."); 115 | } 116 | 117 | if (options.MetadataAddress == null) 118 | { 119 | options.MetadataAddress = new Uri(".well-known/openid-configuration", UriKind.Relative); 120 | } 121 | 122 | if (!options.MetadataAddress.IsAbsoluteUri) 123 | { 124 | if (options.Authority == null || !options.Authority.IsAbsoluteUri) 125 | { 126 | throw new InvalidOperationException("The authority must be provided and must be an absolute URL."); 127 | } 128 | 129 | if (!string.IsNullOrEmpty(options.Authority.Fragment) || !string.IsNullOrEmpty(options.Authority.Query)) 130 | { 131 | throw new InvalidOperationException("The authority cannot contain a fragment or a query string."); 132 | } 133 | 134 | if (!options.Authority.OriginalString.EndsWith("/")) 135 | { 136 | options.Authority = new Uri(options.Authority.OriginalString + "/", UriKind.Absolute); 137 | } 138 | 139 | options.MetadataAddress = new Uri(options.Authority, options.MetadataAddress); 140 | } 141 | 142 | if (options.RequireHttpsMetadata && !options.MetadataAddress.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase)) 143 | { 144 | throw new InvalidOperationException("The metadata endpoint address must be a HTTPS URL when " + 145 | "'RequireHttpsMetadata' is not set to 'false'."); 146 | } 147 | 148 | options.ConfigurationManager = new ConfigurationManager( 149 | options.MetadataAddress.AbsoluteUri, new OAuthIntrospectionConfiguration.Retriever(), 150 | new HttpDocumentRetriever(options.HttpClient) { RequireHttps = options.RequireHttpsMetadata }); 151 | } 152 | } 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Introspection/OAuthIntrospectionOptions.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Net.Http; 10 | using Microsoft.AspNetCore.Authentication; 11 | using Microsoft.AspNetCore.DataProtection; 12 | using Microsoft.Extensions.Caching.Distributed; 13 | using Microsoft.IdentityModel.Protocols; 14 | 15 | namespace AspNet.Security.OAuth.Introspection 16 | { 17 | /// 18 | /// Exposes various settings needed to control 19 | /// the behavior of the introspection middleware. 20 | /// 21 | public class OAuthIntrospectionOptions : AuthenticationSchemeOptions 22 | { 23 | /// 24 | /// Creates a new instance of the class. 25 | /// 26 | public OAuthIntrospectionOptions() 27 | { 28 | Events = new OAuthIntrospectionEvents(); 29 | } 30 | 31 | /// 32 | /// Gets the intended audiences of this resource server. 33 | /// Setting this property is recommended when the authorization 34 | /// server issues access tokens for multiple distinct resource servers. 35 | /// 36 | public ISet Audiences { get; } = new HashSet(StringComparer.Ordinal); 37 | 38 | /// 39 | /// Gets or sets the absolute URL of the OAuth2/OpenID Connect server. 40 | /// Note: this property is ignored when 41 | /// or are set. 42 | /// 43 | public Uri Authority { get; set; } 44 | 45 | /// 46 | /// Gets or sets the URL of the OAuth2/OpenID Connect server discovery endpoint. 47 | /// When the URL is relative, must be set and absolute. 48 | /// Note: this property is ignored when 49 | /// or are set. 50 | /// 51 | public Uri MetadataAddress { get; set; } 52 | 53 | /// 54 | /// Gets or sets a boolean indicating whether HTTPS is required to retrieve the metadata document. 55 | /// The default value is true. This option should be used only in development environments. 56 | /// Note: this property is ignored when or are set. 57 | /// 58 | public bool RequireHttpsMetadata { get; set; } = true; 59 | 60 | /// 61 | /// Gets or sets the configuration used by the introspection middleware. 62 | /// Note: this property is ignored when is set. 63 | /// 64 | public OAuthIntrospectionConfiguration Configuration { get; set; } 65 | 66 | /// 67 | /// Gets or sets the configuration manager used by the introspection middleware. 68 | /// 69 | public IConfigurationManager ConfigurationManager { get; set; } 70 | 71 | /// 72 | /// Gets or sets the client identifier representing the resource server. 73 | /// 74 | public string ClientId { get; set; } 75 | 76 | /// 77 | /// Gets or sets the client secret used to 78 | /// communicate with the introspection endpoint. 79 | /// 80 | public string ClientSecret { get; set; } 81 | 82 | /// 83 | /// Gets or sets the optional "realm" value returned to 84 | /// the caller as part of the WWW-Authenticate header. 85 | /// 86 | public string Realm { get; set; } 87 | 88 | /// 89 | /// Gets or sets a boolean determining whether the access token should be stored in the 90 | /// after a successful authentication process. 91 | /// 92 | public bool SaveToken { get; set; } = true; 93 | 94 | /// 95 | /// Gets or sets a boolean determining whether the token validation errors should be returned to the caller. 96 | /// Enabled by default, this option can be disabled to prevent the introspection middleware from returning 97 | /// an error, an error_description and/or an error_uri in the WWW-Authenticate header. 98 | /// 99 | public bool IncludeErrorDetails { get; set; } = true; 100 | 101 | /// 102 | /// Gets or sets the claim type used for the name claim. 103 | /// By default, the standard 104 | /// claim defined by the OAuth2 introspection specification is used. 105 | /// 106 | public string NameClaimType { get; set; } = OAuthIntrospectionConstants.Claims.Name; 107 | 108 | /// 109 | /// Gets or sets the claim type used for the role claim(s). 110 | /// By default, is used. 111 | /// 112 | public string RoleClaimType { get; set; } = OAuthIntrospectionConstants.Claims.Role; 113 | 114 | /// 115 | /// Gets or sets the cache used to store the access tokens/authentication tickets 116 | /// and the introspection responses returned received by the resource server. 117 | /// 118 | public IDistributedCache Cache { get; set; } 119 | 120 | /// 121 | /// Gets or sets the caching policy used to determine 122 | /// how long the introspection responses should be cached. 123 | /// Note: this property can be set to null to 124 | /// prevent the introspection responses from being cached. 125 | /// 126 | public DistributedCacheEntryOptions CachingPolicy { get; set; } = new DistributedCacheEntryOptions 127 | { 128 | AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(15) 129 | }; 130 | 131 | /// 132 | /// Gets or sets the object provided by the application to process events raised by the authentication middleware. 133 | /// The application may implement the interface fully, or it may create an instance of 134 | /// and assign delegates only to the events it wants to process. 135 | /// 136 | public new OAuthIntrospectionEvents Events 137 | { 138 | get => (OAuthIntrospectionEvents) base.Events; 139 | set => base.Events = value; 140 | } 141 | 142 | /// 143 | /// Gets or sets the HTTP client used to communicate with the remote OAuth2 server. 144 | /// 145 | public HttpClient HttpClient { get; set; } 146 | 147 | /// 148 | /// Gets or sets the clock used to determine the current date/time. 149 | /// 150 | public ISystemClock SystemClock { get; set; } = new SystemClock(); 151 | 152 | /// 153 | /// Gets or sets the data format used to serialize and deserialize 154 | /// the authenticated tickets stored in the distributed cache. 155 | /// 156 | public ISecureDataFormat AccessTokenFormat { get; set; } 157 | 158 | /// 159 | /// Gets or sets the data protection provider used to create the default 160 | /// data protectors used by the OAuth2 introspection handler. 161 | /// When this property is set to null, the data protection provider 162 | /// is directly retrieved from the dependency injection container. 163 | /// 164 | public IDataProtectionProvider DataProtectionProvider { get; set; } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/AspNet.Security.OAuth.Validation.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | netstandard2.0 7 | 8 | 9 | 10 | OAuth2 validation middleware for ASP.NET Core. 11 | Kévin Chalet 12 | aspnetcore;authentication;jwt;openidconnect;security 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/Events/ApplyChallengeContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.AspNetCore.Authentication; 9 | using Microsoft.AspNetCore.Http; 10 | 11 | namespace AspNet.Security.OAuth.Validation 12 | { 13 | /// 14 | /// Allows customization of the challenge process. 15 | /// 16 | public class ApplyChallengeContext : PropertiesContext 17 | { 18 | public ApplyChallengeContext( 19 | [NotNull] HttpContext context, 20 | [NotNull] AuthenticationScheme scheme, 21 | [NotNull] OAuthValidationOptions options, 22 | [NotNull] AuthenticationProperties properties) 23 | : base(context, scheme, options, properties) 24 | { 25 | } 26 | 27 | /// 28 | /// Gets or sets the "error" value returned to the caller as part 29 | /// of the WWW-Authenticate header. This property may be null when 30 | /// is set to false. 31 | /// 32 | public string Error { get; set; } 33 | 34 | /// 35 | /// Gets or sets the "error_description" value returned to the caller as part 36 | /// of the WWW-Authenticate header. This property may be null when 37 | /// is set to false. 38 | /// 39 | public string ErrorDescription { get; set; } 40 | 41 | /// 42 | /// Gets or sets the "error_uri" value returned to the caller as part of the 43 | /// WWW-Authenticate header. This property is always null unless explicitly set. 44 | /// 45 | public string ErrorUri { get; set; } 46 | 47 | /// 48 | /// Gets or sets the "realm" value returned to 49 | /// the caller as part of the WWW-Authenticate header. 50 | /// 51 | public string Realm { get; set; } 52 | 53 | /// 54 | /// Gets or sets the "scope" value returned to 55 | /// the caller as part of the WWW-Authenticate header. 56 | /// 57 | public string Scope { get; set; } 58 | 59 | /// 60 | /// Gets a boolean indicating if the operation was handled from user code. 61 | /// 62 | public bool Handled { get; private set; } 63 | 64 | /// 65 | /// Marks the operation as handled to prevent the default logic from being applied. 66 | /// 67 | public void HandleResponse() => Handled = true; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/Events/CreateTicketContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System.Security.Claims; 8 | using JetBrains.Annotations; 9 | using Microsoft.AspNetCore.Authentication; 10 | using Microsoft.AspNetCore.Http; 11 | 12 | namespace AspNet.Security.OAuth.Validation 13 | { 14 | /// 15 | /// Allows interception of the AuthenticationTicket creation process. 16 | /// 17 | public class CreateTicketContext : ResultContext 18 | { 19 | public CreateTicketContext( 20 | [NotNull] HttpContext context, 21 | [NotNull] AuthenticationScheme scheme, 22 | [NotNull] OAuthValidationOptions options, 23 | [NotNull] AuthenticationTicket ticket) 24 | : base(context, scheme, options) 25 | { 26 | Principal = ticket.Principal; 27 | Properties = ticket.Properties; 28 | } 29 | 30 | /// 31 | /// Gets the identity containing the user claims. 32 | /// 33 | public ClaimsIdentity Identity => Principal?.Identity as ClaimsIdentity; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/Events/DecryptTokenContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.AspNetCore.Authentication; 9 | using Microsoft.AspNetCore.Http; 10 | 11 | namespace AspNet.Security.OAuth.Validation 12 | { 13 | /// 14 | /// Allows custom decryption of access tokens. 15 | /// 16 | public class DecryptTokenContext : ResultContext 17 | { 18 | public DecryptTokenContext( 19 | [NotNull] HttpContext context, 20 | [NotNull] AuthenticationScheme scheme, 21 | [NotNull] OAuthValidationOptions options, 22 | [NotNull] string token) 23 | : base(context, scheme, options) 24 | { 25 | Token = token; 26 | } 27 | 28 | /// 29 | /// Gets the access token. 30 | /// 31 | public string Token { get; } 32 | 33 | /// 34 | /// Gets or sets the data format used to deserialize the authentication ticket. 35 | /// 36 | public ISecureDataFormat DataFormat { get; set; } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/Events/RetrieveTokenContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.AspNetCore.Authentication; 9 | using Microsoft.AspNetCore.Http; 10 | 11 | namespace AspNet.Security.OAuth.Validation 12 | { 13 | /// 14 | /// Allows custom parsing of access tokens from requests. 15 | /// 16 | public class RetrieveTokenContext : ResultContext 17 | { 18 | public RetrieveTokenContext( 19 | [NotNull] HttpContext context, 20 | [NotNull] AuthenticationScheme scheme, 21 | [NotNull] OAuthValidationOptions options) 22 | : base(context, scheme, options) 23 | { 24 | } 25 | 26 | /// 27 | /// Gets or sets the access token. 28 | /// 29 | public string Token { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/Events/ValidateTokenContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.AspNetCore.Authentication; 9 | using Microsoft.AspNetCore.Http; 10 | 11 | namespace AspNet.Security.OAuth.Validation 12 | { 13 | /// 14 | /// Allows customization of the token validation logic. 15 | /// 16 | public class ValidateTokenContext : ResultContext 17 | { 18 | public ValidateTokenContext( 19 | [NotNull] HttpContext context, 20 | [NotNull] AuthenticationScheme scheme, 21 | [NotNull] OAuthValidationOptions options, 22 | [NotNull] AuthenticationTicket ticket) 23 | : base(context, scheme, options) 24 | { 25 | Principal = ticket.Principal; 26 | Properties = ticket.Properties; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/OAuthValidationConstants.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace AspNet.Security.OAuth.Validation 8 | { 9 | public static class OAuthValidationConstants 10 | { 11 | public static class Claims 12 | { 13 | public const string Scope = "scope"; 14 | public const string Subject = "subject"; 15 | } 16 | 17 | public static class Errors 18 | { 19 | public const string InsufficientScope = "insufficient_scope"; 20 | public const string InvalidRequest = "invalid_request"; 21 | public const string InvalidToken = "invalid_token"; 22 | } 23 | 24 | public static class Parameters 25 | { 26 | public const string Error = "error"; 27 | public const string ErrorDescription = "error_description"; 28 | public const string ErrorUri = "error_uri"; 29 | public const string Realm = "realm"; 30 | public const string Scope = "scope"; 31 | } 32 | 33 | public static class Properties 34 | { 35 | public const string Audiences = ".audiences"; 36 | public const string Error = ".error"; 37 | public const string ErrorDescription = ".error_description"; 38 | public const string ErrorUri = ".error_uri"; 39 | public const string Realm = ".realm"; 40 | public const string Scope = ".scope"; 41 | public const string Scopes = ".scopes"; 42 | public const string Token = "access_token"; 43 | } 44 | 45 | public static class Schemes 46 | { 47 | public const string Bearer = "Bearer"; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/OAuthValidationDefaults.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace AspNet.Security.OAuth.Validation 8 | { 9 | public static class OAuthValidationDefaults 10 | { 11 | /// 12 | /// Gets the default scheme used by the validation middleware. 13 | /// 14 | public const string AuthenticationScheme = "Bearer"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/OAuthValidationError.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace AspNet.Security.OAuth.Validation 8 | { 9 | /// 10 | /// Represents an OAuth2 validation error. 11 | /// 12 | public class OAuthValidationError 13 | { 14 | /// 15 | /// Gets or sets the error code. 16 | /// 17 | public string Error { get; set; } 18 | 19 | /// 20 | /// Gets or sets the error_description. 21 | /// 22 | public string ErrorDescription { get; set; } 23 | 24 | /// 25 | /// Gets or sets the error_uri. 26 | /// 27 | public string ErrorUri { get; set; } 28 | 29 | /// 30 | /// Gets or sets the realm. 31 | /// 32 | public string Realm { get; set; } 33 | 34 | /// 35 | /// Gets or sets the scope. 36 | /// 37 | public string Scope { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/OAuthValidationEvents.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Threading.Tasks; 9 | 10 | namespace AspNet.Security.OAuth.Validation 11 | { 12 | /// 13 | /// Allows customization of validation handling within the middleware. 14 | /// 15 | public class OAuthValidationEvents 16 | { 17 | /// 18 | /// Invoked when a challenge response is returned to the caller. 19 | /// 20 | public Func OnApplyChallenge { get; set; } = context => Task.CompletedTask; 21 | 22 | /// 23 | /// Invoked when a ticket is to be created from an introspection response. 24 | /// 25 | public Func OnCreateTicket { get; set; } = context => Task.CompletedTask; 26 | 27 | /// 28 | /// Invoked when a token is to be decrypted. 29 | /// 30 | public Func OnDecryptToken { get; set; } = context => Task.CompletedTask; 31 | 32 | /// 33 | /// Invoked when a token is to be parsed from a newly-received request. 34 | /// 35 | public Func OnRetrieveToken { get; set; } = context => Task.CompletedTask; 36 | 37 | /// 38 | /// Invoked when a token is to be validated, before final processing. 39 | /// 40 | public Func OnValidateToken { get; set; } = context => Task.CompletedTask; 41 | 42 | /// 43 | /// Invoked when a challenge response is returned to the caller. 44 | /// 45 | public virtual Task ApplyChallenge(ApplyChallengeContext context) => OnApplyChallenge(context); 46 | 47 | /// 48 | /// Invoked when a ticket is to be created from an introspection response. 49 | /// 50 | public virtual Task CreateTicket(CreateTicketContext context) => OnCreateTicket(context); 51 | 52 | /// 53 | /// Invoked when a token is to be decrypted. 54 | /// 55 | public virtual Task DecryptToken(DecryptTokenContext context) => OnDecryptToken(context); 56 | 57 | /// 58 | /// Invoked when a token is to be parsed from a newly-received request. 59 | /// 60 | public virtual Task RetrieveToken(RetrieveTokenContext context) => OnRetrieveToken(context); 61 | 62 | /// 63 | /// Invoked when a token is to be validated, before final processing. 64 | /// 65 | public virtual Task ValidateToken(ValidateTokenContext context) => OnValidateToken(context); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/OAuthValidationExtensions.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.ComponentModel; 9 | using AspNet.Security.OAuth.Validation; 10 | using JetBrains.Annotations; 11 | using Microsoft.AspNetCore.Authentication; 12 | using Microsoft.Extensions.DependencyInjection.Extensions; 13 | using Microsoft.Extensions.Options; 14 | 15 | namespace Microsoft.Extensions.DependencyInjection 16 | { 17 | /// 18 | /// Provides extension methods used to configure the OAuth2 19 | /// validation middleware in an ASP.NET Core pipeline. 20 | /// 21 | public static class OAuthValidationExtensions 22 | { 23 | /// 24 | /// Adds a new instance of the OAuth2 validation middleware in the ASP.NET Core pipeline. 25 | /// 26 | /// The authentication builder. 27 | /// The authentication builder. 28 | public static AuthenticationBuilder AddOAuthValidation([NotNull] this AuthenticationBuilder builder) 29 | { 30 | return builder.AddOAuthValidation(OAuthValidationDefaults.AuthenticationScheme); 31 | } 32 | 33 | /// 34 | /// Adds a new instance of the OAuth2 validation middleware in the ASP.NET Core pipeline. 35 | /// 36 | /// The authentication builder. 37 | /// The delegate used to configure the validation options. 38 | /// The authentication builder. 39 | public static AuthenticationBuilder AddOAuthValidation( 40 | [NotNull] this AuthenticationBuilder builder, 41 | [NotNull] Action configuration) 42 | { 43 | return builder.AddOAuthValidation(OAuthValidationDefaults.AuthenticationScheme, configuration); 44 | } 45 | 46 | /// 47 | /// Adds a new instance of the OAuth2 validation middleware in the ASP.NET Core pipeline. 48 | /// 49 | /// The authentication builder. 50 | /// The authentication scheme associated with this instance. 51 | /// The authentication builder. 52 | [EditorBrowsable(EditorBrowsableState.Advanced)] 53 | public static AuthenticationBuilder AddOAuthValidation( 54 | [NotNull] this AuthenticationBuilder builder, [NotNull] string scheme) 55 | { 56 | return builder.AddOAuthValidation(scheme, options => { }); 57 | } 58 | 59 | /// 60 | /// Adds a new instance of the OAuth2 validation middleware in the ASP.NET Core pipeline. 61 | /// 62 | /// The authentication builder. 63 | /// The authentication scheme associated with this instance. 64 | /// The delegate used to configure the validation options. 65 | /// The authentication builder. 66 | [EditorBrowsable(EditorBrowsableState.Advanced)] 67 | public static AuthenticationBuilder AddOAuthValidation( 68 | [NotNull] this AuthenticationBuilder builder, [NotNull] string scheme, 69 | [NotNull] Action configuration) 70 | { 71 | if (builder == null) 72 | { 73 | throw new ArgumentNullException(nameof(builder)); 74 | } 75 | 76 | if (configuration == null) 77 | { 78 | throw new ArgumentNullException(nameof(configuration)); 79 | } 80 | 81 | if (string.IsNullOrEmpty(scheme)) 82 | { 83 | throw new ArgumentException("The scheme cannot be null or empty.", nameof(scheme)); 84 | } 85 | 86 | // Note: TryAddEnumerable() is used here to ensure the initializer is only registered once. 87 | builder.Services.TryAddEnumerable( 88 | ServiceDescriptor.Singleton, 89 | OAuthValidationInitializer>()); 90 | 91 | return builder.AddScheme(scheme, configuration); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/OAuthValidationFeature.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace AspNet.Security.OAuth.Validation 8 | { 9 | /// 10 | /// Exposes the OAuth2 validation details 11 | /// associated with the current request. 12 | /// 13 | public class OAuthValidationFeature 14 | { 15 | /// 16 | /// Gets or sets the error details returned 17 | /// as part of the challenge response. 18 | /// 19 | public OAuthValidationError Error { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/OAuthValidationHelpers.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using JetBrains.Annotations; 9 | using Microsoft.AspNetCore.Authentication; 10 | 11 | namespace AspNet.Security.OAuth.Validation 12 | { 13 | /// 14 | /// Defines a set of commonly used helpers. 15 | /// 16 | internal static class OAuthValidationHelpers 17 | { 18 | /// 19 | /// Gets a given property from the authentication properties. 20 | /// 21 | /// The authentication properties. 22 | /// The specific property to look for. 23 | /// The value corresponding to the property, or null if the property cannot be found. 24 | public static string GetProperty([NotNull] this AuthenticationProperties properties, [NotNull] string property) 25 | { 26 | if (properties == null) 27 | { 28 | throw new ArgumentNullException(nameof(properties)); 29 | } 30 | 31 | if (string.IsNullOrEmpty(property)) 32 | { 33 | throw new ArgumentException("The property name cannot be null or empty.", nameof(property)); 34 | } 35 | 36 | if (!properties.Items.TryGetValue(property, out string value)) 37 | { 38 | return null; 39 | } 40 | 41 | return value; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/OAuthValidationInitializer.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.ComponentModel; 9 | using JetBrains.Annotations; 10 | using Microsoft.AspNetCore.Authentication; 11 | using Microsoft.AspNetCore.DataProtection; 12 | using Microsoft.Extensions.Options; 13 | 14 | namespace AspNet.Security.OAuth.Validation 15 | { 16 | /// 17 | /// Contains the methods required to ensure that the configuration used by 18 | /// the OAuth2 validation handler is in a consistent and valid state. 19 | /// 20 | [EditorBrowsable(EditorBrowsableState.Never)] 21 | public class OAuthValidationInitializer : IPostConfigureOptions 22 | { 23 | private readonly IDataProtectionProvider _dataProtectionProvider; 24 | 25 | /// 26 | /// Creates a new instance of the class. 27 | /// 28 | public OAuthValidationInitializer([NotNull] IDataProtectionProvider dataProtectionProvider) 29 | { 30 | _dataProtectionProvider = dataProtectionProvider; 31 | } 32 | 33 | /// 34 | /// Populates the default OAuth2 validation options and ensure 35 | /// that the configuration is in a consistent and valid state. 36 | /// 37 | /// The authentication scheme associated with the handler instance. 38 | /// The options instance to initialize. 39 | public void PostConfigure([NotNull] string name, [NotNull] OAuthValidationOptions options) 40 | { 41 | if (options == null) 42 | { 43 | throw new ArgumentNullException(nameof(options)); 44 | } 45 | 46 | if (string.IsNullOrEmpty(name)) 47 | { 48 | throw new ArgumentException("The options instance name cannot be null or empty.", nameof(name)); 49 | } 50 | 51 | if (options.Events == null) 52 | { 53 | options.Events = new OAuthValidationEvents(); 54 | } 55 | 56 | if (options.DataProtectionProvider == null) 57 | { 58 | options.DataProtectionProvider = _dataProtectionProvider; 59 | } 60 | 61 | if (options.AccessTokenFormat == null) 62 | { 63 | // Note: the following purposes must match the ones used by the OpenID Connect server middleware. 64 | var protector = options.DataProtectionProvider.CreateProtector( 65 | "OpenIdConnectServerHandler", nameof(options.AccessTokenFormat), "ASOS"); 66 | 67 | options.AccessTokenFormat = new TicketDataFormat(protector); 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/AspNet.Security.OAuth.Validation/OAuthValidationOptions.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using Microsoft.AspNetCore.Authentication; 10 | using Microsoft.AspNetCore.DataProtection; 11 | 12 | namespace AspNet.Security.OAuth.Validation 13 | { 14 | /// 15 | /// Exposes various settings needed to control 16 | /// the behavior of the validation middleware. 17 | /// 18 | public class OAuthValidationOptions : AuthenticationSchemeOptions 19 | { 20 | /// 21 | /// Creates a new instance of the class. 22 | /// 23 | public OAuthValidationOptions() 24 | { 25 | Events = new OAuthValidationEvents(); 26 | } 27 | 28 | /// 29 | /// Gets the intended audiences of this resource server. 30 | /// Setting this property is recommended when the authorization 31 | /// server issues access tokens for multiple distinct resource servers. 32 | /// 33 | public ISet Audiences { get; } = new HashSet(StringComparer.Ordinal); 34 | 35 | /// 36 | /// Gets or sets the optional "realm" value returned to 37 | /// the caller as part of the WWW-Authenticate header. 38 | /// 39 | public string Realm { get; set; } 40 | 41 | /// 42 | /// Gets or sets a boolean determining whether the access token should be stored in the 43 | /// after a successful authentication process. 44 | /// 45 | public bool SaveToken { get; set; } = true; 46 | 47 | /// 48 | /// Gets or sets a boolean determining whether the token validation errors should be returned to the caller. 49 | /// Enabled by default, this option can be disabled to prevent the validation middleware from returning 50 | /// an error, an error_description and/or an error_uri in the WWW-Authenticate header. 51 | /// 52 | public bool IncludeErrorDetails { get; set; } = true; 53 | 54 | /// 55 | /// Gets or sets the object provided by the application to process events raised by the authentication middleware. 56 | /// The application may implement the interface fully, or it may create an instance of 57 | /// and assign delegates only to the events it wants to process. 58 | /// 59 | public new OAuthValidationEvents Events 60 | { 61 | get => (OAuthValidationEvents) base.Events; 62 | set => base.Events = value; 63 | } 64 | 65 | /// 66 | /// Gets or sets the clock used to determine the current date/time. 67 | /// 68 | public ISystemClock SystemClock { get; set; } = new SystemClock(); 69 | 70 | /// 71 | /// Gets or sets the data format used to unprotect the 72 | /// access tokens received by the validation middleware. 73 | /// 74 | public ISecureDataFormat AccessTokenFormat { get; set; } 75 | 76 | /// 77 | /// Gets or sets the data protection provider used to create the default 78 | /// data protectors used by the OAuth2 validation handler. 79 | /// When this property is set to null, the data protection provider 80 | /// is directly retrieved from the dependency injection container. 81 | /// 82 | public IDataProtectionProvider DataProtectionProvider { get; set; } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/Events/ApplyChallengeContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.Owin; 9 | using Microsoft.Owin.Security; 10 | using Microsoft.Owin.Security.Provider; 11 | 12 | namespace Owin.Security.OAuth.Introspection 13 | { 14 | /// 15 | /// Allows customization of the challenge process. 16 | /// 17 | public class ApplyChallengeContext : BaseContext 18 | { 19 | public ApplyChallengeContext( 20 | [NotNull] IOwinContext context, 21 | [NotNull] OAuthIntrospectionOptions options, 22 | [NotNull] AuthenticationProperties properties) 23 | : base(context, options) 24 | { 25 | Properties = properties; 26 | } 27 | 28 | /// 29 | /// Gets the authentication properties associated with the challenge. 30 | /// 31 | public AuthenticationProperties Properties { get; } 32 | 33 | /// 34 | /// Gets or sets the "error" value returned to the caller as part 35 | /// of the WWW-Authenticate header. This property may be null when 36 | /// is set to false. 37 | /// 38 | public string Error { get; set; } 39 | 40 | /// 41 | /// Gets or sets the "error_description" value returned to the caller as part 42 | /// of the WWW-Authenticate header. This property may be null when 43 | /// is set to false. 44 | /// 45 | public string ErrorDescription { get; set; } 46 | 47 | /// 48 | /// Gets or sets the "error_uri" value returned to the caller as part of the 49 | /// WWW-Authenticate header. This property is always null unless explicitly set. 50 | /// 51 | public string ErrorUri { get; set; } 52 | 53 | /// 54 | /// Gets or sets the "realm" value returned to 55 | /// the caller as part of the WWW-Authenticate header. 56 | /// 57 | public string Realm { get; set; } 58 | 59 | /// 60 | /// Gets or sets the "scope" value returned to 61 | /// the caller as part of the WWW-Authenticate header. 62 | /// 63 | public string Scope { get; set; } 64 | 65 | /// 66 | /// Gets a boolean indicating if the operation was handled from user code. 67 | /// 68 | public bool Handled { get; private set; } 69 | 70 | /// 71 | /// Marks the operation as handled to prevent the default logic from being applied. 72 | /// 73 | public void HandleResponse() => Handled = true; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/Events/CreateTicketContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.Owin; 9 | using Microsoft.Owin.Security; 10 | using Microsoft.Owin.Security.Provider; 11 | using Newtonsoft.Json.Linq; 12 | 13 | namespace Owin.Security.OAuth.Introspection 14 | { 15 | /// 16 | /// Allows interception of the AuthenticationTicket creation process. 17 | /// 18 | public class CreateTicketContext : BaseContext 19 | { 20 | public CreateTicketContext( 21 | [NotNull] IOwinContext context, 22 | [NotNull] OAuthIntrospectionOptions options, 23 | [NotNull] AuthenticationTicket ticket, 24 | [NotNull] JObject payload) 25 | : base(context, options) 26 | { 27 | Ticket = ticket; 28 | Payload = payload; 29 | } 30 | 31 | /// 32 | /// Gets the payload extracted from the introspection response. 33 | /// 34 | public JObject Payload { get; } 35 | 36 | /// 37 | /// Gets or sets the created by the application. 38 | /// 39 | public AuthenticationTicket Ticket { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/Events/RetrieveTokenContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.Owin; 9 | using Microsoft.Owin.Security; 10 | using Microsoft.Owin.Security.Provider; 11 | 12 | namespace Owin.Security.OAuth.Introspection 13 | { 14 | /// 15 | /// Allows custom parsing of access tokens from requests. 16 | /// 17 | public class RetrieveTokenContext : BaseContext 18 | { 19 | public RetrieveTokenContext( 20 | [NotNull] IOwinContext context, 21 | [NotNull] OAuthIntrospectionOptions options) 22 | : base(context, options) 23 | { 24 | } 25 | 26 | /// 27 | /// Gets or sets the access token. 28 | /// 29 | public string Token { get; set; } 30 | 31 | /// 32 | /// Gets or sets the created by the application. 33 | /// 34 | public AuthenticationTicket Ticket { get; set; } 35 | 36 | /// 37 | /// Gets a boolean indicating if the operation was handled from user code. 38 | /// 39 | public bool Handled { get; private set; } 40 | 41 | /// 42 | /// Marks the operation as handled to prevent the default logic from being applied. 43 | /// 44 | public void HandleValidation() => Handled = true; 45 | 46 | /// 47 | /// Marks the operation as handled to prevent the default logic from being applied. 48 | /// 49 | /// The authentication ticket to use. 50 | public void HandleValidation(AuthenticationTicket ticket) 51 | { 52 | Ticket = ticket; 53 | Handled = true; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/Events/SendIntrospectionRequestContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System.Net.Http; 8 | using JetBrains.Annotations; 9 | using Microsoft.Owin; 10 | using Microsoft.Owin.Security.Provider; 11 | 12 | namespace Owin.Security.OAuth.Introspection 13 | { 14 | /// 15 | /// Allows for custom handling of the call to the Authorization Server's Introspection endpoint. 16 | /// 17 | public class SendIntrospectionRequestContext : BaseContext 18 | { 19 | public SendIntrospectionRequestContext( 20 | [NotNull] IOwinContext context, 21 | [NotNull] OAuthIntrospectionOptions options, 22 | [NotNull] HttpRequestMessage request, 23 | [NotNull] string token) 24 | : base(context, options) 25 | { 26 | Request = request; 27 | Token = token; 28 | } 29 | 30 | /// 31 | /// An for use by the application to call the authorization server. 32 | /// 33 | public HttpClient Client => Options.HttpClient; 34 | 35 | /// 36 | /// Gets the HTTP request sent to the introspection endpoint. 37 | /// 38 | public new HttpRequestMessage Request { get; } 39 | 40 | /// 41 | /// Gets or sets the HTTP response returned by the introspection endpoint. 42 | /// 43 | public new HttpResponseMessage Response { get; set; } 44 | 45 | /// 46 | /// The access token parsed from the client request. 47 | /// 48 | public string Token { get; } 49 | 50 | /// 51 | /// Gets a boolean indicating if the operation was handled from user code. 52 | /// 53 | public bool Handled { get; private set; } 54 | 55 | /// 56 | /// Marks the operation as handled to prevent the default logic from being applied. 57 | /// 58 | public void HandleResponse() => Handled = true; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/Events/ValidateTokenContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.Owin; 9 | using Microsoft.Owin.Security; 10 | using Microsoft.Owin.Security.Provider; 11 | 12 | namespace Owin.Security.OAuth.Introspection 13 | { 14 | /// 15 | /// Allows customization of the token validation logic. 16 | /// 17 | public class ValidateTokenContext : BaseContext 18 | { 19 | public ValidateTokenContext( 20 | [NotNull] IOwinContext context, 21 | [NotNull] OAuthIntrospectionOptions options, 22 | [NotNull] AuthenticationTicket ticket) 23 | : base(context, options) 24 | { 25 | Ticket = ticket; 26 | } 27 | 28 | /// 29 | /// Gets or sets the 30 | /// created from the introspection response. 31 | /// 32 | public AuthenticationTicket Ticket { get; set; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/OAuthIntrospectionConfiguration.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | using JetBrains.Annotations; 12 | using Microsoft.IdentityModel.Protocols; 13 | using Microsoft.IdentityModel.Protocols.OpenIdConnect; 14 | using Newtonsoft.Json; 15 | 16 | namespace Owin.Security.OAuth.Introspection 17 | { 18 | /// 19 | /// Represents an OAuth2 introspection configuration. 20 | /// 21 | [JsonObject(MemberSerialization = MemberSerialization.OptIn)] 22 | public class OAuthIntrospectionConfiguration : OpenIdConnectConfiguration 23 | { 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | public OAuthIntrospectionConfiguration() 28 | : base() { } 29 | 30 | /// 31 | /// Initializes a new instance of the class. 32 | /// 33 | /// The JSON payload used to initialize the current instance. 34 | public OAuthIntrospectionConfiguration([NotNull] string json) 35 | : base(json) { } 36 | 37 | /// 38 | /// Gets or sets the introspection endpoint address. 39 | /// 40 | [JsonProperty( 41 | DefaultValueHandling = DefaultValueHandling.Ignore, 42 | NullValueHandling = NullValueHandling.Ignore, 43 | PropertyName = OAuthIntrospectionConstants.Metadata.IntrospectionEndpoint)] 44 | public string IntrospectionEndpoint { get; set; } 45 | 46 | /// 47 | /// Gets the list of authentication methods supported by the introspection endpoint. 48 | /// 49 | [JsonProperty( 50 | DefaultValueHandling = DefaultValueHandling.Ignore, 51 | NullValueHandling = NullValueHandling.Ignore, 52 | PropertyName = OAuthIntrospectionConstants.Metadata.IntrospectionEndpointAuthMethodsSupported)] 53 | public ISet IntrospectionEndpointAuthMethodsSupported { get; } = new HashSet(); 54 | 55 | /// 56 | /// Represents a configuration retriever able to deserialize 57 | /// instances. 58 | /// 59 | public class Retriever : IConfigurationRetriever 60 | { 61 | /// 62 | /// Retrieves the OAuth2 introspection configuration from the specified address. 63 | /// 64 | /// The address of the discovery document. 65 | /// The object used to retrieve the discovery document. 66 | /// The that can be used to abort the operation. 67 | /// An instance. 68 | public async Task GetConfigurationAsync( 69 | [NotNull] string address, [NotNull] IDocumentRetriever retriever, CancellationToken cancellationToken) 70 | { 71 | if (string.IsNullOrEmpty(address)) 72 | { 73 | throw new ArgumentException("The address cannot be null or empty.", nameof(address)); 74 | } 75 | 76 | if (retriever == null) 77 | { 78 | throw new ArgumentNullException(nameof(retriever)); 79 | } 80 | 81 | return new OAuthIntrospectionConfiguration(await retriever.GetDocumentAsync(address, cancellationToken)); 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/OAuthIntrospectionConstants.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace Owin.Security.OAuth.Introspection 8 | { 9 | public static class OAuthIntrospectionConstants 10 | { 11 | public static class Claims 12 | { 13 | public const string Active = "active"; 14 | public const string Audience = "aud"; 15 | public const string ExpiresAt = "exp"; 16 | public const string IssuedAt = "iat"; 17 | public const string JwtId = "jti"; 18 | public const string Name = "name"; 19 | public const string NotBefore = "nbf"; 20 | public const string Role = "role"; 21 | public const string Scope = "scope"; 22 | public const string Subject = "sub"; 23 | public const string TokenType = "token_type"; 24 | public const string TokenUsage = "token_usage"; 25 | public const string Username = "username"; 26 | } 27 | 28 | public static class ClaimValueTypes 29 | { 30 | public const string Json = "JSON"; 31 | public const string JsonArray = "JSON_ARRAY"; 32 | } 33 | 34 | public static class ClientAuthenticationMethods 35 | { 36 | public const string ClientSecretBasic = "client_secret_basic"; 37 | public const string ClientSecretPost = "client_secret_post"; 38 | } 39 | 40 | public static class Errors 41 | { 42 | public const string InsufficientScope = "insufficient_scope"; 43 | public const string InvalidRequest = "invalid_request"; 44 | public const string InvalidToken = "invalid_token"; 45 | } 46 | 47 | public static class Headers 48 | { 49 | public const string Authorization = "Authorization"; 50 | public const string WWWAuthenticate = "WWW-Authenticate"; 51 | } 52 | 53 | public static class Metadata 54 | { 55 | public const string IntrospectionEndpoint = "introspection_endpoint"; 56 | public const string IntrospectionEndpointAuthMethodsSupported = "introspection_endpoint_auth_methods_supported"; 57 | } 58 | 59 | public static class Parameters 60 | { 61 | public const string ClientId = "client_id"; 62 | public const string ClientSecret = "client_secret"; 63 | public const string Error = "error"; 64 | public const string ErrorDescription = "error_description"; 65 | public const string ErrorUri = "error_uri"; 66 | public const string Realm = "realm"; 67 | public const string Scope = "scope"; 68 | public const string Token = "token"; 69 | public const string TokenTypeHint = "token_type_hint"; 70 | } 71 | 72 | public static class Properties 73 | { 74 | public const string AccessToken = "access_token"; 75 | public const string Audiences = ".audiences"; 76 | public const string Error = ".error"; 77 | public const string ErrorDescription = ".error_description"; 78 | public const string ErrorUri = ".error_uri"; 79 | public const string Realm = ".realm"; 80 | public const string Scope = ".scope"; 81 | public const string Scopes = ".scopes"; 82 | public const string TokenId = ".token_id"; 83 | public const string TokenUsage = ".token_usage"; 84 | } 85 | 86 | public static class Schemes 87 | { 88 | public const string Basic = "Basic"; 89 | public const string Bearer = "Bearer"; 90 | } 91 | 92 | public static class Separators 93 | { 94 | public static readonly char[] Space = { ' ' }; 95 | } 96 | 97 | public static class TokenTypeHints 98 | { 99 | public const string AccessToken = "access_token"; 100 | } 101 | 102 | public static class TokenUsages 103 | { 104 | public const string AccessToken = "access_token"; 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/OAuthIntrospectionDefaults.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace Owin.Security.OAuth.Introspection 8 | { 9 | public static class OAuthIntrospectionDefaults 10 | { 11 | /// 12 | /// Gets the default scheme used by the introspection middleware. 13 | /// 14 | public const string AuthenticationScheme = "Bearer"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/OAuthIntrospectionError.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace Owin.Security.OAuth.Introspection 8 | { 9 | /// 10 | /// Represents an OAuth2 introspection error. 11 | /// 12 | public class OAuthIntrospectionError 13 | { 14 | /// 15 | /// Gets or sets the error code. 16 | /// 17 | public string Error { get; set; } 18 | 19 | /// 20 | /// Gets or sets the error_description. 21 | /// 22 | public string ErrorDescription { get; set; } 23 | 24 | /// 25 | /// Gets or sets the error_uri. 26 | /// 27 | public string ErrorUri { get; set; } 28 | 29 | /// 30 | /// Gets or sets the realm. 31 | /// 32 | public string Realm { get; set; } 33 | 34 | /// 35 | /// Gets or sets the scope. 36 | /// 37 | public string Scope { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/OAuthIntrospectionEvents.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Threading.Tasks; 9 | 10 | namespace Owin.Security.OAuth.Introspection 11 | { 12 | /// 13 | /// Allows customization of introspection handling within the middleware. 14 | /// 15 | public class OAuthIntrospectionEvents 16 | { 17 | /// 18 | /// Invoked when a challenge response is returned to the caller. 19 | /// 20 | public Func OnApplyChallenge { get; set; } = context => Task.CompletedTask; 21 | 22 | /// 23 | /// Invoked when a ticket is to be created from an introspection response. 24 | /// 25 | public Func OnCreateTicket { get; set; } = context => Task.CompletedTask; 26 | 27 | /// 28 | /// Invoked when a token is to be parsed from a newly-received request. 29 | /// 30 | public Func OnRetrieveToken { get; set; } = context => Task.CompletedTask; 31 | 32 | /// 33 | /// Invoked when a token is to be sent to the authorization server for introspection. 34 | /// 35 | public Func OnSendIntrospectionRequest { get; set; } = context => Task.CompletedTask; 36 | 37 | /// 38 | /// Invoked when a token is to be validated, before final processing. 39 | /// 40 | public Func OnValidateToken { get; set; } = context => Task.CompletedTask; 41 | 42 | /// 43 | /// Invoked when a challenge response is returned to the caller. 44 | /// 45 | public virtual Task ApplyChallenge(ApplyChallengeContext context) => OnApplyChallenge(context); 46 | 47 | /// 48 | /// Invoked when a ticket is to be created from an introspection response. 49 | /// 50 | public virtual Task CreateTicket(CreateTicketContext context) => OnCreateTicket(context); 51 | 52 | /// 53 | /// Invoked when a token is to be parsed from a newly-received request. 54 | /// 55 | public virtual Task RetrieveToken(RetrieveTokenContext context) => OnRetrieveToken(context); 56 | 57 | /// 58 | /// Invoked when a token is to be sent to the authorization server for introspection. 59 | /// 60 | public virtual Task SendIntrospectionRequest(SendIntrospectionRequestContext context) => OnSendIntrospectionRequest(context); 61 | 62 | /// 63 | /// Invoked when a token is to be validated, before final processing. 64 | /// 65 | public virtual Task ValidateToken(ValidateTokenContext context) => OnValidateToken(context); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/OAuthIntrospectionExtensions.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using JetBrains.Annotations; 9 | using Microsoft.Extensions.Logging; 10 | using Owin.Security.OAuth.Introspection; 11 | 12 | namespace Owin 13 | { 14 | /// 15 | /// Provides extension methods used to configure the OAuth2 16 | /// introspection middleware in an OWIN/Katana pipeline. 17 | /// 18 | public static class OAuthIntrospectionExtensions 19 | { 20 | /// 21 | /// Adds a new instance of the OAuth2 introspection middleware in the OWIN/Katana pipeline. 22 | /// 23 | /// The application builder. 24 | /// The delegate used to configure the introspection options. 25 | /// The application builder. 26 | public static IAppBuilder UseOAuthIntrospection( 27 | [NotNull] this IAppBuilder app, 28 | [NotNull] Action configuration) 29 | { 30 | if (app == null) 31 | { 32 | throw new ArgumentNullException(nameof(app)); 33 | } 34 | 35 | if (configuration == null) 36 | { 37 | throw new ArgumentNullException(nameof(configuration)); 38 | } 39 | 40 | var options = new OAuthIntrospectionOptions(); 41 | configuration(options); 42 | 43 | return app.UseOAuthIntrospection(options); 44 | } 45 | 46 | /// 47 | /// Adds a new instance of the OAuth2 introspection middleware in the OWIN/Katana pipeline. 48 | /// 49 | /// The application builder. 50 | /// The options used to configure the introspection middleware. 51 | /// The application builder. 52 | public static IAppBuilder UseOAuthIntrospection( 53 | [NotNull] this IAppBuilder app, 54 | [NotNull] OAuthIntrospectionOptions options) 55 | { 56 | if (app == null) 57 | { 58 | throw new ArgumentNullException(nameof(app)); 59 | } 60 | 61 | if (options == null) 62 | { 63 | throw new ArgumentNullException(nameof(options)); 64 | } 65 | 66 | return app.Use(app.Properties, options); 67 | } 68 | 69 | /// 70 | /// Configures the OAuth2 introspection middleware to enable logging. 71 | /// 72 | /// The options used to configure the OAuth2 introspection middleware. 73 | /// The delegate used to configure the logger factory. 74 | /// The options used to configure the OAuth2 introspection middleware. 75 | public static OAuthIntrospectionOptions UseLogging( 76 | [NotNull] this OAuthIntrospectionOptions options, 77 | [NotNull] Action configuration) 78 | { 79 | if (options == null) 80 | { 81 | throw new ArgumentNullException(nameof(options)); 82 | } 83 | 84 | if (configuration == null) 85 | { 86 | throw new ArgumentNullException(nameof(configuration)); 87 | } 88 | 89 | var factory = new LoggerFactory(); 90 | configuration(factory); 91 | 92 | options.Logger = factory.CreateLogger(); 93 | 94 | return options; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/OAuthIntrospectionHelpers.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using JetBrains.Annotations; 9 | using Microsoft.Owin.Security; 10 | 11 | namespace Owin.Security.OAuth.Introspection 12 | { 13 | /// 14 | /// Defines a set of commonly used helpers. 15 | /// 16 | internal static class OAuthIntrospectionHelpers 17 | { 18 | /// 19 | /// Gets a given property from the authentication properties. 20 | /// 21 | /// The authentication properties. 22 | /// The specific property to look for. 23 | /// The value corresponding to the property, or null if the property cannot be found. 24 | public static string GetProperty([NotNull] this AuthenticationProperties properties, [NotNull] string property) 25 | { 26 | if (properties == null) 27 | { 28 | throw new ArgumentNullException(nameof(properties)); 29 | } 30 | 31 | if (string.IsNullOrEmpty(property)) 32 | { 33 | throw new ArgumentException("The property name cannot be null or empty.", nameof(property)); 34 | } 35 | 36 | if (!properties.Dictionary.TryGetValue(property, out string value)) 37 | { 38 | return null; 39 | } 40 | 41 | return value; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/OAuthIntrospectionMiddleware.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Net.Http; 10 | using JetBrains.Annotations; 11 | using Microsoft.AspNetCore.DataProtection; 12 | using Microsoft.Extensions.Caching.Distributed; 13 | using Microsoft.Extensions.Caching.Memory; 14 | using Microsoft.Extensions.Logging.Abstractions; 15 | using Microsoft.Extensions.Options; 16 | using Microsoft.IdentityModel.Protocols; 17 | using Microsoft.Owin; 18 | using Microsoft.Owin.BuilderProperties; 19 | using Microsoft.Owin.Security.Infrastructure; 20 | using Microsoft.Owin.Security.Interop; 21 | 22 | namespace Owin.Security.OAuth.Introspection 23 | { 24 | /// 25 | /// Provides the entry point necessary to register the 26 | /// OAuth2 introspection handler in an OWIN/Katana pipeline. 27 | /// 28 | public class OAuthIntrospectionMiddleware : AuthenticationMiddleware 29 | { 30 | /// 31 | /// Creates a new instance of the class. 32 | /// 33 | public OAuthIntrospectionMiddleware( 34 | [NotNull] OwinMiddleware next, 35 | [NotNull] IDictionary properties, 36 | [NotNull] OAuthIntrospectionOptions options) 37 | : base(next, options) 38 | { 39 | if (string.IsNullOrEmpty(options.ClientId) || string.IsNullOrEmpty(options.ClientSecret)) 40 | { 41 | throw new ArgumentException("Client credentials must be configured.", nameof(options)); 42 | } 43 | 44 | if (Options.Events == null) 45 | { 46 | Options.Events = new OAuthIntrospectionEvents(); 47 | } 48 | 49 | if (options.DataProtectionProvider == null) 50 | { 51 | // Use the application name provided by the OWIN host as the Data Protection discriminator. 52 | // If the application name cannot be resolved, throw an invalid operation exception. 53 | var discriminator = new AppProperties(properties).AppName; 54 | if (string.IsNullOrEmpty(discriminator)) 55 | { 56 | throw new InvalidOperationException("The application name cannot be resolved from the OWIN application builder. " + 57 | "Consider manually setting the 'DataProtectionProvider' property in the " + 58 | "options using 'DataProtectionProvider.Create([unique application name])'."); 59 | } 60 | 61 | options.DataProtectionProvider = DataProtectionProvider.Create(discriminator); 62 | } 63 | 64 | if (options.AccessTokenFormat == null) 65 | { 66 | var protector = Options.DataProtectionProvider.CreateProtector( 67 | nameof(OAuthIntrospectionHandler), 68 | nameof(Options.AccessTokenFormat), Options.AuthenticationType); 69 | 70 | options.AccessTokenFormat = new AspNetTicketDataFormat(new DataProtectorShim(protector)); 71 | } 72 | 73 | if (options.Cache == null) 74 | { 75 | options.Cache = new MemoryDistributedCache(new OptionsWrapper(new MemoryDistributedCacheOptions())); 76 | } 77 | 78 | if (options.Logger == null) 79 | { 80 | options.Logger = NullLogger.Instance; 81 | } 82 | 83 | if (options.HttpClient == null) 84 | { 85 | options.HttpClient = new HttpClient 86 | { 87 | Timeout = TimeSpan.FromSeconds(15), 88 | MaxResponseContentBufferSize = 1024 * 1024 * 10 89 | }; 90 | 91 | options.HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd("OWIN OAuth2 introspection middleware"); 92 | } 93 | 94 | if (Options.ConfigurationManager == null) 95 | { 96 | if (Options.Configuration != null) 97 | { 98 | if (string.IsNullOrEmpty(Options.Configuration.IntrospectionEndpoint)) 99 | { 100 | throw new ArgumentException("The introspection endpoint address cannot be null or empty.", nameof(options)); 101 | } 102 | 103 | Options.ConfigurationManager = new StaticConfigurationManager(Options.Configuration); 104 | } 105 | 106 | else 107 | { 108 | if (Options.Authority == null && Options.MetadataAddress == null) 109 | { 110 | throw new ArgumentException("The authority or an absolute metadata endpoint address must be provided.", nameof(options)); 111 | } 112 | 113 | if (Options.MetadataAddress == null) 114 | { 115 | Options.MetadataAddress = new Uri(".well-known/openid-configuration", UriKind.Relative); 116 | } 117 | 118 | if (!Options.MetadataAddress.IsAbsoluteUri) 119 | { 120 | if (Options.Authority == null || !Options.Authority.IsAbsoluteUri) 121 | { 122 | throw new ArgumentException("The authority must be provided and must be an absolute URL.", nameof(options)); 123 | } 124 | 125 | if (!string.IsNullOrEmpty(Options.Authority.Fragment) || !string.IsNullOrEmpty(Options.Authority.Query)) 126 | { 127 | throw new ArgumentException("The authority cannot contain a fragment or a query string.", nameof(options)); 128 | } 129 | 130 | if (!Options.Authority.OriginalString.EndsWith("/")) 131 | { 132 | Options.Authority = new Uri(Options.Authority.OriginalString + "/", UriKind.Absolute); 133 | } 134 | 135 | Options.MetadataAddress = new Uri(Options.Authority, Options.MetadataAddress); 136 | } 137 | 138 | if (Options.RequireHttpsMetadata && !Options.MetadataAddress.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase)) 139 | { 140 | throw new ArgumentException("The metadata endpoint address must be a HTTPS URL when " + 141 | "'RequireHttpsMetadata' is not set to 'false'.", nameof(options)); 142 | } 143 | 144 | options.ConfigurationManager = new ConfigurationManager( 145 | options.MetadataAddress.AbsoluteUri, new OAuthIntrospectionConfiguration.Retriever(), 146 | new HttpDocumentRetriever(options.HttpClient) { RequireHttps = options.RequireHttpsMetadata }); 147 | } 148 | } 149 | } 150 | 151 | /// 152 | /// Returns a new instance. 153 | /// 154 | /// A new instance of the class. 155 | protected override AuthenticationHandler CreateHandler() 156 | { 157 | return new OAuthIntrospectionHandler(); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/OAuthIntrospectionOptions.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Net.Http; 10 | using Microsoft.AspNetCore.DataProtection; 11 | using Microsoft.Extensions.Caching.Distributed; 12 | using Microsoft.Extensions.Logging; 13 | using Microsoft.IdentityModel.Protocols; 14 | using Microsoft.Owin.Infrastructure; 15 | using Microsoft.Owin.Security; 16 | 17 | namespace Owin.Security.OAuth.Introspection 18 | { 19 | /// 20 | /// Exposes various settings needed to control 21 | /// the behavior of the introspection middleware. 22 | /// 23 | public class OAuthIntrospectionOptions : AuthenticationOptions 24 | { 25 | /// 26 | /// Creates a new instance of the class. 27 | /// 28 | public OAuthIntrospectionOptions() 29 | : base(OAuthIntrospectionDefaults.AuthenticationScheme) 30 | { 31 | AuthenticationMode = AuthenticationMode.Active; 32 | } 33 | 34 | /// 35 | /// Gets or sets the absolute URL of the OAuth2/OpenID Connect server. 36 | /// Note: this property is ignored when 37 | /// or are set. 38 | /// 39 | public Uri Authority { get; set; } 40 | 41 | /// 42 | /// Gets the intended audiences of this resource server. 43 | /// Setting this property is recommended when the authorization 44 | /// server issues access tokens for multiple distinct resource servers. 45 | /// 46 | public ISet Audiences { get; } = new HashSet(StringComparer.Ordinal); 47 | 48 | /// 49 | /// Gets or sets the URL of the OAuth2/OpenID Connect server discovery endpoint. 50 | /// When the URL is relative, must be set and absolute. 51 | /// Note: this property is ignored when 52 | /// or are set. 53 | /// 54 | public Uri MetadataAddress { get; set; } 55 | 56 | /// 57 | /// Gets or sets a boolean indicating whether HTTPS is required to retrieve the metadata document. 58 | /// The default value is true. This option should be used only in development environments. 59 | /// Note: this property is ignored when or are set. 60 | /// 61 | public bool RequireHttpsMetadata { get; set; } = true; 62 | 63 | /// 64 | /// Gets or sets the configuration used by the introspection middleware. 65 | /// Note: this property is ignored when is set. 66 | /// 67 | public OAuthIntrospectionConfiguration Configuration { get; set; } 68 | 69 | /// 70 | /// Gets or sets the configuration manager used by the introspection middleware. 71 | /// 72 | public IConfigurationManager ConfigurationManager { get; set; } 73 | 74 | /// 75 | /// Gets or sets the client identifier representing the resource server. 76 | /// 77 | public string ClientId { get; set; } 78 | 79 | /// 80 | /// Gets or sets the client secret used to 81 | /// communicate with the introspection endpoint. 82 | /// 83 | public string ClientSecret { get; set; } 84 | 85 | /// 86 | /// Gets or sets the optional "realm" value returned to 87 | /// the caller as part of the WWW-Authenticate header. 88 | /// 89 | public string Realm { get; set; } 90 | 91 | /// 92 | /// Gets or sets a boolean determining whether the access token should be stored in the 93 | /// after a successful authentication process. 94 | /// 95 | public bool SaveToken { get; set; } = true; 96 | 97 | /// 98 | /// Gets or sets a boolean determining whether the token validation errors should be returned to the caller. 99 | /// Enabled by default, this option can be disabled to prevent the introspection middleware from returning 100 | /// an error, an error_description and/or an error_uri in the WWW-Authenticate header. 101 | /// 102 | public bool IncludeErrorDetails { get; set; } = true; 103 | 104 | /// 105 | /// Gets or sets the claim type used for the name claim. 106 | /// By default, the standard 107 | /// claim defined by the OAuth2 introspection specification is used. 108 | /// 109 | public string NameClaimType { get; set; } = OAuthIntrospectionConstants.Claims.Name; 110 | 111 | /// 112 | /// Gets or sets the claim type used for the role claim(s). 113 | /// By default, is used. 114 | /// 115 | public string RoleClaimType { get; set; } = OAuthIntrospectionConstants.Claims.Role; 116 | 117 | /// 118 | /// Gets or sets the cache used to store the access tokens/authentication tickets 119 | /// and the introspection responses returned received by the resource server. 120 | /// 121 | public IDistributedCache Cache { get; set; } 122 | 123 | /// 124 | /// Gets or sets the caching policy used to determine 125 | /// how long the introspection responses should be cached. 126 | /// Note: this property can be set to null to 127 | /// prevent the introspection responses from being cached. 128 | /// 129 | public DistributedCacheEntryOptions CachingPolicy { get; set; } = new DistributedCacheEntryOptions 130 | { 131 | AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(15) 132 | }; 133 | 134 | /// 135 | /// Gets or sets the object provided by the application to process events raised by the authentication middleware. 136 | /// The application may implement the interface fully, or it may create an instance of 137 | /// and assign delegates only to the events it wants to process. 138 | /// 139 | public OAuthIntrospectionEvents Events { get; set; } = new OAuthIntrospectionEvents(); 140 | 141 | /// 142 | /// Gets or sets the HTTP client used to communicate with the remote OAuth2 server. 143 | /// 144 | public HttpClient HttpClient { get; set; } 145 | 146 | /// 147 | /// Gets or sets the logger used by the OAuth2 introspection handler. 148 | /// When unassigned, a default instance is created using the logger factory. 149 | /// 150 | public ILogger Logger { get; set; } 151 | 152 | /// 153 | /// Gets or sets the clock used to determine the current date/time. 154 | /// 155 | public ISystemClock SystemClock { get; set; } = new SystemClock(); 156 | 157 | /// 158 | /// Gets or sets the data format used to serialize and deserialize 159 | /// the authenticated tickets stored in the distributed cache. 160 | /// 161 | public ISecureDataFormat AccessTokenFormat { get; set; } 162 | 163 | /// 164 | /// Gets or sets the data protection provider used to create the default 165 | /// data protectors used by the OAuth2 introspection handler. 166 | /// 167 | public IDataProtectionProvider DataProtectionProvider { get; set; } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Introspection/Owin.Security.OAuth.Introspection.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | net461 7 | 8 | 9 | 10 | OAuth2 introspection middleware for OWIN/Katana. 11 | Kévin Chalet 12 | authentication;katana;jwt;openidconnect;owin;security 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/Events/ApplyChallengeContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.Owin; 9 | using Microsoft.Owin.Security; 10 | using Microsoft.Owin.Security.Provider; 11 | 12 | namespace Owin.Security.OAuth.Validation 13 | { 14 | /// 15 | /// Allows customization of the challenge process. 16 | /// 17 | public class ApplyChallengeContext : BaseContext 18 | { 19 | public ApplyChallengeContext( 20 | [NotNull] IOwinContext context, 21 | [NotNull] OAuthValidationOptions options, 22 | [NotNull] AuthenticationProperties properties) 23 | : base(context, options) 24 | { 25 | Properties = properties; 26 | } 27 | 28 | /// 29 | /// Gets the authentication properties associated with the challenge. 30 | /// 31 | public AuthenticationProperties Properties { get; } 32 | 33 | /// 34 | /// Gets or sets the "error" value returned to the caller as part 35 | /// of the WWW-Authenticate header. This property may be null when 36 | /// is set to false. 37 | /// 38 | public string Error { get; set; } 39 | 40 | /// 41 | /// Gets or sets the "error_description" value returned to the caller as part 42 | /// of the WWW-Authenticate header. This property may be null when 43 | /// is set to false. 44 | /// 45 | public string ErrorDescription { get; set; } 46 | 47 | /// 48 | /// Gets or sets the "error_uri" value returned to the caller as part of the 49 | /// WWW-Authenticate header. This property is always null unless explicitly set. 50 | /// 51 | public string ErrorUri { get; set; } 52 | 53 | /// 54 | /// Gets or sets the "realm" value returned to 55 | /// the caller as part of the WWW-Authenticate header. 56 | /// 57 | public string Realm { get; set; } 58 | 59 | /// 60 | /// Gets or sets the "scope" value returned to 61 | /// the caller as part of the WWW-Authenticate header. 62 | /// 63 | public string Scope { get; set; } 64 | 65 | /// 66 | /// Gets a boolean indicating if the operation was handled from user code. 67 | /// 68 | public bool Handled { get; private set; } 69 | 70 | /// 71 | /// Marks the operation as handled to prevent the default logic from being applied. 72 | /// 73 | public void HandleResponse() => Handled = true; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/Events/CreateTicketContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.Owin; 9 | using Microsoft.Owin.Security; 10 | using Microsoft.Owin.Security.Provider; 11 | 12 | namespace Owin.Security.OAuth.Validation 13 | { 14 | /// 15 | /// Allows interception of the AuthenticationTicket creation process. 16 | /// 17 | public class CreateTicketContext : BaseContext 18 | { 19 | public CreateTicketContext( 20 | [NotNull] IOwinContext context, 21 | [NotNull] OAuthValidationOptions options, 22 | [NotNull] AuthenticationTicket ticket) 23 | : base(context, options) 24 | { 25 | Ticket = ticket; 26 | } 27 | 28 | /// 29 | /// Gets or sets the created by the application. 30 | /// 31 | public AuthenticationTicket Ticket { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/Events/DecryptTokenContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.Owin; 9 | using Microsoft.Owin.Security; 10 | using Microsoft.Owin.Security.Provider; 11 | 12 | namespace Owin.Security.OAuth.Validation 13 | { 14 | /// 15 | /// Allows custom decryption of access tokens. 16 | /// 17 | public class DecryptTokenContext : BaseContext 18 | { 19 | public DecryptTokenContext( 20 | [NotNull] IOwinContext context, 21 | [NotNull] OAuthValidationOptions options, 22 | [NotNull] string token) 23 | : base(context, options) 24 | { 25 | Token = token; 26 | } 27 | 28 | /// 29 | /// Gets the access token. 30 | /// 31 | public string Token { get; } 32 | 33 | /// 34 | /// Gets or sets the data format used to deserialize the authentication ticket. 35 | /// 36 | public ISecureDataFormat DataFormat { get; set; } 37 | 38 | /// 39 | /// Gets or sets the 40 | /// extracted from the access token. 41 | /// 42 | public AuthenticationTicket Ticket { get; set; } 43 | 44 | /// 45 | /// Gets a boolean indicating if the operation was handled from user code. 46 | /// 47 | public bool Handled { get; private set; } 48 | 49 | /// 50 | /// Marks the operation as handled to prevent the default logic from being applied. 51 | /// 52 | public void HandleDecryption() => Handled = true; 53 | 54 | /// 55 | /// Marks the operation as handled to prevent the default logic from being applied. 56 | /// 57 | /// The authentication ticket to use. 58 | public void HandleDecryption(AuthenticationTicket ticket) 59 | { 60 | Ticket = ticket; 61 | Handled = true; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/Events/RetrieveTokenContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.Owin; 9 | using Microsoft.Owin.Security; 10 | using Microsoft.Owin.Security.Provider; 11 | 12 | namespace Owin.Security.OAuth.Validation 13 | { 14 | /// 15 | /// Allows custom parsing of access tokens from requests. 16 | /// 17 | public class RetrieveTokenContext : BaseContext 18 | { 19 | public RetrieveTokenContext( 20 | [NotNull] IOwinContext context, 21 | [NotNull] OAuthValidationOptions options) 22 | : base(context, options) 23 | { 24 | } 25 | 26 | /// 27 | /// Gets or sets the access token. 28 | /// 29 | public string Token { get; set; } 30 | 31 | /// 32 | /// Gets or sets the created by the application. 33 | /// 34 | public AuthenticationTicket Ticket { get; set; } 35 | 36 | /// 37 | /// Gets a boolean indicating if the operation was handled from user code. 38 | /// 39 | public bool Handled { get; private set; } 40 | 41 | /// 42 | /// Marks the operation as handled to prevent the default logic from being applied. 43 | /// 44 | public void HandleValidation() => Handled = true; 45 | 46 | /// 47 | /// Marks the operation as handled to prevent the default logic from being applied. 48 | /// 49 | /// The authentication ticket to use. 50 | public void HandleValidation(AuthenticationTicket ticket) 51 | { 52 | Ticket = ticket; 53 | Handled = true; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/Events/ValidateTokenContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using JetBrains.Annotations; 8 | using Microsoft.Owin; 9 | using Microsoft.Owin.Security; 10 | using Microsoft.Owin.Security.Provider; 11 | 12 | namespace Owin.Security.OAuth.Validation 13 | { 14 | /// 15 | /// Allows customization of the token validation logic. 16 | /// 17 | public class ValidateTokenContext : BaseContext 18 | { 19 | public ValidateTokenContext( 20 | [NotNull] IOwinContext context, 21 | [NotNull] OAuthValidationOptions options, 22 | [NotNull] AuthenticationTicket ticket) 23 | : base(context, options) 24 | { 25 | Ticket = ticket; 26 | } 27 | 28 | /// 29 | /// Gets or sets the 30 | /// extracted from the access token. 31 | /// 32 | public AuthenticationTicket Ticket { get; set; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/OAuthValidationConstants.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace Owin.Security.OAuth.Validation 8 | { 9 | public static class OAuthValidationConstants 10 | { 11 | public static class Claims 12 | { 13 | public const string Scope = "scope"; 14 | public const string Subject = "subject"; 15 | } 16 | 17 | public static class Errors 18 | { 19 | public const string InsufficientScope = "insufficient_scope"; 20 | public const string InvalidRequest = "invalid_request"; 21 | public const string InvalidToken = "invalid_token"; 22 | } 23 | 24 | public static class Headers 25 | { 26 | public const string Authorization = "Authorization"; 27 | public const string WWWAuthenticate = "WWW-Authenticate"; 28 | } 29 | 30 | public static class Parameters 31 | { 32 | public const string Error = "error"; 33 | public const string ErrorDescription = "error_description"; 34 | public const string ErrorUri = "error_uri"; 35 | public const string Realm = "realm"; 36 | public const string Scope = "scope"; 37 | } 38 | 39 | public static class Properties 40 | { 41 | public const string Audiences = ".audiences"; 42 | public const string Error = ".error"; 43 | public const string ErrorDescription = ".error_description"; 44 | public const string ErrorUri = ".error_uri"; 45 | public const string Realm = ".realm"; 46 | public const string Scope = ".scope"; 47 | public const string Scopes = ".scopes"; 48 | public const string Token = "access_token"; 49 | } 50 | 51 | public static class Schemes 52 | { 53 | public const string Bearer = "Bearer"; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/OAuthValidationDefaults.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace Owin.Security.OAuth.Validation 8 | { 9 | public static class OAuthValidationDefaults 10 | { 11 | /// 12 | /// Gets the default scheme used by the validation middleware. 13 | /// 14 | public const string AuthenticationScheme = "Bearer"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/OAuthValidationError.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | namespace Owin.Security.OAuth.Validation 8 | { 9 | /// 10 | /// Represents an OAuth2 validation error. 11 | /// 12 | public class OAuthValidationError 13 | { 14 | /// 15 | /// Gets or sets the error code. 16 | /// 17 | public string Error { get; set; } 18 | 19 | /// 20 | /// Gets or sets the error_description. 21 | /// 22 | public string ErrorDescription { get; set; } 23 | 24 | /// 25 | /// Gets or sets the error_uri. 26 | /// 27 | public string ErrorUri { get; set; } 28 | 29 | /// 30 | /// Gets or sets the realm. 31 | /// 32 | public string Realm { get; set; } 33 | 34 | /// 35 | /// Gets or sets the scope. 36 | /// 37 | public string Scope { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/OAuthValidationEvents.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Threading.Tasks; 9 | 10 | namespace Owin.Security.OAuth.Validation 11 | { 12 | /// 13 | /// Allows customization of validation handling within the middleware. 14 | /// 15 | public class OAuthValidationEvents 16 | { 17 | /// 18 | /// Invoked when a challenge response is returned to the caller. 19 | /// 20 | public Func OnApplyChallenge { get; set; } = context => Task.CompletedTask; 21 | 22 | /// 23 | /// Invoked when a ticket is to be created from an access token. 24 | /// 25 | public Func OnCreateTicket { get; set; } = context => Task.CompletedTask; 26 | 27 | /// 28 | /// Invoked when a token is to be decrypted. 29 | /// 30 | public Func OnDecryptToken { get; set; } = context => Task.CompletedTask; 31 | 32 | /// 33 | /// Invoked when a token is to be parsed from a newly-received request. 34 | /// 35 | public Func OnRetrieveToken { get; set; } = context => Task.CompletedTask; 36 | 37 | /// 38 | /// Invoked when a token is to be validated, before final processing. 39 | /// 40 | public Func OnValidateToken { get; set; } = context => Task.CompletedTask; 41 | 42 | /// 43 | /// Invoked when a challenge response is returned to the caller. 44 | /// 45 | public virtual Task ApplyChallenge(ApplyChallengeContext context) => OnApplyChallenge(context); 46 | 47 | /// 48 | /// Invoked when a ticket is to be created from an access token. 49 | /// 50 | public virtual Task CreateTicket(CreateTicketContext context) => OnCreateTicket(context); 51 | 52 | /// 53 | /// Invoked when a token is to be decrypted. 54 | /// 55 | public virtual Task DecryptToken(DecryptTokenContext context) => OnDecryptToken(context); 56 | 57 | /// 58 | /// Invoked when a token is to be parsed from a newly-received request. 59 | /// 60 | public virtual Task RetrieveToken(RetrieveTokenContext context) => OnRetrieveToken(context); 61 | 62 | /// 63 | /// Invoked when a token is to be validated, before final processing. 64 | /// 65 | public virtual Task ValidateToken(ValidateTokenContext context) => OnValidateToken(context); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/OAuthValidationExtensions.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using JetBrains.Annotations; 9 | using Microsoft.Extensions.Logging; 10 | using Owin.Security.OAuth.Validation; 11 | 12 | namespace Owin 13 | { 14 | /// 15 | /// Provides extension methods used to configure the OAuth2 16 | /// validation middleware in an OWIN/Katana pipeline. 17 | /// 18 | public static class OAuthValidationExtensions 19 | { 20 | /// 21 | /// Adds a new instance of the OAuth2 validation middleware in the OWIN/Katana pipeline. 22 | /// 23 | /// The application builder. 24 | /// The application builder. 25 | public static IAppBuilder UseOAuthValidation([NotNull] this IAppBuilder app) 26 | { 27 | if (app == null) 28 | { 29 | throw new ArgumentNullException(nameof(app)); 30 | } 31 | 32 | return app.UseOAuthValidation(options => { }); 33 | } 34 | 35 | /// 36 | /// Adds a new instance of the OAuth2 validation middleware in the OWIN/Katana pipeline. 37 | /// 38 | /// The application builder. 39 | /// The delegate used to configure the validation options. 40 | /// The application builder. 41 | public static IAppBuilder UseOAuthValidation( 42 | [NotNull] this IAppBuilder app, 43 | [NotNull] Action configuration) 44 | { 45 | if (app == null) 46 | { 47 | throw new ArgumentNullException(nameof(app)); 48 | } 49 | 50 | if (configuration == null) 51 | { 52 | throw new ArgumentNullException(nameof(configuration)); 53 | } 54 | 55 | var options = new OAuthValidationOptions(); 56 | configuration(options); 57 | 58 | return app.UseOAuthValidation(options); 59 | } 60 | 61 | /// 62 | /// Adds a new instance of the OAuth2 validation middleware in the OWIN/Katana pipeline. 63 | /// 64 | /// The application builder. 65 | /// The options used to configure the validation middleware. 66 | /// The application builder. 67 | public static IAppBuilder UseOAuthValidation( 68 | [NotNull] this IAppBuilder app, 69 | [NotNull] OAuthValidationOptions options) 70 | { 71 | if (app == null) 72 | { 73 | throw new ArgumentNullException(nameof(app)); 74 | } 75 | 76 | if (options == null) 77 | { 78 | throw new ArgumentNullException(nameof(options)); 79 | } 80 | 81 | return app.Use(app.Properties, options); 82 | } 83 | 84 | /// 85 | /// Configures the OAuth2 validation middleware to enable logging. 86 | /// 87 | /// The options used to configure the OAuth2 validation middleware. 88 | /// The delegate used to configure the logger factory. 89 | /// The options used to configure the OAuth2 validation middleware. 90 | public static OAuthValidationOptions UseLogging( 91 | [NotNull] this OAuthValidationOptions options, 92 | [NotNull] Action configuration) 93 | { 94 | if (options == null) 95 | { 96 | throw new ArgumentNullException(nameof(options)); 97 | } 98 | 99 | if (configuration == null) 100 | { 101 | throw new ArgumentNullException(nameof(configuration)); 102 | } 103 | 104 | var factory = new LoggerFactory(); 105 | configuration(factory); 106 | 107 | options.Logger = factory.CreateLogger(); 108 | 109 | return options; 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/OAuthValidationHelpers.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using JetBrains.Annotations; 9 | using Microsoft.Owin.Security; 10 | 11 | namespace Owin.Security.OAuth.Validation 12 | { 13 | /// 14 | /// Defines a set of commonly used helpers. 15 | /// 16 | internal static class OAuthValidationHelpers 17 | { 18 | /// 19 | /// Gets a given property from the authentication properties. 20 | /// 21 | /// The authentication properties. 22 | /// The specific property to look for. 23 | /// The value corresponding to the property, or null if the property cannot be found. 24 | public static string GetProperty([NotNull] this AuthenticationProperties properties, [NotNull] string property) 25 | { 26 | if (properties == null) 27 | { 28 | throw new ArgumentNullException(nameof(properties)); 29 | } 30 | 31 | if (string.IsNullOrEmpty(property)) 32 | { 33 | throw new ArgumentException("The property name cannot be null or empty.", nameof(property)); 34 | } 35 | 36 | if (!properties.Dictionary.TryGetValue(property, out string value)) 37 | { 38 | return null; 39 | } 40 | 41 | return value; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/OAuthValidationMiddleware.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using JetBrains.Annotations; 10 | using Microsoft.AspNetCore.DataProtection; 11 | using Microsoft.Extensions.Logging.Abstractions; 12 | using Microsoft.Owin; 13 | using Microsoft.Owin.BuilderProperties; 14 | using Microsoft.Owin.Security.Infrastructure; 15 | using Microsoft.Owin.Security.Interop; 16 | 17 | namespace Owin.Security.OAuth.Validation 18 | { 19 | /// 20 | /// Provides the entry point necessary to register the 21 | /// OAuth2 validation handler in an OWIN/Katana pipeline. 22 | /// 23 | public class OAuthValidationMiddleware : AuthenticationMiddleware 24 | { 25 | /// 26 | /// Creates a new instance of the class. 27 | /// 28 | public OAuthValidationMiddleware( 29 | [NotNull] OwinMiddleware next, 30 | [NotNull] IDictionary properties, 31 | [NotNull] OAuthValidationOptions options) 32 | : base(next, options) 33 | { 34 | if (Options.Events == null) 35 | { 36 | Options.Events = new OAuthValidationEvents(); 37 | } 38 | 39 | if (options.DataProtectionProvider == null) 40 | { 41 | // Use the application name provided by the OWIN host as the Data Protection discriminator. 42 | // If the application name cannot be resolved, throw an invalid operation exception. 43 | var discriminator = new AppProperties(properties).AppName; 44 | if (string.IsNullOrEmpty(discriminator)) 45 | { 46 | throw new InvalidOperationException("The application name cannot be resolved from the OWIN application builder. " + 47 | "Consider manually setting the 'DataProtectionProvider' property in the " + 48 | "options using 'DataProtectionProvider.Create([unique application name])'."); 49 | } 50 | 51 | options.DataProtectionProvider = DataProtectionProvider.Create(discriminator); 52 | } 53 | 54 | if (options.AccessTokenFormat == null) 55 | { 56 | // Note: the following purposes must match the ones used by the OpenID Connect server middleware. 57 | var protector = Options.DataProtectionProvider.CreateProtector( 58 | "OpenIdConnectServerHandler", nameof(Options.AccessTokenFormat), "ASOS"); 59 | 60 | options.AccessTokenFormat = new AspNetTicketDataFormat(new DataProtectorShim(protector)); 61 | } 62 | 63 | if (options.Logger == null) 64 | { 65 | options.Logger = NullLogger.Instance; 66 | } 67 | } 68 | 69 | /// 70 | /// Returns a new instance. 71 | /// 72 | /// A new instance of the class. 73 | protected override AuthenticationHandler CreateHandler() 74 | { 75 | return new OAuthValidationHandler(); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/OAuthValidationOptions.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using Microsoft.AspNetCore.DataProtection; 10 | using Microsoft.Extensions.Logging; 11 | using Microsoft.Owin.Infrastructure; 12 | using Microsoft.Owin.Security; 13 | 14 | namespace Owin.Security.OAuth.Validation 15 | { 16 | /// 17 | /// Exposes various settings needed to control 18 | /// the behavior of the validation middleware. 19 | /// 20 | public class OAuthValidationOptions : AuthenticationOptions 21 | { 22 | /// 23 | /// Creates a new instance of the class. 24 | /// 25 | public OAuthValidationOptions() 26 | : base(OAuthValidationDefaults.AuthenticationScheme) 27 | { 28 | AuthenticationMode = AuthenticationMode.Active; 29 | } 30 | 31 | /// 32 | /// Gets the intended audiences of this resource server. 33 | /// Setting this property is recommended when the authorization 34 | /// server issues access tokens for multiple distinct resource servers. 35 | /// 36 | public ISet Audiences { get; } = new HashSet(StringComparer.Ordinal); 37 | 38 | /// 39 | /// Gets or sets the optional "realm" value returned to 40 | /// the caller as part of the WWW-Authenticate header. 41 | /// 42 | public string Realm { get; set; } 43 | 44 | /// 45 | /// Gets or sets a boolean determining whether the access token should be stored in the 46 | /// after a successful authentication process. 47 | /// 48 | public bool SaveToken { get; set; } = true; 49 | 50 | /// 51 | /// Gets or sets a boolean determining whether the token validation errors should be returned to the caller. 52 | /// Enabled by default, this option can be disabled to prevent the validation middleware from returning 53 | /// an error, an error_description and/or an error_uri in the WWW-Authenticate header. 54 | /// 55 | public bool IncludeErrorDetails { get; set; } = true; 56 | 57 | /// 58 | /// Gets or sets the logger used by the OAuth2 validation handler. 59 | /// When unassigned, a default instance is created using the logger factory. 60 | /// 61 | public ILogger Logger { get; set; } 62 | 63 | /// 64 | /// Gets or sets the clock used to determine the current date/time. 65 | /// 66 | public ISystemClock SystemClock { get; set; } = new SystemClock(); 67 | 68 | /// 69 | /// Gets or sets the data format used to unprotect the 70 | /// access tokens received by the validation middleware. 71 | /// 72 | public ISecureDataFormat AccessTokenFormat { get; set; } 73 | 74 | /// 75 | /// Gets or sets the data protection provider used to create the default 76 | /// data protector used by the OAuth2 validation handler. 77 | /// 78 | public IDataProtectionProvider DataProtectionProvider { get; set; } 79 | 80 | /// 81 | /// Gets or sets the object provided by the application to process events raised by the authentication middleware. 82 | /// The application may implement the interface fully, or it may create an instance of 83 | /// and assign delegates only to the events it wants to process. 84 | /// 85 | public OAuthValidationEvents Events { get; set; } = new OAuthValidationEvents(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Owin.Security.OAuth.Validation/Owin.Security.OAuth.Validation.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | net461 7 | 8 | 9 | 10 | OAuth2 validation middleware for OWIN/Katana. 11 | Kévin Chalet 12 | authentication;katana;jwt;openidconnect;owin;security 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /test/AspNet.Security.OAuth.Introspection.Tests/AspNet.Security.OAuth.Introspection.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | netcoreapp2.0;net461 7 | netcoreapp2.0 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/AspNet.Security.OAuth.Introspection.Tests/OAuthIntrospectionInitializerTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Threading.Tasks; 9 | using Microsoft.AspNetCore.Authentication; 10 | using Microsoft.AspNetCore.Builder; 11 | using Microsoft.AspNetCore.DataProtection; 12 | using Microsoft.AspNetCore.Hosting; 13 | using Microsoft.AspNetCore.TestHost; 14 | using Microsoft.Extensions.DependencyInjection; 15 | using Microsoft.Extensions.Logging; 16 | using Xunit; 17 | 18 | namespace AspNet.Security.OAuth.Introspection.Tests 19 | { 20 | public class OAuthIntrospectionInitializerTests 21 | { 22 | [Theory] 23 | [InlineData(null, null)] 24 | [InlineData("", "")] 25 | [InlineData("client_id", null)] 26 | [InlineData("client_id", "")] 27 | [InlineData(null, "client_secret")] 28 | [InlineData("", "client_secret")] 29 | public async Task PostConfigure_ThrowsAnExceptionForMissingCredentials(string identifier, string secret) 30 | { 31 | // Arrange 32 | var server = CreateResourceServer(options => 33 | { 34 | options.Authority = new Uri("http://www.fabrikam.com/"); 35 | options.ClientId = identifier; 36 | options.ClientSecret = secret; 37 | options.RequireHttpsMetadata = false; 38 | }); 39 | 40 | var client = server.CreateClient(); 41 | 42 | // Act and assert 43 | var exception = await Assert.ThrowsAsync(delegate 44 | { 45 | return client.GetAsync("/"); 46 | }); 47 | 48 | Assert.Equal("Client credentials must be configured.", exception.Message); 49 | } 50 | 51 | [Fact] 52 | public async Task PostConfigure_ThrowsAnExceptionForMissingEndpoint() 53 | { 54 | // Arrange 55 | var server = CreateResourceServer(options => 56 | { 57 | options.Configuration = new OAuthIntrospectionConfiguration 58 | { 59 | IntrospectionEndpoint = null 60 | }; 61 | }); 62 | 63 | var client = server.CreateClient(); 64 | 65 | // Act and assert 66 | var exception = await Assert.ThrowsAsync(delegate 67 | { 68 | return client.GetAsync("/"); 69 | }); 70 | 71 | Assert.Equal("The introspection endpoint address cannot be null or empty.", exception.Message); 72 | } 73 | 74 | [Fact] 75 | public async Task PostConfigure_ThrowsAnExceptionForMissingAuthority() 76 | { 77 | // Arrange 78 | var server = CreateResourceServer(options => 79 | { 80 | options.Authority = null; 81 | options.MetadataAddress = null; 82 | }); 83 | 84 | var client = server.CreateClient(); 85 | 86 | // Act and assert 87 | var exception = await Assert.ThrowsAsync(delegate 88 | { 89 | return client.GetAsync("/"); 90 | }); 91 | 92 | Assert.Equal("The authority or an absolute metadata endpoint address must be provided.", exception.Message); 93 | } 94 | 95 | [Fact] 96 | public async Task PostConfigure_ThrowsAnExceptionForRelativeAuthority() 97 | { 98 | // Arrange 99 | var server = CreateResourceServer(options => 100 | { 101 | options.Authority = new Uri("/relative-path", UriKind.Relative); 102 | }); 103 | 104 | var client = server.CreateClient(); 105 | 106 | // Act and assert 107 | var exception = await Assert.ThrowsAsync(delegate 108 | { 109 | return client.GetAsync("/"); 110 | }); 111 | 112 | Assert.Equal("The authority must be provided and must be an absolute URL.", exception.Message); 113 | } 114 | 115 | [Theory] 116 | [InlineData("http://www.fabrikam.com/path?param=value")] 117 | [InlineData("http://www.fabrikam.com/path#param=value")] 118 | public async Task PostConfigure_ThrowsAnExceptionForInvalidAuthority(string authority) 119 | { 120 | // Arrange 121 | var server = CreateResourceServer(options => 122 | { 123 | options.Authority = new Uri(authority); 124 | }); 125 | 126 | var client = server.CreateClient(); 127 | 128 | // Act and assert 129 | var exception = await Assert.ThrowsAsync(delegate 130 | { 131 | return client.GetAsync("/"); 132 | }); 133 | 134 | Assert.Equal("The authority cannot contain a fragment or a query string.", exception.Message); 135 | } 136 | 137 | [Fact] 138 | public async Task PostConfigure_ThrowsAnExceptionForNonHttpsAuthority() 139 | { 140 | // Arrange 141 | var server = CreateResourceServer(options => 142 | { 143 | options.Authority = new Uri("http://www.fabrikam.com/"); 144 | options.RequireHttpsMetadata = true; 145 | }); 146 | 147 | var client = server.CreateClient(); 148 | 149 | // Act and assert 150 | var exception = await Assert.ThrowsAsync(delegate 151 | { 152 | return client.GetAsync("/"); 153 | }); 154 | 155 | Assert.Equal("The metadata endpoint address must be a HTTPS URL when " + 156 | "'RequireHttpsMetadata' is not set to 'false'.", exception.Message); 157 | } 158 | 159 | private static TestServer CreateResourceServer(Action configuration = null) 160 | { 161 | var builder = new WebHostBuilder(); 162 | builder.UseEnvironment("Testing"); 163 | 164 | builder.ConfigureLogging(options => options.AddDebug()); 165 | 166 | builder.ConfigureServices(services => 167 | { 168 | services.AddDistributedMemoryCache(); 169 | 170 | services.AddAuthentication() 171 | .AddOAuthIntrospection(options => 172 | { 173 | options.ClientId = "Fabrikam"; 174 | options.ClientSecret = "B4657E03-D619"; 175 | 176 | // Note: overriding the default data protection provider is not necessary for the tests to pass, 177 | // but is useful to ensure unnecessary keys are not persisted in testing environments, which also 178 | // helps make the unit tests run faster, as no registry or disk access is required in this case. 179 | options.DataProtectionProvider = new EphemeralDataProtectionProvider(new LoggerFactory()); 180 | 181 | // Run the configuration delegate 182 | // registered by the unit tests. 183 | configuration?.Invoke(options); 184 | }); 185 | }); 186 | 187 | builder.Configure(app => 188 | { 189 | app.Run(context => context.ChallengeAsync(OAuthIntrospectionDefaults.AuthenticationScheme)); 190 | }); 191 | 192 | return new TestServer(builder); 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /test/AspNet.Security.OAuth.Validation.Tests/AspNet.Security.OAuth.Validation.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | netcoreapp2.0;net461 7 | netcoreapp2.0 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/Owin.Security.OAuth.Introspection.Tests/OAuthIntrospectionMiddlewareTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Reflection; 9 | using Microsoft.AspNetCore.DataProtection; 10 | using Microsoft.Extensions.Logging; 11 | using Microsoft.Owin.BuilderProperties; 12 | using Microsoft.Owin.Testing; 13 | using Xunit; 14 | 15 | namespace Owin.Security.OAuth.Introspection.Tests 16 | { 17 | public class OAuthIntrospectionMiddlewareTests 18 | { 19 | [Theory] 20 | [InlineData(null, null)] 21 | [InlineData("", "")] 22 | [InlineData("client_id", null)] 23 | [InlineData("client_id", "")] 24 | [InlineData(null, "client_secret")] 25 | [InlineData("", "client_secret")] 26 | public void Constructor_ThrowsAnExceptionForMissingCredentials(string identifier, string secret) 27 | { 28 | // Arrange, act, assert 29 | var exception = Assert.Throws(() => CreateResourceServer(options => 30 | { 31 | options.Authority = new Uri("http://www.fabrikam.com/"); 32 | options.ClientId = identifier; 33 | options.ClientSecret = secret; 34 | options.RequireHttpsMetadata = false; 35 | })); 36 | 37 | Assert.IsType(exception.InnerException); 38 | Assert.Equal("options", ((ArgumentException) exception.InnerException).ParamName); 39 | Assert.StartsWith("Client credentials must be configured.", exception.InnerException.Message); 40 | } 41 | 42 | [Theory] 43 | [InlineData(null)] 44 | [InlineData("")] 45 | public void Constructor_ThrowsAnExceptionForMissingAppName(string name) 46 | { 47 | // Arrange, act, assert 48 | var exception = Assert.Throws(() => TestServer.Create(app => 49 | { 50 | var properties = new AppProperties(app.Properties); 51 | properties.AppName = name; 52 | 53 | app.UseOAuthIntrospection(options => 54 | { 55 | options.Authority = new Uri("http://www.fabrikam.com/"); 56 | options.ClientId = "Fabrikam"; 57 | options.ClientSecret = "B4657E03-D619"; 58 | options.RequireHttpsMetadata = false; 59 | }); 60 | })); 61 | 62 | Assert.IsType(exception.InnerException); 63 | Assert.StartsWith("The application name cannot be resolved from the OWIN application builder. " + 64 | "Consider manually setting the 'DataProtectionProvider' property in the " + 65 | "options using 'DataProtectionProvider.Create([unique application name])'.", 66 | exception.InnerException.Message); 67 | } 68 | 69 | [Fact] 70 | public void Constructor_ThrowsAnExceptionForMissingEndpoint() 71 | { 72 | // Arrange, act, assert 73 | var exception = Assert.Throws(() => CreateResourceServer(options => 74 | { 75 | options.Configuration = new OAuthIntrospectionConfiguration 76 | { 77 | IntrospectionEndpoint = null 78 | }; 79 | })); 80 | 81 | Assert.IsType(exception.InnerException); 82 | Assert.Equal("options", ((ArgumentException) exception.InnerException).ParamName); 83 | Assert.StartsWith("The introspection endpoint address cannot be null or empty.", exception.InnerException.Message); 84 | } 85 | 86 | [Fact] 87 | public void Constructor_ThrowsAnExceptionForMissingAuthority() 88 | { 89 | // Arrange, act, assert 90 | var exception = Assert.Throws(() => CreateResourceServer(options => 91 | { 92 | options.Authority = null; 93 | options.MetadataAddress = null; 94 | })); 95 | 96 | Assert.IsType(exception.InnerException); 97 | Assert.Equal("options", ((ArgumentException) exception.InnerException).ParamName); 98 | Assert.StartsWith("The authority or an absolute metadata endpoint address must be provided.", exception.InnerException.Message); 99 | } 100 | 101 | [Fact] 102 | public void Constructor_ThrowsAnExceptionForRelativeAuthority() 103 | { 104 | // Arrange, act, assert 105 | var exception = Assert.Throws(() => CreateResourceServer(options => 106 | { 107 | options.Authority = new Uri("/relative-path", UriKind.Relative); 108 | })); 109 | 110 | Assert.IsType(exception.InnerException); 111 | Assert.Equal("options", ((ArgumentException) exception.InnerException).ParamName); 112 | Assert.StartsWith("The authority must be provided and must be an absolute URL.", exception.InnerException.Message); 113 | } 114 | 115 | [Theory] 116 | [InlineData("http://www.fabrikam.com/path?param=value")] 117 | [InlineData("http://www.fabrikam.com/path#param=value")] 118 | public void Constructor_ThrowsAnExceptionForInvalidAuthority(string authority) 119 | { 120 | // Arrange, act, assert 121 | var exception = Assert.Throws(() => CreateResourceServer(options => 122 | { 123 | options.Authority = new Uri(authority); 124 | })); 125 | 126 | Assert.IsType(exception.InnerException); 127 | Assert.Equal("options", ((ArgumentException) exception.InnerException).ParamName); 128 | Assert.StartsWith("The authority cannot contain a fragment or a query string.", exception.InnerException.Message); 129 | } 130 | 131 | [Fact] 132 | public void Constructor_ThrowsAnExceptionForNonHttpsAuthority() 133 | { 134 | // Arrange, act, assert 135 | var exception = Assert.Throws(() => CreateResourceServer(options => 136 | { 137 | options.Authority = new Uri("http://www.fabrikam.com/"); 138 | options.RequireHttpsMetadata = true; 139 | })); 140 | 141 | Assert.IsType(exception.InnerException); 142 | Assert.Equal("options", ((ArgumentException) exception.InnerException).ParamName); 143 | Assert.StartsWith("The metadata endpoint address must be a HTTPS URL when " + 144 | "'RequireHttpsMetadata' is not set to 'false'.", exception.InnerException.Message); 145 | } 146 | 147 | private static TestServer CreateResourceServer(Action configuration = null) 148 | { 149 | return TestServer.Create(app => 150 | { 151 | app.UseOAuthIntrospection(options => 152 | { 153 | options.Authority = new Uri("http://www.fabrikam.com/"); 154 | options.RequireHttpsMetadata = false; 155 | 156 | options.ClientId = "Fabrikam"; 157 | options.ClientSecret = "B4657E03-D619"; 158 | 159 | // Note: overriding the default data protection provider is not necessary for the tests to pass, 160 | // but is useful to ensure unnecessary keys are not persisted in testing environments, which also 161 | // helps make the unit tests run faster, as no registry or disk access is required in this case. 162 | options.DataProtectionProvider = new EphemeralDataProtectionProvider(new LoggerFactory()); 163 | 164 | // Run the configuration delegate 165 | // registered by the unit tests. 166 | configuration?.Invoke(options); 167 | }); 168 | }); 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /test/Owin.Security.OAuth.Introspection.Tests/Owin.Security.OAuth.Introspection.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | net461 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/Owin.Security.OAuth.Validation.Tests/OAuthValidationMiddlewareTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 3 | * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Extensions for more information 4 | * concerning the license and the contributors participating to this project. 5 | */ 6 | 7 | using System; 8 | using System.Reflection; 9 | using Microsoft.Owin.BuilderProperties; 10 | using Microsoft.Owin.Testing; 11 | using Xunit; 12 | 13 | namespace Owin.Security.OAuth.Validation.Tests 14 | { 15 | public class OAuthValidationMiddlewareTests 16 | { 17 | [Theory] 18 | [InlineData(null)] 19 | [InlineData("")] 20 | public void Constructor_ThrowsAnExceptionForMissingAppName(string name) 21 | { 22 | // Arrange, act, assert 23 | var exception = Assert.Throws(() => TestServer.Create(app => 24 | { 25 | var properties = new AppProperties(app.Properties); 26 | properties.AppName = name; 27 | 28 | app.UseOAuthValidation(); 29 | })); 30 | 31 | Assert.IsType(exception.InnerException); 32 | Assert.StartsWith("The application name cannot be resolved from the OWIN application builder. " + 33 | "Consider manually setting the 'DataProtectionProvider' property in the " + 34 | "options using 'DataProtectionProvider.Create([unique application name])'.", 35 | exception.InnerException.Message); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/Owin.Security.OAuth.Validation.Tests/Owin.Security.OAuth.Validation.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | net461 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | --------------------------------------------------------------------------------