Merge remote-tracking branch 'Security/rybrande/masterToSrc' into rybrande/Mondo22ToMaster

This commit is contained in:
Ryan Brandenburg 2018-11-26 12:35:26 -08:00
commit 7aefd16eed
85 changed files with 2509 additions and 3291 deletions

View File

@ -30,3 +30,4 @@ project.lock.json
/.vs/
.vscode/
global.json
BenchmarkDotNet.Artifacts/

View File

@ -1,10 +1,6 @@
<Project>
<PropertyGroup>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">$(MicrosoftNETCoreApp20PackageVersion)</RuntimeFrameworkVersion>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">$(MicrosoftNETCoreApp21PackageVersion)</RuntimeFrameworkVersion>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.2' ">$(MicrosoftNETCoreApp22PackageVersion)</RuntimeFrameworkVersion>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp3.0' ">$(MicrosoftNETCoreAppPackageVersion)</RuntimeFrameworkVersion>
<NETStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard2.0' ">$(NETStandardLibrary20PackageVersion)</NETStandardImplicitPackageVersion>
<!-- aspnet/BuildTools#662 Don't police what version of NetCoreApp we use -->
<NETCoreAppMaximumVersion>99.9</NETCoreAppMaximumVersion>
</PropertyGroup>
</Project>

View File

@ -1,9 +1,7 @@
ASP.NET Security
========
ASP.NET Security [Archived]
===========================
AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/fujhh8n956v5ohfd/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/Security/branch/dev)
Travis: [![Travis](https://travis-ci.org/aspnet/Security.svg?branch=dev)](https://travis-ci.org/aspnet/Security)
**This GitHub project has been archived.** Ongoing development on this project can be found in <https://github.com/aspnet/AspNetCore>.
Contains the security and authorization middlewares for ASP.NET Core.
@ -14,4 +12,4 @@ A list of community projects related to authentication and security for ASP.NET
ASP.NET Security will not include Basic Authentication middleware due to its potential insecurity and performance problems. If you host under IIS you can enable it via IIS configuration.
This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo.
This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [AspNetCore](https://github.com/aspnet/AspNetCore) repo.

View File

@ -79,6 +79,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authen
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WsFedSample", "samples\WsFedSample\WsFedSample.csproj", "{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{55052FE3-F8C2-4E6C-97B0-C02ED1DBEA62}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Security.Performance", "benchmarks\Microsoft.AspNetCore.Security.Performance\Microsoft.AspNetCore.Security.Performance.csproj", "{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -517,6 +521,22 @@ Global
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|x64.Build.0 = Release|Any CPU
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|x86.ActiveCfg = Release|Any CPU
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|x86.Build.0 = Release|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|x64.ActiveCfg = Debug|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|x64.Build.0 = Debug|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|x86.ActiveCfg = Debug|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Debug|x86.Build.0 = Debug|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|Any CPU.Build.0 = Release|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|x64.ActiveCfg = Release|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|x64.Build.0 = Release|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|x86.ActiveCfg = Release|Any CPU
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -549,6 +569,7 @@ Global
{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
{5EC2E398-E46A-430D-8E4B-E91C8FC3E800} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
{556C4FAA-F4B1-4EA9-8921-CB1DF7D94C2A} = {55052FE3-F8C2-4E6C-97B0-C02ED1DBEA62}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {ABF8089E-43D0-4010-84A7-7A9DCFE49357}

View File

@ -0,0 +1,53 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Security
{
public class AuthorizationMiddlewareBenchmark
{
private AuthorizationMiddleware _authorizationMiddleware;
private DefaultHttpContext _httpContextNoEndpoint;
private DefaultHttpContext _httpContextHasEndpoint;
[GlobalSetup]
public void Setup()
{
var policyProvider = new DefaultAuthorizationPolicyProvider(Options.Create(new AuthorizationOptions()));
_authorizationMiddleware = new AuthorizationMiddleware((context) => Task.CompletedTask, policyProvider);
_httpContextNoEndpoint = new DefaultHttpContext();
var feature = new EndpointFeature
{
Endpoint = new Endpoint((context) => Task.CompletedTask, EndpointMetadataCollection.Empty, "Test endpoint")
};
_httpContextHasEndpoint = new DefaultHttpContext();
_httpContextHasEndpoint.Features.Set<IEndpointFeature>(feature);
}
[Benchmark]
public Task Invoke_NoEndpoint_NoAuthorization()
{
return _authorizationMiddleware.Invoke(_httpContextNoEndpoint);
}
[Benchmark]
public Task Invoke_HasEndpoint_NoAuthorization()
{
return _authorizationMiddleware.Invoke(_httpContextHasEndpoint);
}
private class EndpointFeature : IEndpointFeature
{
public Endpoint Endpoint { get; set; }
}
}
}

View File

@ -0,0 +1,28 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Security
{
public class AuthorizationPolicyBenchmark
{
private DefaultAuthorizationPolicyProvider _policyProvider;
[GlobalSetup]
public void Setup()
{
_policyProvider = new DefaultAuthorizationPolicyProvider(Options.Create(new AuthorizationOptions()));
}
[Benchmark]
public Task CombineAsync()
{
return AuthorizationPolicy.CombineAsync(_policyProvider, Array.Empty<IAuthorizeData>());
}
}
}

View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<OutputType>Exe</OutputType>
<ServerGarbageCollection>true</ServerGarbageCollection>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPackable>false</IsPackable>
<RootNamespace>Microsoft.AspNetCore.Security</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authorization.Policy\Microsoft.AspNetCore.Authorization.Policy.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNetPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.BenchmarkRunner.Sources" PrivateAssets="All" Version="$(MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="$(MicrosoftAspNetCoreHttpPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsDependencyInjectionPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsLoggingPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1 @@
[assembly: BenchmarkDotNet.Attributes.AspNetCoreBenchmark]

View File

@ -0,0 +1,16 @@
Compile the solution in Release mode (so binaries are available in release)
To run a specific benchmark add it as parameter.
```
dotnet run -c Release --framework <tfm> <benchmark_name>
```
To run all benchmarks use '*' as the name.
```
dotnet run -c Release --framework <tfm> *
```
If you run without any parameters, you'll be offered the list of all benchmarks and get to choose.
```
dotnet run -c Release --framework <tfm>
```

View File

@ -3,50 +3,54 @@
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>
<PropertyGroup Label="Package Versions">
<InternalAspNetCoreSdkPackageVersion>2.2.0-preview2-20181004.6</InternalAspNetCoreSdkPackageVersion>
<MicrosoftAspNetCoreAuthenticationAbstractionsPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreAuthenticationAbstractionsPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreDataProtectionExtensionsPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreDataProtectionExtensionsPackageVersion>
<MicrosoftAspNetCoreDataProtectionPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreDataProtectionPackageVersion>
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreDiagnosticsPackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
<MicrosoftAspNetCoreHttpPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreHttpPackageVersion>
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
<MicrosoftAspNetCoreServerKestrelHttpsPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreServerKestrelHttpsPackageVersion>
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreServerKestrelPackageVersion>
<MicrosoftAspNetCoreStaticFilesPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreStaticFilesPackageVersion>
<MicrosoftAspNetCoreTestHostPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreTestHostPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftExtensionsCachingMemoryPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsCachingMemoryPackageVersion>
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
<MicrosoftExtensionsConfigurationUserSecretsPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsConfigurationUserSecretsPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsWebEncodersPackageVersion>
<MicrosoftIdentityModelClientsActiveDirectoryPackageVersion>3.14.2</MicrosoftIdentityModelClientsActiveDirectoryPackageVersion>
<MicrosoftIdentityModelProtocolsOpenIdConnectPackageVersion>5.2.0</MicrosoftIdentityModelProtocolsOpenIdConnectPackageVersion>
<MicrosoftIdentityModelProtocolsWsFederationPackageVersion>5.2.0</MicrosoftIdentityModelProtocolsWsFederationPackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.9</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.3</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNETCoreApp22PackageVersion>2.2.0-preview3-27001-02</MicrosoftNETCoreApp22PackageVersion>
<BenchmarkDotNetPackageVersion>0.10.13</BenchmarkDotNetPackageVersion>
<InternalAspNetCoreSdkPackageVersion>3.0.0-build-20181114.5</InternalAspNetCoreSdkPackageVersion>
<MicrosoftAspNetCoreAuthenticationAbstractionsPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreAuthenticationAbstractionsPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>3.0.0-preview-181113-11</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreDataProtectionExtensionsPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreDataProtectionExtensionsPackageVersion>
<MicrosoftAspNetCoreDataProtectionPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreDataProtectionPackageVersion>
<MicrosoftAspNetCoreDiagnosticsPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreDiagnosticsPackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreHttpAbstractionsPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreHttpAbstractionsPackageVersion>
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
<MicrosoftAspNetCoreHttpPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreHttpPackageVersion>
<MicrosoftAspNetCoreRoutingPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreRoutingPackageVersion>
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
<MicrosoftAspNetCoreServerKestrelHttpsPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreServerKestrelHttpsPackageVersion>
<MicrosoftAspNetCoreServerKestrelPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreServerKestrelPackageVersion>
<MicrosoftAspNetCoreStaticFilesPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreStaticFilesPackageVersion>
<MicrosoftAspNetCoreTestHostPackageVersion>3.0.0-alpha1-10742</MicrosoftAspNetCoreTestHostPackageVersion>
<MicrosoftAspNetCoreTestingPackageVersion>3.0.0-preview-181113-11</MicrosoftAspNetCoreTestingPackageVersion>
<MicrosoftExtensionsCachingMemoryPackageVersion>3.0.0-preview-181113-11</MicrosoftExtensionsCachingMemoryPackageVersion>
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>3.0.0-preview-181113-11</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
<MicrosoftExtensionsConfigurationUserSecretsPackageVersion>3.0.0-preview-181113-11</MicrosoftExtensionsConfigurationUserSecretsPackageVersion>
<MicrosoftExtensionsDependencyInjectionPackageVersion>3.0.0-preview-181113-11</MicrosoftExtensionsDependencyInjectionPackageVersion>
<MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>3.0.0-preview-181113-11</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>3.0.0-preview-181113-11</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>3.0.0-preview-181113-11</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingDebugPackageVersion>3.0.0-preview-181113-11</MicrosoftExtensionsLoggingDebugPackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>3.0.0-preview-181113-11</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsOptionsPackageVersion>3.0.0-preview-181113-11</MicrosoftExtensionsOptionsPackageVersion>
<MicrosoftExtensionsSecurityHelperSourcesPackageVersion>3.0.0-preview-181113-11</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
<MicrosoftExtensionsWebEncodersPackageVersion>3.0.0-preview-181113-11</MicrosoftExtensionsWebEncodersPackageVersion>
<MicrosoftIdentityModelClientsActiveDirectoryPackageVersion>3.19.8</MicrosoftIdentityModelClientsActiveDirectoryPackageVersion>
<MicrosoftIdentityModelProtocolsOpenIdConnectPackageVersion>5.3.0</MicrosoftIdentityModelProtocolsOpenIdConnectPackageVersion>
<MicrosoftIdentityModelProtocolsWsFederationPackageVersion>5.3.0</MicrosoftIdentityModelProtocolsWsFederationPackageVersion>
<MicrosoftNETCoreAppPackageVersion>3.0.0-preview1-26907-05</MicrosoftNETCoreAppPackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
<MicrosoftOwinSecurityCookiesPackageVersion>3.0.1</MicrosoftOwinSecurityCookiesPackageVersion>
<MicrosoftOwinSecurityPackageVersion>3.0.1</MicrosoftOwinSecurityPackageVersion>
<MicrosoftOwinTestingPackageVersion>3.0.1</MicrosoftOwinTestingPackageVersion>
<MoqPackageVersion>4.10.0</MoqPackageVersion>
<NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
<NewtonsoftJsonPackageVersion>11.0.2</NewtonsoftJsonPackageVersion>
<SystemIdentityModelTokensJwtPackageVersion>5.2.0</SystemIdentityModelTokensJwtPackageVersion>
<SystemIdentityModelTokensJwtPackageVersion>5.3.0</SystemIdentityModelTokensJwtPackageVersion>
<XunitAnalyzersPackageVersion>0.10.0</XunitAnalyzersPackageVersion>
<XunitPackageVersion>2.3.1</XunitPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.4.0</XunitRunnerVisualStudioPackageVersion>
</PropertyGroup>
<PropertyGroup Label="Package Versions: Pinned" />
<Import Project="$(DotNetPackageVersionPropsPath)" Condition=" '$(DotNetPackageVersionPropsPath)' != '' " />
<PropertyGroup Label="Package Versions: Pinned" />
</Project>

View File

@ -1,19 +1,13 @@
<Project>
<Import Project="dependencies.props" />
<ItemGroup>
<ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.Owin.Security.Interop.Test\*.csproj" Condition="'$(OS)' != 'Windows_NT'" />
</ItemGroup>
<PropertyGroup>
<!-- These properties are use by the automation that updates dependencies.props -->
<LineupPackageId>Internal.AspNetCore.Universe.Lineup</LineupPackageId>
<LineupPackageVersion>2.2.0-*</LineupPackageVersion>
<LineupPackageRestoreSource>https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json</LineupPackageRestoreSource>
</PropertyGroup>
<ItemGroup>
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp20PackageVersion)" />
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp21PackageVersion)" />
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp22PackageVersion)" />
<DotNetCoreRuntime Include="$(MicrosoftNETCoreAppPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.2</TargetFrameworks>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.2</TargetFrameworks>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.2</TargetFrameworks>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.2</TargetFrameworks>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UserSecretsId>aspnet5-JwtBearerSample-20151210102827</UserSecretsId>
</PropertyGroup>

View File

@ -64,5 +64,6 @@
<script src="App/Scripts/userDataCtrl.js"></script>
<script src="App/Scripts/todoListCtrl.js"></script>
<script src="App/Scripts/todoListSvc.js"></script>
</div>
</body>
</html>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.2</TargetFrameworks>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UserSecretsId>aspnet5-OpenIdConnectSample-20151210110318</UserSecretsId>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.2</TargetFrameworks>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UserSecretsId>aspnet5-OpenIdConnectSample-20151210110318</UserSecretsId>
</PropertyGroup>

View File

@ -63,6 +63,7 @@ namespace OpenIdConnectSample
o.ResponseType = OpenIdConnectResponseType.CodeIdToken;
o.SaveTokens = true;
o.GetClaimsFromUserInfoEndpoint = true;
o.AccessDeniedPath = "/access-denied-from-remote";
o.ClaimActions.MapAllExcept("aud", "iss", "iat", "nbf", "exp", "aio", "c_hash", "uti", "nonce");
@ -126,6 +127,16 @@ namespace OpenIdConnectSample
return;
}
if (context.Request.Path.Equals("/access-denied-from-remote"))
{
await WriteHtmlAsync(response, async res =>
{
await res.WriteAsync($"<h1>Access Denied error received from the remote authorization server</h1>");
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/\">Home</a>");
});
return;
}
if (context.Request.Path.Equals("/Account/AccessDenied"))
{
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.2</TargetFrameworks>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UserSecretsId>aspnet5-SocialSample-20151210111056</UserSecretsId>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>net461</TargetFrameworks>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -422,7 +422,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
var returnUrl = properties.RedirectUri;
if (string.IsNullOrEmpty(returnUrl))
{
returnUrl = OriginalPathBase + Request.Path + Request.QueryString;
returnUrl = OriginalPathBase + OriginalPath + Request.QueryString;
}
var accessDeniedUri = Options.AccessDeniedPath + QueryString.Create(Options.ReturnUrlParameter, returnUrl);
var redirectContext = new RedirectContext<CookieAuthenticationOptions>(Context, Scheme, Options, properties, BuildRedirectUri(accessDeniedUri));
@ -434,7 +434,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
var redirectUri = properties.RedirectUri;
if (string.IsNullOrEmpty(redirectUri))
{
redirectUri = OriginalPathBase + Request.Path + Request.QueryString;
redirectUri = OriginalPathBase + OriginalPath + Request.QueryString;
}
var loginUri = Options.LoginPath + QueryString.Create(Options.ReturnUrlParameter, redirectUri);

View File

@ -147,68 +147,5 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
/// </para>
/// </summary>
public TimeSpan ExpireTimeSpan { get; set; }
#region Obsolete API
/// <summary>
/// <para>
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.Name"/> on <see cref="Cookie"/>.
/// </para>
/// <para>
/// Determines the cookie name used to persist the identity. The default value is ".AspNetCore.Cookies".
/// This value should be changed if you change the name of the AuthenticationScheme, especially if your
/// system uses the cookie authentication handler multiple times.
/// </para>
/// </summary>
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Name) + ".")]
public string CookieName { get => Cookie.Name; set => Cookie.Name = value; }
/// <summary>
/// <para>
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.Domain"/> on <see cref="Cookie"/>.
/// </para>
/// <para>
/// Determines the domain used to create the cookie. Is not provided by default.
/// </para>
/// </summary>
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Domain) + ".")]
public string CookieDomain { get => Cookie.Domain; set => Cookie.Domain = value; }
/// <summary>
/// <para>
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.Path"/> on <see cref="Cookie"/>.
/// </para>
/// <para>
/// Determines the path used to create the cookie. The default value is "/" for highest browser compatibility.
/// </para>
/// </summary>
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Path) + ".")]
public string CookiePath { get => Cookie.Path; set => Cookie.Path = value; }
/// <summary>
/// <para>
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.HttpOnly"/> on <see cref="Cookie"/>.
/// </para>
/// <para>
/// Determines if the browser should allow the cookie to be accessed by client-side javascript. The
/// default is true, which means the cookie will only be passed to http requests and is not made available
/// to script on the page.
/// </para>
/// </summary>
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.HttpOnly) + ".")]
public bool CookieHttpOnly { get => Cookie.HttpOnly; set => Cookie.HttpOnly = value; }
/// <summary>
/// <para>
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.SecurePolicy"/> on <see cref="Cookie"/>.
/// </para>
/// <para>
/// Determines if the cookie should only be transmitted on HTTPS request. The default is to limit the cookie
/// to HTTPS requests if the page which is doing the SignIn is also HTTPS. If you have an HTTPS sign in page
/// and portions of your site are HTTP you may need to change this value.
/// </para>
/// </summary>
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.SecurePolicy) + ".")]
public CookieSecurePolicy CookieSecure { get => Cookie.SecurePolicy; set => Cookie.SecurePolicy = value; }
#endregion
}
}

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>ASP.NET Core middleware that enables an application to use cookie based authentication.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<DefineConstants>$(DefineConstants);SECURITY</DefineConstants>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

View File

@ -0,0 +1,52 @@
[
{
"TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions",
"MemberId": "public Microsoft.AspNetCore.Http.CookieSecurePolicy get_CookieSecure()",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions",
"MemberId": "public System.Boolean get_CookieHttpOnly()",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions",
"MemberId": "public System.String get_CookieDomain()",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions",
"MemberId": "public System.String get_CookieName()",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions",
"MemberId": "public System.String get_CookiePath()",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions",
"MemberId": "public System.Void set_CookieDomain(System.String value)",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions",
"MemberId": "public System.Void set_CookieHttpOnly(System.Boolean value)",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions",
"MemberId": "public System.Void set_CookieName(System.String value)",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions",
"MemberId": "public System.Void set_CookiePath(System.String value)",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions",
"MemberId": "public System.Void set_CookieSecure(Microsoft.AspNetCore.Http.CookieSecurePolicy value)",
"Kind": "Removal"
}
]

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>ASP.NET Core middleware that enables an application to support Facebook's OAuth 2.0 authentication workflow.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;authentication;security</PackageTags>

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>ASP.NET Core contains middleware to support Google's OpenId and OAuth 2.0 authentication workflows.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;authentication;security</PackageTags>

View File

@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
{
private OpenIdConnectConfiguration _configuration;
public JwtBearerHandler(IOptionsMonitor<JwtBearerOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
public JwtBearerHandler(IOptionsMonitor<JwtBearerOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{ }

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>ASP.NET Core middleware that enables an application to receive an OpenID Connect bearer token.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;authentication;security</PackageTags>

View File

@ -0,0 +1,7 @@
[
{
"TypeId": "public class Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler : Microsoft.AspNetCore.Authentication.AuthenticationHandler<Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions>",
"MemberId": "public .ctor(Microsoft.Extensions.Options.IOptionsMonitor<Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions> options, Microsoft.Extensions.Logging.ILoggerFactory logger, System.Text.Encodings.Web.UrlEncoder encoder, Microsoft.AspNetCore.DataProtection.IDataProtectionProvider dataProtection, Microsoft.AspNetCore.Authentication.ISystemClock clock)",
"Kind": "Removal"
}
]

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>ASP.NET Core middleware that enables an application to support the Microsoft Account authentication workflow.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;authentication;security</PackageTags>

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>ASP.NET Core middleware that enables an application to support any standard OAuth 2.0 authentication workflow.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;authentication;security</PackageTags>

View File

@ -63,6 +63,16 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
var error = query["error"];
if (!StringValues.IsNullOrEmpty(error))
{
// Note: access_denied errors are special protocol errors indicating the user didn't
// approve the authorization demand requested by the remote authorization server.
// Since it's a frequent scenario (that is not caused by incorrect configuration),
// denied errors are handled differently using HandleAccessDeniedErrorAsync().
// Visit https://tools.ietf.org/html/rfc6749#section-4.1.2.1 for more information.
if (StringValues.Equals(error, "access_denied"))
{
return await HandleAccessDeniedErrorAsync(properties);
}
var failureMessage = new StringBuilder();
failureMessage.Append(error);
var errorDescription = query["error_description"];
@ -194,7 +204,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
{
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = CurrentUri;
properties.RedirectUri = OriginalPathBase + OriginalPath + Request.QueryString;
}
// OAuth2 10.12 CSRF

View File

@ -3,11 +3,9 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
using Microsoft.AspNetCore.Http.Authentication;
using System.Globalization;
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authentication.OAuth
{

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>ASP.NET Core middleware that enables an application to support the OpenID Connect authentication workflow.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;authentication;security</PackageTags>

View File

@ -186,7 +186,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
properties.RedirectUri = BuildRedirectUriIfRelative(Options.SignedOutRedirectUri);
if (string.IsNullOrWhiteSpace(properties.RedirectUri))
{
properties.RedirectUri = CurrentUri;
properties.RedirectUri = OriginalPathBase + OriginalPath + Request.QueryString;
}
}
Logger.PostSignOutRedirect(properties.RedirectUri);
@ -312,7 +312,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
// 2. CurrentUri if RedirectUri is not set)
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = CurrentUri;
properties.RedirectUri = OriginalPathBase + OriginalPath + Request.QueryString;
}
Logger.PostAuthenticationLocalRedirect(properties.RedirectUri);
@ -520,6 +520,16 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
// if any of the error fields are set, throw error null
if (!string.IsNullOrEmpty(authorizationResponse.Error))
{
// Note: access_denied errors are special protocol errors indicating the user didn't
// approve the authorization demand requested by the remote authorization server.
// Since it's a frequent scenario (that is not caused by incorrect configuration),
// denied errors are handled differently using HandleAccessDeniedErrorAsync().
// Visit https://tools.ietf.org/html/rfc6749#section-4.1.2.1 for more information.
if (string.Equals(authorizationResponse.Error, "access_denied", StringComparison.Ordinal))
{
return await HandleAccessDeniedErrorAsync(properties);
}
return HandleRequestResult.Fail(CreateOpenIdConnectProtocolException(authorizationResponse, response: null), properties);
}

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>ASP.NET Core middleware that enables an application to support Twitter's OAuth 1.0 authentication workflow.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;authentication;security</PackageTags>

View File

@ -55,12 +55,14 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
var properties = requestToken.Properties;
// REVIEW: see which of these are really errors
var denied = query["denied"];
if (!StringValues.IsNullOrEmpty(denied))
{
return HandleRequestResult.Fail("The user denied permissions.", properties);
// Note: denied errors are special protocol errors indicating the user didn't
// approve the authorization demand requested by the remote authorization server.
// Since it's a frequent scenario (that is not caused by incorrect configuration),
// denied errors are handled differently using HandleAccessDeniedErrorAsync().
return await HandleAccessDeniedErrorAsync(properties);
}
var returnedToken = query["oauth_token"];
@ -130,7 +132,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
{
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = CurrentUri;
properties.RedirectUri = OriginalPathBase + OriginalPath + Request.QueryString;
}
// If CallbackConfirmed is false, this will throw

View File

@ -2,8 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Security.Claims;
using System.Globalization;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
using Microsoft.AspNetCore.Http;

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>ASP.NET Core middleware that enables an application to support the WsFederation authentication workflow.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;authentication;security</PackageTags>
</PropertyGroup>

View File

@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Authentication.WsFederation
// Save the original challenge URI so we can redirect back to it when we're done.
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = CurrentUri;
properties.RedirectUri = OriginalPathBase + OriginalPath + Request.QueryString;
}
var wsFederationMessage = new WsFederationMessage()

View File

@ -46,48 +46,6 @@ namespace Microsoft.Extensions.DependencyInjection
return builder;
}
[Obsolete("AddScheme is obsolete. Use AddAuthentication().AddScheme instead.")]
public static IServiceCollection AddScheme<TOptions, THandler>(this IServiceCollection services, string authenticationScheme, string displayName, Action<AuthenticationSchemeBuilder> configureScheme, Action<TOptions> configureOptions)
where TOptions : AuthenticationSchemeOptions, new()
where THandler : AuthenticationHandler<TOptions>
{
services.AddAuthentication(o =>
{
o.AddScheme(authenticationScheme, scheme => {
scheme.HandlerType = typeof(THandler);
scheme.DisplayName = displayName;
configureScheme?.Invoke(scheme);
});
});
if (configureOptions != null)
{
services.Configure(authenticationScheme, configureOptions);
}
services.AddTransient<THandler>();
return services;
}
[Obsolete("AddScheme is obsolete. Use AddAuthentication().AddScheme instead.")]
public static IServiceCollection AddScheme<TOptions, THandler>(this IServiceCollection services, string authenticationScheme, Action<TOptions> configureOptions)
where TOptions : AuthenticationSchemeOptions, new()
where THandler : AuthenticationHandler<TOptions>
=> services.AddScheme<TOptions, THandler>(authenticationScheme, displayName: null, configureScheme: null, configureOptions: configureOptions);
[Obsolete("AddScheme is obsolete. Use AddAuthentication().AddScheme instead.")]
public static IServiceCollection AddScheme<TOptions, THandler>(this IServiceCollection services, string authenticationScheme, string displayName, Action<TOptions> configureOptions)
where TOptions : AuthenticationSchemeOptions, new()
where THandler : AuthenticationHandler<TOptions>
=> services.AddScheme<TOptions, THandler>(authenticationScheme, displayName, configureScheme: null, configureOptions: configureOptions);
[Obsolete("AddScheme is obsolete. Use AddAuthentication().AddScheme instead.")]
public static IServiceCollection AddRemoteScheme<TOptions, THandler>(this IServiceCollection services, string authenticationScheme, string displayName, Action<TOptions> configureOptions)
where TOptions : RemoteAuthenticationOptions, new()
where THandler : RemoteAuthenticationHandler<TOptions>
{
services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<TOptions>, EnsureSignInScheme<TOptions>>());
return services.AddScheme<TOptions, THandler>(authenticationScheme, displayName, configureScheme: null, configureOptions: configureOptions);
}
// Used to ensure that there's always a sign in scheme
private class EnsureSignInScheme<TOptions> : IPostConfigureOptions<TOptions> where TOptions : RemoteAuthenticationOptions
{

View File

@ -0,0 +1,44 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authentication
{
/// <summary>
/// Provides access denied failure context information to handler providers.
/// </summary>
public class AccessDeniedContext : HandleRequestContext<RemoteAuthenticationOptions>
{
public AccessDeniedContext(
HttpContext context,
AuthenticationScheme scheme,
RemoteAuthenticationOptions options)
: base(context, scheme, options)
{
}
/// <summary>
/// Gets or sets the endpoint path the user agent will be redirected to.
/// By default, this property is set to <see cref="RemoteAuthenticationOptions.AccessDeniedPath"/>.
/// </summary>
public PathString AccessDeniedPath { get; set; }
/// <summary>
/// Additional state values for the authentication session.
/// </summary>
public AuthenticationProperties Properties { get; set; }
/// <summary>
/// Gets or sets the return URL that will be flowed up to the access denied page.
/// If <see cref="ReturnUrlParameter"/> is not set, this property is not used.
/// </summary>
public string ReturnUrl { get; set; }
/// <summary>
/// Gets or sets the parameter name that will be used to flow the return URL.
/// By default, this property is set to <see cref="RemoteAuthenticationOptions.ReturnUrlParameter"/>.
/// </summary>
public string ReturnUrlParameter { get; set; }
}
}

View File

@ -8,12 +8,18 @@ namespace Microsoft.AspNetCore.Authentication
{
public class RemoteAuthenticationEvents
{
public Func<AccessDeniedContext, Task> OnAccessDenied { get; set; } = context => Task.CompletedTask;
public Func<RemoteFailureContext, Task> OnRemoteFailure { get; set; } = context => Task.CompletedTask;
public Func<TicketReceivedContext, Task> OnTicketReceived { get; set; } = context => Task.CompletedTask;
/// <summary>
/// Invoked when there is a remote failure
/// Invoked when an access denied error was returned by the remote server.
/// </summary>
public virtual Task AccessDenied(AccessDeniedContext context) => OnAccessDenied(context);
/// <summary>
/// Invoked when there is a remote failure.
/// </summary>
public virtual Task RemoteFailure(RemoteFailureContext context) => OnRemoteFailure(context);

View File

@ -7,17 +7,20 @@ namespace Microsoft.Extensions.Logging
{
internal static class LoggingExtensions
{
private static Action<ILogger, string, Exception> _authSchemeAuthenticated;
private static Action<ILogger, string, Exception> _authSchemeNotAuthenticated;
private static Action<ILogger, string, string, Exception> _authSchemeNotAuthenticatedWithFailure;
private static Action<ILogger, string, Exception> _authSchemeChallenged;
private static Action<ILogger, string, Exception> _authSchemeForbidden;
private static Action<ILogger, string, Exception> _remoteAuthenticationError;
private static Action<ILogger, Exception> _signInHandled;
private static Action<ILogger, Exception> _signInSkipped;
private static Action<ILogger, string, Exception> _correlationPropertyNotFound;
private static Action<ILogger, string, Exception> _correlationCookieNotFound;
private static Action<ILogger, string, string, Exception> _unexpectedCorrelationCookieValue;
private static readonly Action<ILogger, string, Exception> _authSchemeAuthenticated;
private static readonly Action<ILogger, string, Exception> _authSchemeNotAuthenticated;
private static readonly Action<ILogger, string, string, Exception> _authSchemeNotAuthenticatedWithFailure;
private static readonly Action<ILogger, string, Exception> _authSchemeChallenged;
private static readonly Action<ILogger, string, Exception> _authSchemeForbidden;
private static readonly Action<ILogger, string, Exception> _remoteAuthenticationError;
private static readonly Action<ILogger, Exception> _signInHandled;
private static readonly Action<ILogger, Exception> _signInSkipped;
private static readonly Action<ILogger, string, Exception> _correlationPropertyNotFound;
private static readonly Action<ILogger, string, Exception> _correlationCookieNotFound;
private static readonly Action<ILogger, string, string, Exception> _unexpectedCorrelationCookieValue;
private static readonly Action<ILogger, Exception> _accessDeniedError;
private static readonly Action<ILogger, Exception> _accessDeniedContextHandled;
private static readonly Action<ILogger, Exception> _accessDeniedContextSkipped;
static LoggingExtensions()
{
@ -65,6 +68,18 @@ namespace Microsoft.Extensions.Logging
eventId: 16,
logLevel: LogLevel.Warning,
formatString: "The correlation cookie value '{CorrelationCookieName}' did not match the expected value '{CorrelationCookieValue}'.");
_accessDeniedError = LoggerMessage.Define(
eventId: 17,
logLevel: LogLevel.Information,
formatString: "Access was denied by the resource owner or by the remote server.");
_accessDeniedContextHandled = LoggerMessage.Define(
eventId: 18,
logLevel: LogLevel.Debug,
formatString: "The AccessDenied event returned Handled.");
_accessDeniedContextSkipped = LoggerMessage.Define(
eventId: 19,
logLevel: LogLevel.Debug,
formatString: "The AccessDenied event returned Skipped.");
}
public static void AuthenticationSchemeAuthenticated(this ILogger logger, string authenticationScheme)
@ -121,5 +136,20 @@ namespace Microsoft.Extensions.Logging
{
_unexpectedCorrelationCookieValue(logger, cookieName, cookieValue, null);
}
public static void AccessDeniedError(this ILogger logger)
{
_accessDeniedError(logger, null);
}
public static void AccessDeniedContextHandled(this ILogger logger)
{
_accessDeniedContextHandled(logger, null);
}
public static void AccessDeniedContextSkipped(this ILogger logger)
{
_accessDeniedContextSkipped(logger, null);
}
}
}

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>ASP.NET Core common types used by the various authentication middleware components.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;authentication;security</PackageTags>

View File

@ -5,6 +5,7 @@ using System;
using System.Security.Cryptography;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@ -241,5 +242,48 @@ namespace Microsoft.AspNetCore.Authentication
return true;
}
protected virtual async Task<HandleRequestResult> HandleAccessDeniedErrorAsync(AuthenticationProperties properties)
{
Logger.AccessDeniedError();
var context = new AccessDeniedContext(Context, Scheme, Options)
{
AccessDeniedPath = Options.AccessDeniedPath,
Properties = properties,
ReturnUrl = properties?.RedirectUri,
ReturnUrlParameter = Options.ReturnUrlParameter
};
await Events.AccessDenied(context);
if (context.Result != null)
{
if (context.Result.Handled)
{
Logger.AccessDeniedContextHandled();
}
else if (context.Result.Skipped)
{
Logger.AccessDeniedContextSkipped();
}
return context.Result;
}
// If an access denied endpoint was specified, redirect the user agent.
// Otherwise, invoke the RemoteFailure event for further processing.
if (context.AccessDeniedPath.HasValue)
{
string uri = context.AccessDeniedPath;
if (!string.IsNullOrEmpty(context.ReturnUrlParameter) && !string.IsNullOrEmpty(context.ReturnUrl))
{
uri = QueryHelpers.AddQueryString(uri, context.ReturnUrlParameter, context.ReturnUrl);
}
Response.Redirect(uri);
return HandleRequestResult.Handle();
}
return HandleRequestResult.Fail("Access was denied by the resource owner or by the remote server.", properties);
}
}
}

View File

@ -89,6 +89,22 @@ namespace Microsoft.AspNetCore.Authentication
/// </summary>
public PathString CallbackPath { get; set; }
/// <summary>
/// Gets or sets the optional path the user agent is redirected to if the user
/// doesn't approve the authorization demand requested by the remote server.
/// This property is not set by default. In this case, an exception is thrown
/// if an access_denied response is returned by the remote authorization server.
/// </summary>
public PathString AccessDeniedPath { get; set; }
/// <summary>
/// Gets or sets the name of the parameter used to convey the original location
/// of the user before the remote challenge was triggered up to the access denied page.
/// This property is only used when the <see cref="AccessDeniedPath"/> is explicitly specified.
/// </summary>
// Note: this deliberately matches the default parameter name used by the cookie handler.
public string ReturnUrlParameter { get; set; } = "ReturnUrl";
/// <summary>
/// Gets or sets the authentication scheme corresponding to the middleware
/// responsible of persisting user's identity after a successful authentication.

View File

@ -0,0 +1,22 @@
[
{
"TypeId": "public static class Microsoft.Extensions.DependencyInjection.AuthenticationServiceCollectionExtensions",
"MemberId": "public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddRemoteScheme<T0, T1>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.String authenticationScheme, System.String displayName, System.Action<T0> configureOptions) where T0 : Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions, new() where T1 : Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler<T0>",
"Kind": "Removal"
},
{
"TypeId": "public static class Microsoft.Extensions.DependencyInjection.AuthenticationServiceCollectionExtensions",
"MemberId": "public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddScheme<T0, T1>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.String authenticationScheme, System.Action<T0> configureOptions) where T0 : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions, new() where T1 : Microsoft.AspNetCore.Authentication.AuthenticationHandler<T0>",
"Kind": "Removal"
},
{
"TypeId": "public static class Microsoft.Extensions.DependencyInjection.AuthenticationServiceCollectionExtensions",
"MemberId": "public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddScheme<T0, T1>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.String authenticationScheme, System.String displayName, System.Action<Microsoft.AspNetCore.Authentication.AuthenticationSchemeBuilder> configureScheme, System.Action<T0> configureOptions) where T0 : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions, new() where T1 : Microsoft.AspNetCore.Authentication.AuthenticationHandler<T0>",
"Kind": "Removal"
},
{
"TypeId": "public static class Microsoft.Extensions.DependencyInjection.AuthenticationServiceCollectionExtensions",
"MemberId": "public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddScheme<T0, T1>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.String authenticationScheme, System.String displayName, System.Action<T0> configureOptions) where T0 : Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions, new() where T1 : Microsoft.AspNetCore.Authentication.AuthenticationHandler<T0>",
"Kind": "Removal"
}
]

View File

@ -0,0 +1,29 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Authorization;
namespace Microsoft.AspNetCore.Builder
{
/// <summary>
/// Extension methods to add authorization capabilities to an HTTP application pipeline.
/// </summary>
public static class AuthorizationAppBuilderExtensions
{
/// <summary>
/// Adds the <see cref="AuthorizationMiddleware"/> to the specified <see cref="IApplicationBuilder"/>, which enables authorization capabilities.
/// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param>
/// <returns>A reference to this instance after the operation has completed.</returns>
public static IApplicationBuilder UseAuthorization(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<AuthorizationMiddleware>();
}
}
}

View File

@ -0,0 +1,50 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Routing;
namespace Microsoft.AspNetCore.Builder
{
public static class AuthorizationEndpointConventionBuilderExtensions
{
public static IEndpointConventionBuilder RequireAuthorization(this IEndpointConventionBuilder builder, params IAuthorizeData[] authorizeData)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
if (authorizeData == null)
{
throw new ArgumentNullException(nameof(authorizeData));
}
builder.Apply(endpointBuilder =>
{
foreach (var data in authorizeData)
{
endpointBuilder.Metadata.Add(data);
}
});
return builder;
}
public static IEndpointConventionBuilder RequireAuthorization(this IEndpointConventionBuilder builder, params string[] policyNames)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
if (policyNames == null)
{
throw new ArgumentNullException(nameof(policyNames));
}
return builder.RequireAuthorization(policyNames.Select(n => new AuthorizeAttribute(n)).ToArray());
}
}
}

View File

@ -0,0 +1,104 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Authorization
{
public class AuthorizationMiddleware
{
private readonly RequestDelegate _next;
private readonly IAuthorizationPolicyProvider _policyProvider;
public AuthorizationMiddleware(RequestDelegate next, IAuthorizationPolicyProvider policyProvider)
{
if (next == null)
{
throw new ArgumentNullException(nameof(next));
}
if (policyProvider == null)
{
throw new ArgumentNullException(nameof(policyProvider));
}
_next = next;
_policyProvider = policyProvider;
}
public async Task Invoke(HttpContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var endpoint = context.GetEndpoint();
var authorizeData = endpoint?.Metadata.GetOrderedMetadata<IAuthorizeData>() ?? Array.Empty<IAuthorizeData>();
var policy = await AuthorizationPolicy.CombineAsync(_policyProvider, authorizeData);
if (policy == null)
{
await _next(context);
return;
}
// Policy evaluator has transient lifetime so it fetched from request services instead of injecting in constructor
var policyEvaluator = context.RequestServices.GetRequiredService<IPolicyEvaluator>();
var authenticateResult = await policyEvaluator.AuthenticateAsync(policy, context);
// Allow Anonymous skips all authorization
if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null)
{
await _next(context);
return;
}
// Note that the resource will be null if there is no matched endpoint
var authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticateResult, context, resource: endpoint);
if (authorizeResult.Challenged)
{
if (policy.AuthenticationSchemes.Any())
{
foreach (var scheme in policy.AuthenticationSchemes)
{
await context.ChallengeAsync(scheme);
}
}
else
{
await context.ChallengeAsync();
}
return;
}
else if (authorizeResult.Forbidden)
{
if (policy.AuthenticationSchemes.Any())
{
foreach (var scheme in policy.AuthenticationSchemes)
{
await context.ForbidAsync(scheme);
}
}
else
{
await context.ForbidAsync();
}
return;
}
await _next(context);
}
}
}

View File

@ -2,8 +2,8 @@
<PropertyGroup>
<Description>ASP.NET Core authorization policy helper classes.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591;NU1605</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;authorization</PackageTags>
</PropertyGroup>
@ -14,6 +14,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.Abstractions" Version="$(MicrosoftAspNetCoreAuthenticationAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="$(MicrosoftAspNetCoreHttpAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="$(MicrosoftAspNetCoreRoutingPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.SecurityHelper.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsSecurityHelperSourcesPackageVersion)" />
</ItemGroup>

View File

@ -20,13 +20,25 @@ namespace Microsoft.AspNetCore.Authorization
public bool InvokeHandlersAfterFailure { get; set; } = true;
/// <summary>
/// Gets or sets the default authorization policy.
/// Gets or sets the default authorization policy. Defaults to require authenticated users.
/// </summary>
/// <remarks>
/// The default policy is to require any authenticated user.
/// The default policy used when evaluating <see cref="IAuthorizeData"/> with no policy name specified.
/// </remarks>
public AuthorizationPolicy DefaultPolicy { get; set; } = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
/// <summary>
/// Gets or sets the required authorization policy. Defaults to null.
/// </summary>
/// <remarks>
/// By default the required policy is null.
///
/// If a required policy has been specified then it is always evaluated, even if there are no
/// <see cref="IAuthorizeData"/> instances for a resource. If a resource has <see cref="IAuthorizeData"/>
/// then they are evaluated together with the required policy.
/// </remarks>
public AuthorizationPolicy RequiredPolicy { get; set; }
/// <summary>
/// Add an authorization policy with the provided name.
/// </summary>

View File

@ -120,46 +120,74 @@ namespace Microsoft.AspNetCore.Authorization
throw new ArgumentNullException(nameof(authorizeData));
}
var policyBuilder = new AuthorizationPolicyBuilder();
var any = false;
foreach (var authorizeDatum in authorizeData)
// Avoid allocating enumerator if the data is known to be empty
var skipEnumeratingData = false;
if (authorizeData is IList<IAuthorizeData> dataList)
{
any = true;
var useDefaultPolicy = true;
if (!string.IsNullOrWhiteSpace(authorizeDatum.Policy))
skipEnumeratingData = dataList.Count == 0;
}
AuthorizationPolicyBuilder policyBuilder = null;
if (!skipEnumeratingData)
{
foreach (var authorizeDatum in authorizeData)
{
var policy = await policyProvider.GetPolicyAsync(authorizeDatum.Policy);
if (policy == null)
if (policyBuilder == null)
{
throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound(authorizeDatum.Policy));
policyBuilder = new AuthorizationPolicyBuilder();
}
policyBuilder.Combine(policy);
useDefaultPolicy = false;
}
var rolesSplit = authorizeDatum.Roles?.Split(',');
if (rolesSplit != null && rolesSplit.Any())
{
var trimmedRolesSplit = rolesSplit.Where(r => !string.IsNullOrWhiteSpace(r)).Select(r => r.Trim());
policyBuilder.RequireRole(trimmedRolesSplit);
useDefaultPolicy = false;
}
var authTypesSplit = authorizeDatum.AuthenticationSchemes?.Split(',');
if (authTypesSplit != null && authTypesSplit.Any())
{
foreach (var authType in authTypesSplit)
var useDefaultPolicy = true;
if (!string.IsNullOrWhiteSpace(authorizeDatum.Policy))
{
if (!string.IsNullOrWhiteSpace(authType))
var policy = await policyProvider.GetPolicyAsync(authorizeDatum.Policy);
if (policy == null)
{
policyBuilder.AuthenticationSchemes.Add(authType.Trim());
throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound(authorizeDatum.Policy));
}
policyBuilder.Combine(policy);
useDefaultPolicy = false;
}
var rolesSplit = authorizeDatum.Roles?.Split(',');
if (rolesSplit != null && rolesSplit.Any())
{
var trimmedRolesSplit = rolesSplit.Where(r => !string.IsNullOrWhiteSpace(r)).Select(r => r.Trim());
policyBuilder.RequireRole(trimmedRolesSplit);
useDefaultPolicy = false;
}
var authTypesSplit = authorizeDatum.AuthenticationSchemes?.Split(',');
if (authTypesSplit != null && authTypesSplit.Any())
{
foreach (var authType in authTypesSplit)
{
if (!string.IsNullOrWhiteSpace(authType))
{
policyBuilder.AuthenticationSchemes.Add(authType.Trim());
}
}
}
}
if (useDefaultPolicy)
{
policyBuilder.Combine(await policyProvider.GetDefaultPolicyAsync());
if (useDefaultPolicy)
{
policyBuilder.Combine(await policyProvider.GetDefaultPolicyAsync());
}
}
}
return any ? policyBuilder.Build() : null;
var requiredPolicy = await policyProvider.GetRequiredPolicyAsync();
if (requiredPolicy != null)
{
if (policyBuilder == null)
{
policyBuilder = new AuthorizationPolicyBuilder();
}
policyBuilder.Combine(requiredPolicy);
}
return policyBuilder?.Build();
}
}
}

View File

@ -96,16 +96,16 @@ namespace Microsoft.AspNetCore.Authorization
/// to the current instance.
/// </summary>
/// <param name="claimType">The claim type required.</param>
/// <param name="requiredValues">Values the claim must process one or more of for evaluation to succeed.</param>
/// <param name="allowedValues">Values the claim must process one or more of for evaluation to succeed.</param>
/// <returns>A reference to this instance after the operation has completed.</returns>
public AuthorizationPolicyBuilder RequireClaim(string claimType, params string[] requiredValues)
public AuthorizationPolicyBuilder RequireClaim(string claimType, params string[] allowedValues)
{
if (claimType == null)
{
throw new ArgumentNullException(nameof(claimType));
}
return RequireClaim(claimType, (IEnumerable<string>)requiredValues);
return RequireClaim(claimType, (IEnumerable<string>)allowedValues);
}
/// <summary>
@ -113,16 +113,16 @@ namespace Microsoft.AspNetCore.Authorization
/// to the current instance.
/// </summary>
/// <param name="claimType">The claim type required.</param>
/// <param name="requiredValues">Values the claim must process one or more of for evaluation to succeed.</param>
/// <param name="allowedValues">Values the claim must process one or more of for evaluation to succeed.</param>
/// <returns>A reference to this instance after the operation has completed.</returns>
public AuthorizationPolicyBuilder RequireClaim(string claimType, IEnumerable<string> requiredValues)
public AuthorizationPolicyBuilder RequireClaim(string claimType, IEnumerable<string> allowedValues)
{
if (claimType == null)
{
throw new ArgumentNullException(nameof(claimType));
}
Requirements.Add(new ClaimsAuthorizationRequirement(claimType, requiredValues));
Requirements.Add(new ClaimsAuthorizationRequirement(claimType, allowedValues));
return this;
}
@ -147,7 +147,7 @@ namespace Microsoft.AspNetCore.Authorization
/// Adds a <see cref="RolesAuthorizationRequirement"/>
/// to the current instance.
/// </summary>
/// <param name="roles">The roles required.</param>
/// <param name="roles">The allowed roles.</param>
/// <returns>A reference to this instance after the operation has completed.</returns>
public AuthorizationPolicyBuilder RequireRole(params string[] roles)
{
@ -163,7 +163,7 @@ namespace Microsoft.AspNetCore.Authorization
/// Adds a <see cref="RolesAuthorizationRequirement"/>
/// to the current instance.
/// </summary>
/// <param name="roles">The roles required.</param>
/// <param name="roles">The allowed roles.</param>
/// <returns>A reference to this instance after the operation has completed.</returns>
public AuthorizationPolicyBuilder RequireRole(IEnumerable<string> roles)
{
@ -247,4 +247,4 @@ namespace Microsoft.AspNetCore.Authorization
return new AuthorizationPolicy(Requirements, AuthenticationSchemes.Distinct());
}
}
}
}

View File

@ -39,15 +39,5 @@ namespace Microsoft.AspNetCore.Authorization
/// Gets or sets a comma delimited list of schemes from which user information is constructed.
/// </summary>
public string AuthenticationSchemes { get; set; }
/// <summary>
/// Gets or sets a comma delimited list of schemes from which user information is constructed.
/// </summary>
[Obsolete("Use AuthenticationSchemes instead.", error: false)]
public string ActiveAuthenticationSchemes
{
get => AuthenticationSchemes;
set => AuthenticationSchemes = value;
}
}
}

View File

@ -14,6 +14,8 @@ namespace Microsoft.AspNetCore.Authorization
public class DefaultAuthorizationPolicyProvider : IAuthorizationPolicyProvider
{
private readonly AuthorizationOptions _options;
private Task<AuthorizationPolicy> _cachedDefaultPolicy;
private Task<AuthorizationPolicy> _cachedRequiredPolicy;
/// <summary>
/// Creates a new instance of <see cref="DefaultAuthorizationPolicyProvider"/>.
@ -35,7 +37,26 @@ namespace Microsoft.AspNetCore.Authorization
/// <returns>The default authorization policy.</returns>
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
return Task.FromResult(_options.DefaultPolicy);
return GetCachedPolicy(ref _cachedDefaultPolicy, _options.DefaultPolicy);
}
/// <summary>
/// Gets the required authorization policy.
/// </summary>
/// <returns>The required authorization policy.</returns>
public Task<AuthorizationPolicy> GetRequiredPolicyAsync()
{
return GetCachedPolicy(ref _cachedRequiredPolicy, _options.RequiredPolicy);
}
private Task<AuthorizationPolicy> GetCachedPolicy(ref Task<AuthorizationPolicy> cachedPolicy, AuthorizationPolicy currentPolicy)
{
var local = cachedPolicy;
if (local == null || local.Result != currentPolicy)
{
cachedPolicy = local = Task.FromResult(currentPolicy);
}
return local;
}
/// <summary>

View File

@ -22,5 +22,11 @@ namespace Microsoft.AspNetCore.Authorization
/// </summary>
/// <returns>The default authorization policy.</returns>
Task<AuthorizationPolicy> GetDefaultPolicyAsync();
/// <summary>
/// Gets the required authorization policy.
/// </summary>
/// <returns>The required authorization policy.</returns>
Task<AuthorizationPolicy> GetRequiredPolicyAsync();
}
}

View File

@ -5,7 +5,7 @@
Commonly used types:
Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute
Microsoft.AspNetCore.Authorization.AuthorizeAttribute</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;authorization</PackageTags>

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>ASP.NET Core cookie policy classes to control the behavior of cookies.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore</PackageTags>

View File

@ -1,13 +1,6 @@
<Project>
<Import Project="..\Directory.Build.props" />
<PropertyGroup>
<DeveloperBuildTestTfms>netcoreapp2.2</DeveloperBuildTestTfms>
<StandardTestTfms>$(DeveloperBuildTestTfms)</StandardTestTfms>
<StandardTestTfms Condition=" '$(DeveloperBuild)' != 'true' ">$(StandardTestTfms)</StandardTestTfms>
<StandardTestTfms Condition=" '$(DeveloperBuild)' != 'true' AND '$(OS)' == 'Windows_NT' ">$(StandardTestTfms);net461</StandardTestTfms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Internal.AspNetCore.Sdk" PrivateAssets="All" Version="$(InternalAspNetCoreSdkPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Testing" Version="$(MicrosoftAspNetCoreTestingPackageVersion)" />

View File

@ -10,7 +10,6 @@ using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.AspNetCore.Authentication.Tests;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
@ -22,431 +21,16 @@ using Xunit;
namespace Microsoft.AspNetCore.Authentication.Cookies
{
public class CookieTests
public class CookieTests : SharedAuthenticationTests<CookieAuthenticationOptions>
{
private TestClock _clock = new TestClock();
[Fact]
public async Task CanForwardDefault()
protected override string DefaultScheme => CookieAuthenticationDefaults.AuthenticationScheme;
protected override Type HandlerType => typeof(CookieAuthenticationHandler);
protected override void RegisterAuth(AuthenticationBuilder services, Action<CookieAuthenticationOptions> configure)
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.AddScheme<TestHandler>("auth1", "auth1");
})
.AddCookie(o => o.ForwardDefault = "auth1");
var forwardDefault = new TestHandler();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await context.SignOutAsync();
Assert.Equal(1, forwardDefault.SignOutCount);
await context.SignInAsync(new ClaimsPrincipal());
Assert.Equal(1, forwardDefault.SignInCount);
}
[Fact]
public async Task ForwardSignInWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddCookie(o =>
{
o.ForwardDefault = "auth1";
o.ForwardSignIn = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.SignInAsync(new ClaimsPrincipal());
Assert.Equal(1, specific.SignInCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardSignOutWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddCookie(o =>
{
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.SignOutAsync();
Assert.Equal(1, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardForbidWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddCookie(o =>
{
o.ForwardDefault = "auth1";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ForbidAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(1, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardAuthenticateWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddCookie(o =>
{
o.ForwardDefault = "auth1";
o.ForwardAuthenticate = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(1, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardChallengeWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.AddScheme<TestHandler>("specific", "specific");
o.AddScheme<TestHandler2>("auth1", "auth1");
})
.AddCookie(o =>
{
o.ForwardDefault = "auth1";
o.ForwardChallenge = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ChallengeAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(1, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardSelectorWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddCookie(o =>
{
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, selector.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, selector.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, selector.ChallengeCount);
await context.SignOutAsync();
Assert.Equal(1, selector.SignOutCount);
await context.SignInAsync(new ClaimsPrincipal());
Assert.Equal(1, selector.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task NullForwardSelectorUsesDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddCookie(o =>
{
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => null;
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await context.SignOutAsync();
Assert.Equal(1, forwardDefault.SignOutCount);
await context.SignInAsync(new ClaimsPrincipal());
Assert.Equal(1, forwardDefault.SignInCount);
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task SpecificForwardWinsOverSelectorAndDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddCookie(o =>
{
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
o.ForwardAuthenticate = "specific";
o.ForwardChallenge = "specific";
o.ForwardSignIn = "specific";
o.ForwardSignOut = "specific";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, specific.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, specific.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, specific.ChallengeCount);
await context.SignOutAsync();
Assert.Equal(1, specific.SignOutCount);
await context.SignInAsync(new ClaimsPrincipal());
Assert.Equal(1, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
}
[Fact]
public async Task VerifySchemeDefaults()
{
var services = new ServiceCollection();
services.AddAuthentication().AddCookie();
var sp = services.BuildServiceProvider();
var schemeProvider = sp.GetRequiredService<IAuthenticationSchemeProvider>();
var scheme = await schemeProvider.GetSchemeAsync(CookieAuthenticationDefaults.AuthenticationScheme);
Assert.NotNull(scheme);
Assert.Equal("CookieAuthenticationHandler", scheme.HandlerType.Name);
Assert.Null(scheme.DisplayName);
services.AddCookie(configure);
}
[Fact]

View File

@ -1,17 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Authentication.Tests;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
@ -20,478 +11,40 @@ using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNetCore.Authentication.Facebook
{
public class FacebookTests
public class FacebookTests : RemoteAuthenticationTests<FacebookOptions>
{
private void ConfigureDefaults(FacebookOptions o)
protected override string DefaultScheme => FacebookDefaults.AuthenticationScheme;
protected override Type HandlerType => typeof(FacebookHandler);
protected override bool SupportsSignIn { get => false; }
protected override bool SupportsSignOut { get => false; }
protected override void RegisterAuth(AuthenticationBuilder services, Action<FacebookOptions> configure)
{
services.AddFacebook(o =>
{
ConfigureDefaults(o);
configure.Invoke(o);
});
}
protected override void ConfigureDefaults(FacebookOptions o)
{
o.AppId = "whatever";
o.AppSecret = "whatever";
o.SignInScheme = "auth1";
}
[Fact]
public async Task CanForwardDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = FacebookDefaults.AuthenticationScheme;
o.AddScheme<TestHandler>("auth1", "auth1");
})
.AddFacebook(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
});
var forwardDefault = new TestHandler();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
[Fact]
public async Task ForwardSignInThrows()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = FacebookDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddFacebook(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
[Fact]
public async Task ForwardSignOutThrows()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = FacebookDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddFacebook(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
}
[Fact]
public async Task ForwardForbidWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = FacebookDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddFacebook(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ForbidAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(1, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardAuthenticateWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = FacebookDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddFacebook(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardAuthenticate = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(1, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardChallengeWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = FacebookDefaults.AuthenticationScheme;
o.AddScheme<TestHandler>("specific", "specific");
o.AddScheme<TestHandler2>("auth1", "auth1");
})
.AddFacebook(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardChallenge = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ChallengeAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(1, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardSelectorWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = FacebookDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddFacebook(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, selector.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, selector.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, selector.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task NullForwardSelectorUsesDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = FacebookDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddFacebook(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => null;
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task SpecificForwardWinsOverSelectorAndDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = FacebookDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddFacebook(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
o.ForwardAuthenticate = "specific";
o.ForwardChallenge = "specific";
o.ForwardSignIn = "specific";
o.ForwardSignOut = "specific";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, specific.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, specific.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, specific.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
}
[Fact]
public async Task VerifySignInSchemeCannotBeSetToSelf()
{
var server = CreateServer(
app => { },
services => services.AddAuthentication().AddFacebook(o =>
{
o.AppId = "whatever";
o.AppSecret = "whatever";
o.SignInScheme = FacebookDefaults.AuthenticationScheme;
}),
async context =>
{
await context.ChallengeAsync("Facebook");
return true;
});
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message);
}
[Fact]
public async Task VerifySignInSchemeCannotBeSetToSelfUsingDefaultScheme()
{
var server = CreateServer(
app => { },
services => services.AddAuthentication(o => o.DefaultScheme = FacebookDefaults.AuthenticationScheme).AddFacebook(o =>
{
o.AppId = "whatever";
o.AppSecret = "whatever";
}),
async context =>
{
await context.ChallengeAsync("Facebook");
return true;
});
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message);
}
[Fact]
public async Task VerifySignInSchemeCannotBeSetToSelfUsingDefaultSignInScheme()
{
var server = CreateServer(
app => { },
services => services.AddAuthentication(o => o.DefaultSignInScheme = FacebookDefaults.AuthenticationScheme).AddFacebook(o =>
{
o.AppId = "whatever";
o.AppSecret = "whatever";
}),
async context =>
{
await context.ChallengeAsync("Facebook");
return true;
});
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message);
}
[Fact]
public async Task VerifySchemeDefaults()
{
var services = new ServiceCollection();
services.AddAuthentication().AddFacebook();
var sp = services.BuildServiceProvider();
var schemeProvider = sp.GetRequiredService<IAuthenticationSchemeProvider>();
var scheme = await schemeProvider.GetSchemeAsync(FacebookDefaults.AuthenticationScheme);
Assert.NotNull(scheme);
Assert.Equal("FacebookHandler", scheme.HandlerType.Name);
Assert.Equal(FacebookDefaults.AuthenticationScheme, scheme.DisplayName);
}
[Fact]
public async Task ThrowsIfAppIdMissing()
{

View File

@ -1,16 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Authentication.Tests;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
@ -20,433 +10,42 @@ using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNetCore.Authentication.Google
{
public class GoogleTests
public class GoogleTests : RemoteAuthenticationTests<GoogleOptions>
{
private void ConfigureDefaults(GoogleOptions o)
protected override string DefaultScheme => GoogleDefaults.AuthenticationScheme;
protected override Type HandlerType => typeof(GoogleHandler);
protected override bool SupportsSignIn { get => false; }
protected override bool SupportsSignOut { get => false; }
protected override void RegisterAuth(AuthenticationBuilder services, Action<GoogleOptions> configure)
{
services.AddGoogle(o =>
{
ConfigureDefaults(o);
configure.Invoke(o);
});
}
protected override void ConfigureDefaults(GoogleOptions o)
{
o.ClientId = "whatever";
o.ClientSecret = "whatever";
o.SignInScheme = "auth1";
}
[Fact]
public async Task CanForwardDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = GoogleDefaults.AuthenticationScheme;
o.AddScheme<TestHandler>("auth1", "auth1");
})
.AddGoogle(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
});
var forwardDefault = new TestHandler();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
[Fact]
public async Task ForwardSignInThrows()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = GoogleDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddGoogle(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
[Fact]
public async Task ForwardSignOutThrows()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = GoogleDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddGoogle(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
}
[Fact]
public async Task ForwardForbidWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = GoogleDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddGoogle(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ForbidAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(1, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardAuthenticateWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = GoogleDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddGoogle(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardAuthenticate = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(1, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardChallengeWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = GoogleDefaults.AuthenticationScheme;
o.AddScheme<TestHandler>("specific", "specific");
o.AddScheme<TestHandler2>("auth1", "auth1");
})
.AddGoogle(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardChallenge = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ChallengeAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(1, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardSelectorWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = GoogleDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddGoogle(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, selector.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, selector.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, selector.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task NullForwardSelectorUsesDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = GoogleDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddGoogle(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => null;
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task SpecificForwardWinsOverSelectorAndDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = GoogleDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddGoogle(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
o.ForwardAuthenticate = "specific";
o.ForwardChallenge = "specific";
o.ForwardSignIn = "specific";
o.ForwardSignOut = "specific";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, specific.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, specific.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, specific.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
}
[Fact]
public async Task VerifySignInSchemeCannotBeSetToSelf()
{
var server = CreateServer(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
o.SignInScheme = GoogleDefaults.AuthenticationScheme;
});
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message);
}
[Fact]
public async Task VerifySchemeDefaults()
{
var services = new ServiceCollection();
services.AddAuthentication().AddGoogle();
var sp = services.BuildServiceProvider();
var schemeProvider = sp.GetRequiredService<IAuthenticationSchemeProvider>();
var scheme = await schemeProvider.GetSchemeAsync(GoogleDefaults.AuthenticationScheme);
Assert.NotNull(scheme);
Assert.Equal("GoogleHandler", scheme.HandlerType.Name);
Assert.Equal(GoogleDefaults.AuthenticationScheme, scheme.DisplayName);
}
[Fact]
public async Task ChallengeWillTriggerRedirection()
{
@ -758,6 +357,70 @@ namespace Microsoft.AspNetCore.Authentication.Google
Assert.Equal("The oauth state was missing or invalid.", error.GetBaseException().Message);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task ReplyPathWithAccessDeniedErrorFails(bool redirect)
{
var server = CreateServer(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
o.StateDataFormat = new TestStateDataFormat();
o.Events = redirect ? new OAuthEvents()
{
OnAccessDenied = ctx =>
{
ctx.Response.Redirect("/error?FailureMessage=AccessDenied");
ctx.HandleResponse();
return Task.FromResult(0);
}
} : new OAuthEvents();
});
var sendTask = server.SendAsync("https://example.com/signin-google?error=access_denied&error_description=SoBad&error_uri=foobar&state=protected_state",
".AspNetCore.Correlation.Google.correlationId=N");
if (redirect)
{
var transaction = await sendTask;
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
Assert.Equal("/error?FailureMessage=AccessDenied", transaction.Response.Headers.GetValues("Location").First());
}
else
{
var error = await Assert.ThrowsAnyAsync<Exception>(() => sendTask);
Assert.Equal("Access was denied by the resource owner or by the remote server.", error.GetBaseException().Message);
}
}
[Fact]
public async Task ReplyPathWithAccessDeniedError_AllowsCustomizingPath()
{
var server = CreateServer(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
o.StateDataFormat = new TestStateDataFormat();
o.AccessDeniedPath = "/access-denied";
o.Events = new OAuthEvents()
{
OnAccessDenied = ctx =>
{
Assert.Equal("/access-denied", ctx.AccessDeniedPath.Value);
Assert.Equal("http://testhost/redirect", ctx.ReturnUrl);
Assert.Equal("ReturnUrl", ctx.ReturnUrlParameter);
ctx.AccessDeniedPath = "/custom-denied-page";
ctx.ReturnUrl = "http://www.google.com/";
ctx.ReturnUrlParameter = "rurl";
return Task.FromResult(0);
}
};
});
var transaction = await server.SendAsync("https://example.com/signin-google?error=access_denied&error_description=SoBad&error_uri=foobar&state=protected_state",
".AspNetCore.Correlation.Google.correlationId=N");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
Assert.Equal("/custom-denied-page?rurl=http%3A%2F%2Fwww.google.com%2F", transaction.Response.Headers.GetValues("Location").First());
}
[Theory]
[InlineData(true)]
[InlineData(false)]
@ -779,7 +442,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
} : new OAuthEvents();
});
var sendTask = server.SendAsync("https://example.com/signin-google?error=OMG&error_description=SoBad&error_uri=foobar&state=protected_state",
".AspNetCore.Correlation.Google.corrilationId=N");
".AspNetCore.Correlation.Google.correlationId=N");
if (redirect)
{
var transaction = await sendTask;
@ -1606,7 +1269,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
Assert.Equal("protected_state", protectedText);
var properties = new AuthenticationProperties(new Dictionary<string, string>()
{
{ ".xsrf", "corrilationId" },
{ ".xsrf", "correlationId" },
{ "testkey", "testvalue" }
});
properties.RedirectUri = "http://testhost/redirect";

View File

@ -1,6 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
@ -11,428 +17,30 @@ using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.AspNetCore.Authentication.Tests;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Xunit;
namespace Microsoft.AspNetCore.Authentication.JwtBearer
{
public class JwtBearerTests
public class JwtBearerTests : SharedAuthenticationTests<JwtBearerOptions>
{
protected override string DefaultScheme => JwtBearerDefaults.AuthenticationScheme;
protected override Type HandlerType => typeof(JwtBearerHandler);
protected override bool SupportsSignIn { get => false; }
protected override bool SupportsSignOut { get => false; }
protected override void RegisterAuth(AuthenticationBuilder services, Action<JwtBearerOptions> configure)
{
services.AddJwtBearer(o =>
{
ConfigureDefaults(o);
configure.Invoke(o);
});
}
private void ConfigureDefaults(JwtBearerOptions o)
{
}
[Fact]
public async Task CanForwardDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.AddScheme<TestHandler>("auth1", "auth1");
})
.AddJwtBearer(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
});
var forwardDefault = new TestHandler();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
[Fact]
public async Task ForwardSignInThrows()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddJwtBearer(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
[Fact]
public async Task ForwardSignOutThrows()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddJwtBearer(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
}
[Fact]
public async Task ForwardForbidWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultSignInScheme = "auth1";
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddJwtBearer(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ForbidAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(1, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardAuthenticateWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultSignInScheme = "auth1";
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddJwtBearer(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardAuthenticate = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(1, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardChallengeWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultSignInScheme = "auth1";
o.AddScheme<TestHandler>("specific", "specific");
o.AddScheme<TestHandler2>("auth1", "auth1");
})
.AddJwtBearer(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardChallenge = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ChallengeAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(1, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardSelectorWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddJwtBearer(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, selector.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, selector.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, selector.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task NullForwardSelectorUsesDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddJwtBearer(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => null;
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task SpecificForwardWinsOverSelectorAndDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddJwtBearer(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
o.ForwardAuthenticate = "specific";
o.ForwardChallenge = "specific";
o.ForwardSignIn = "specific";
o.ForwardSignOut = "specific";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, specific.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, specific.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, specific.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
}
[Fact]
public async Task VerifySchemeDefaults()
{
var services = new ServiceCollection();
services.AddAuthentication().AddJwtBearer();
var sp = services.BuildServiceProvider();
var schemeProvider = sp.GetRequiredService<IAuthenticationSchemeProvider>();
var scheme = await schemeProvider.GetSchemeAsync(JwtBearerDefaults.AuthenticationScheme);
Assert.NotNull(scheme);
Assert.Equal("JwtBearerHandler", scheme.HandlerType.Name);
Assert.Null(scheme.DisplayName);
}
[Fact]
public async Task BearerTokenValidation()
{

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -1,14 +1,5 @@
// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Builder;
@ -16,438 +7,44 @@ using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
{
public class MicrosoftAccountTests
public class MicrosoftAccountTests : RemoteAuthenticationTests<MicrosoftAccountOptions>
{
private void ConfigureDefaults(MicrosoftAccountOptions o)
protected override string DefaultScheme => MicrosoftAccountDefaults.AuthenticationScheme;
protected override Type HandlerType => typeof(MicrosoftAccountHandler);
protected override bool SupportsSignIn { get => false; }
protected override bool SupportsSignOut { get => false; }
protected override void RegisterAuth(AuthenticationBuilder services, Action<MicrosoftAccountOptions> configure)
{
services.AddMicrosoftAccount(o =>
{
ConfigureDefaults(o);
configure.Invoke(o);
});
}
protected override void ConfigureDefaults(MicrosoftAccountOptions o)
{
o.ClientId = "whatever";
o.ClientSecret = "whatever";
o.SignInScheme = "auth1";
}
[Fact]
public async Task CanForwardDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = MicrosoftAccountDefaults.AuthenticationScheme;
o.AddScheme<TestHandler>("auth1", "auth1");
})
.AddMicrosoftAccount(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
});
var forwardDefault = new TestHandler();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
[Fact]
public async Task ForwardSignInThrows()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = MicrosoftAccountDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddMicrosoftAccount(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
[Fact]
public async Task ForwardSignOutThrows()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = MicrosoftAccountDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddMicrosoftAccount(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
}
[Fact]
public async Task ForwardForbidWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = MicrosoftAccountDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddMicrosoftAccount(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ForbidAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(1, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardAuthenticateWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = MicrosoftAccountDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddMicrosoftAccount(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardAuthenticate = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(1, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardChallengeWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = MicrosoftAccountDefaults.AuthenticationScheme;
o.AddScheme<TestHandler>("specific", "specific");
o.AddScheme<TestHandler2>("auth1", "auth1");
})
.AddMicrosoftAccount(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardChallenge = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ChallengeAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(1, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardSelectorWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = MicrosoftAccountDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddMicrosoftAccount(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, selector.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, selector.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, selector.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task NullForwardSelectorUsesDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = MicrosoftAccountDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddMicrosoftAccount(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => null;
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task SpecificForwardWinsOverSelectorAndDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = MicrosoftAccountDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddMicrosoftAccount(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
o.ForwardAuthenticate = "specific";
o.ForwardChallenge = "specific";
o.ForwardSignIn = "specific";
o.ForwardSignOut = "specific";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, specific.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, specific.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, specific.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
}
[Fact]
public async Task VerifySignInSchemeCannotBeSetToSelf()
{
var server = CreateServer(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
o.SignInScheme = MicrosoftAccountDefaults.AuthenticationScheme;
});
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message);
}
[Fact]
public async Task VerifySchemeDefaults()
{
var services = new ServiceCollection();
services.AddAuthentication().AddMicrosoftAccount();
var sp = services.BuildServiceProvider();
var schemeProvider = sp.GetRequiredService<IAuthenticationSchemeProvider>();
var scheme = await schemeProvider.GetSchemeAsync(MicrosoftAccountDefaults.AuthenticationScheme);
Assert.NotNull(scheme);
Assert.Equal("MicrosoftAccountHandler", scheme.HandlerType.Name);
Assert.Equal(MicrosoftAccountDefaults.AuthenticationScheme, scheme.DisplayName);
}
[Fact]
public async Task ChallengeWillTriggerApplyRedirectEvent()
{

View File

@ -1,447 +1,34 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Net;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Tests;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNetCore.Authentication.OAuth
{
public class OAuthTests
public class OAuthTests : RemoteAuthenticationTests<OAuthOptions>
{
[Fact]
public async Task CanForwardDefault()
{
var services = new ServiceCollection().AddLogging();
protected override string DefaultScheme => OAuthDefaults.DisplayName;
protected override Type HandlerType => typeof(OAuthHandler<OAuthOptions>);
protected override bool SupportsSignIn { get => false; }
protected override bool SupportsSignOut { get => false; }
services.AddAuthentication(o =>
{
o.DefaultScheme = "default";
o.AddScheme<TestHandler>("auth1", "auth1");
})
.AddOAuth("default", o =>
protected override void RegisterAuth(AuthenticationBuilder services, Action<OAuthOptions> configure)
{
services.AddOAuth(DefaultScheme, o =>
{
ConfigureDefaults(o);
o.SignInScheme = "auth1";
o.ForwardDefault = "auth1";
configure.Invoke(o);
});
var forwardDefault = new TestHandler();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
[Fact]
public async Task ForwardSignInThrows()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = "default";
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddOAuth("default", o =>
{
ConfigureDefaults(o);
o.SignInScheme = "auth1";
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
[Fact]
public async Task ForwardSignOutThrows()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = "default";
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddOAuth("default", o =>
{
ConfigureDefaults(o);
o.SignInScheme = "auth1";
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
}
[Fact]
public async Task ForwardForbidWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = "default";
o.DefaultSignInScheme = "auth1";
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddOAuth("default", o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ForbidAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(1, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardAuthenticateWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = "default";
o.DefaultSignInScheme = "auth1";
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddOAuth("default", o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardAuthenticate = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(1, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardChallengeWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = "default";
o.DefaultSignInScheme = "auth1";
o.AddScheme<TestHandler>("specific", "specific");
o.AddScheme<TestHandler2>("auth1", "auth1");
})
.AddOAuth("default", o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardChallenge = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ChallengeAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(1, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardSelectorWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = "default";
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddOAuth("default", o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, selector.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, selector.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, selector.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task NullForwardSelectorUsesDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = "default";
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddOAuth("default", o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => null;
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task SpecificForwardWinsOverSelectorAndDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = "default";
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddOAuth("default", o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
o.ForwardAuthenticate = "specific";
o.ForwardChallenge = "specific";
o.ForwardSignIn = "specific";
o.ForwardSignOut = "specific";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, specific.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, specific.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, specific.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
}
[Fact]
public async Task VerifySignInSchemeCannotBeSetToSelf()
{
var server = CreateServer(
services => services.AddAuthentication().AddOAuth("weeblie", o =>
{
o.SignInScheme = "weeblie";
o.ClientId = "whatever";
o.ClientSecret = "whatever";
o.CallbackPath = "/whatever";
o.AuthorizationEndpoint = "/whatever";
o.TokenEndpoint = "/whatever";
}));
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/"));
Assert.Contains("cannot be set to itself", error.Message);
}
[Fact]
public async Task VerifySchemeDefaults()
{
var services = new ServiceCollection();
services.AddAuthentication().AddOAuth("oauth", o => { });
var sp = services.BuildServiceProvider();
var schemeProvider = sp.GetRequiredService<IAuthenticationSchemeProvider>();
var scheme = await schemeProvider.GetSchemeAsync("oauth");
Assert.NotNull(scheme);
Assert.Equal("OAuthHandler`1", scheme.HandlerType.Name);
Assert.Equal(OAuthDefaults.DisplayName, scheme.DisplayName);
}
[Fact]
@ -654,7 +241,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
Assert.Contains("scope=baz%20qux", res.Headers.Location.Query);
}
private void ConfigureDefaults(OAuthOptions o)
protected override void ConfigureDefaults(OAuthOptions o)
{
o.ClientId = "Test Id";
o.ClientSecret = "secret";
@ -664,6 +251,101 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
o.CallbackPath = "/oauth-callback";
}
[Fact]
public async Task HandleRequestAsync_RedirectsToAccessDeniedPathWhenExplicitlySet()
{
var server = CreateServer(
s => s.AddAuthentication().AddOAuth(
"Weblie",
opt =>
{
opt.ClientId = "Test Id";
opt.ClientSecret = "secret";
opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
opt.AuthorizationEndpoint = "https://example.com/provider/login";
opt.TokenEndpoint = "https://example.com/provider/token";
opt.CallbackPath = "/oauth-callback";
opt.AccessDeniedPath = "/access-denied";
opt.StateDataFormat = new TestStateDataFormat();
opt.Events.OnRemoteFailure = context => throw new InvalidOperationException("This event should not be called.");
}));
var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=access_denied&state=protected_state",
".AspNetCore.Correlation.Weblie.correlationId=N");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
Assert.Equal("/access-denied?ReturnUrl=http%3A%2F%2Ftesthost%2Fredirect", transaction.Response.Headers.Location.ToString());
}
[Fact]
public async Task HandleRequestAsync_InvokesAccessDeniedEvent()
{
var server = CreateServer(
s => s.AddAuthentication().AddOAuth(
"Weblie",
opt =>
{
opt.ClientId = "Test Id";
opt.ClientSecret = "secret";
opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
opt.AuthorizationEndpoint = "https://example.com/provider/login";
opt.TokenEndpoint = "https://example.com/provider/token";
opt.CallbackPath = "/oauth-callback";
opt.StateDataFormat = new TestStateDataFormat();
opt.Events = new OAuthEvents()
{
OnAccessDenied = context =>
{
Assert.Equal("testvalue", context.Properties.Items["testkey"]);
context.Response.StatusCode = StatusCodes.Status406NotAcceptable;
context.HandleResponse();
return Task.CompletedTask;
}
};
}));
var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=access_denied&state=protected_state",
".AspNetCore.Correlation.Weblie.correlationId=N");
Assert.Equal(HttpStatusCode.NotAcceptable, transaction.Response.StatusCode);
Assert.Null(transaction.Response.Headers.Location);
}
[Fact]
public async Task HandleRequestAsync_InvokesRemoteFailureEventWhenAccessDeniedPathIsNotExplicitlySet()
{
var server = CreateServer(
s => s.AddAuthentication().AddOAuth(
"Weblie",
opt =>
{
opt.ClientId = "Test Id";
opt.ClientSecret = "secret";
opt.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
opt.AuthorizationEndpoint = "https://example.com/provider/login";
opt.TokenEndpoint = "https://example.com/provider/token";
opt.CallbackPath = "/oauth-callback";
opt.StateDataFormat = new TestStateDataFormat();
opt.Events = new OAuthEvents()
{
OnRemoteFailure = context =>
{
Assert.Equal("Access was denied by the resource owner or by the remote server.", context.Failure.Message);
Assert.Equal("testvalue", context.Properties.Items["testkey"]);
context.Response.StatusCode = StatusCodes.Status406NotAcceptable;
context.HandleResponse();
return Task.CompletedTask;
}
};
}));
var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=access_denied&state=protected_state",
".AspNetCore.Correlation.Weblie.correlationId=N");
Assert.Equal(HttpStatusCode.NotAcceptable, transaction.Response.StatusCode);
Assert.Null(transaction.Response.Headers.Location);
}
[Fact]
public async Task RemoteAuthenticationFailed_OAuthError_IncludesProperties()
{
@ -683,7 +365,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
{
OnRemoteFailure = context =>
{
Assert.Contains("declined", context.Failure.Message);
Assert.Contains("custom_error", context.Failure.Message);
Assert.Equal("testvalue", context.Properties.Items["testkey"]);
context.Response.StatusCode = StatusCodes.Status406NotAcceptable;
context.HandleResponse();
@ -692,8 +374,8 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
};
}));
var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=declined&state=protected_state",
".AspNetCore.Correlation.Weblie.corrilationId=N");
var transaction = await server.SendAsync("https://www.example.com/oauth-callback?error=custom_error&state=protected_state",
".AspNetCore.Correlation.Weblie.correlationId=N");
Assert.Equal(HttpStatusCode.NotAcceptable, transaction.Response.StatusCode);
Assert.Null(transaction.Response.Headers.Location);
@ -736,7 +418,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
Assert.Equal("protected_state", protectedText);
var properties = new AuthenticationProperties(new Dictionary<string, string>()
{
{ ".xsrf", "corrilationId" },
{ ".xsrf", "correlationId" },
{ "testkey", "testvalue" }
});
properties.RedirectUri = "http://testhost/redirect";

View File

@ -783,6 +783,52 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
events.ValidateExpectations();
}
[Fact]
public async Task OnAccessDenied_Skip_NoMoreEventsRun()
{
var events = new ExpectedOidcEvents()
{
ExpectMessageReceived = true,
ExpectAccessDenied = true
};
events.OnAccessDenied = context =>
{
context.SkipHandler();
return Task.FromResult(0);
};
var server = CreateServer(events, AppWritePath);
var response = await PostAsync(server, "signin-oidc", "error=access_denied&state=protected_state");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("/signin-oidc", await response.Content.ReadAsStringAsync());
events.ValidateExpectations();
}
[Fact]
public async Task OnAccessDenied_Handled_NoMoreEventsRun()
{
var events = new ExpectedOidcEvents()
{
ExpectMessageReceived = true,
ExpectAccessDenied = true
};
events.OnAccessDenied = context =>
{
Assert.Equal("testvalue", context.Properties.Items["testkey"]);
context.HandleResponse();
context.Response.StatusCode = StatusCodes.Status202Accepted;
return Task.FromResult(0);
};
var server = CreateServer(events, AppNotImpl);
var response = await PostAsync(server, "signin-oidc", "error=access_denied&state=protected_state");
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
Assert.Equal("", await response.Content.ReadAsStringAsync());
events.ValidateExpectations();
}
[Fact]
public async Task OnRemoteFailure_Skip_NoMoreEventsRun()
{
@ -1099,6 +1145,9 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
public bool ExpectTokenValidated { get; set; }
public bool InvokedTokenValidated { get; set; }
public bool ExpectAccessDenied { get; set; }
public bool InvokedAccessDenied { get; set; }
public bool ExpectRemoteFailure { get; set; }
public bool InvokedRemoteFailure { get; set; }
@ -1168,6 +1217,12 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
return base.TicketReceived(context);
}
public override Task AccessDenied(AccessDeniedContext context)
{
InvokedAccessDenied = true;
return base.AccessDenied(context);
}
public override Task RemoteFailure(RemoteFailureContext context)
{
InvokedRemoteFailure = true;
@ -1201,6 +1256,7 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
Assert.Equal(ExpectUserInfoReceived, InvokedUserInfoReceived);
Assert.Equal(ExpectAuthenticationFailed, InvokeAuthenticationFailed);
Assert.Equal(ExpectTicketReceived, InvokedTicketReceived);
Assert.Equal(ExpectAccessDenied, InvokedAccessDenied);
Assert.Equal(ExpectRemoteFailure, InvokedRemoteFailure);
Assert.Equal(ExpectRedirectForSignOut, InvokedRedirectForSignOut);
Assert.Equal(ExpectRemoteSignOut, InvokedRemoteSignOut);
@ -1248,7 +1304,7 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
private Task<HttpResponseMessage> PostAsync(TestServer server, string path, string form)
{
var client = server.CreateClient();
var cookie = ".AspNetCore.Correlation." + OpenIdConnectDefaults.AuthenticationScheme + ".corrilationId=N";
var cookie = ".AspNetCore.Correlation." + OpenIdConnectDefaults.AuthenticationScheme + ".correlationId=N";
client.DefaultRequestHeaders.Add("Cookie", cookie);
return client.PostAsync("signin-oidc",
new StringContent(form, Encoding.ASCII, "application/x-www-form-urlencoded"));
@ -1273,7 +1329,7 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
Assert.Equal("protected_state", protectedText);
var properties = new AuthenticationProperties(new Dictionary<string, string>()
{
{ ".xsrf", "corrilationId" },
{ ".xsrf", "correlationId" },
{ OpenIdConnectDefaults.RedirectUriForCodePropertiesKey, "redirect_uri" },
{ "testkey", "testvalue" }
});

View File

@ -0,0 +1,92 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNetCore.Authentication
{
public abstract class RemoteAuthenticationTests<TOptions> : SharedAuthenticationTests<TOptions> where TOptions : RemoteAuthenticationOptions
{
protected override string DisplayName => DefaultScheme;
private TestServer CreateServer(Action<TOptions> configureOptions, Func<HttpContext, Task> testpath = null, bool isDefault = true)
=> CreateServerWithServices(s =>
{
var builder = s.AddAuthentication();
if (isDefault)
{
s.Configure<AuthenticationOptions>(o => o.DefaultScheme = DefaultScheme);
}
RegisterAuth(builder, configureOptions);
s.AddSingleton<ISystemClock>(Clock);
}, testpath);
protected virtual TestServer CreateServerWithServices(Action<IServiceCollection> configureServices, Func<HttpContext, Task> testpath = null)
{
//private static TestServer CreateServer(Action<IApplicationBuilder> configure, Action<IServiceCollection> configureServices, Func<HttpContext, Task<bool>> handler)
var builder = new WebHostBuilder()
.Configure(app =>
{
app.Use(async (context, next) =>
{
if (testpath != null)
{
await testpath(context);
}
await next();
});
})
.ConfigureServices(configureServices);
return new TestServer(builder);
}
protected abstract void ConfigureDefaults(TOptions o);
[Fact]
public async Task VerifySignInSchemeCannotBeSetToSelf()
{
var server = CreateServer(
o =>
{
ConfigureDefaults(o);
o.SignInScheme = DefaultScheme;
},
context => context.ChallengeAsync(DefaultScheme));
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message);
}
[Fact]
public async Task VerifySignInSchemeCannotBeSetToSelfUsingDefaultScheme()
{
var server = CreateServer(
o => o.SignInScheme = null,
context => context.ChallengeAsync(DefaultScheme),
isDefault: true);
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message);
}
[Fact]
public async Task VerifySignInSchemeCannotBeSetToSelfUsingDefaultSignInScheme()
{
var server = CreateServerWithServices(
services =>
{
var builder = services.AddAuthentication(o => o.DefaultSignInScheme = DefaultScheme);
RegisterAuth(builder, o => o.SignInScheme = null);
},
context => context.ChallengeAsync(DefaultScheme));
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message);
}
}
}

View File

@ -0,0 +1,510 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Authentication.Tests;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNetCore.Authentication
{
public abstract class SharedAuthenticationTests<TOptions> where TOptions : AuthenticationSchemeOptions
{
protected TestClock Clock { get; } = new TestClock();
protected abstract string DefaultScheme { get; }
protected virtual string DisplayName { get; }
protected abstract Type HandlerType { get; }
protected virtual bool SupportsSignIn { get => true; }
protected virtual bool SupportsSignOut { get => true; }
protected abstract void RegisterAuth(AuthenticationBuilder services, Action<TOptions> configure);
[Fact]
public async Task CanForwardDefault()
{
var services = new ServiceCollection().AddLogging();
var builder = services.AddAuthentication(o =>
{
o.DefaultScheme = DefaultScheme;
o.AddScheme<TestHandler>("auth1", "auth1");
});
RegisterAuth(builder, o => o.ForwardDefault = "auth1");
var forwardDefault = new TestHandler();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
if (SupportsSignOut)
{
await context.SignOutAsync();
Assert.Equal(1, forwardDefault.SignOutCount);
}
else
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
}
if (SupportsSignIn)
{
await context.SignInAsync(new ClaimsPrincipal());
Assert.Equal(1, forwardDefault.SignInCount);
}
else
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
}
[Fact]
public async Task ForwardSignInWinsOverDefault()
{
if (SupportsSignIn)
{
var services = new ServiceCollection().AddLogging();
var builder = services.AddAuthentication(o =>
{
o.DefaultScheme = DefaultScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
});
RegisterAuth(builder, o =>
{
o.ForwardDefault = "auth1";
o.ForwardSignIn = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.SignInAsync(new ClaimsPrincipal());
Assert.Equal(1, specific.SignInCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
}
[Fact]
public async Task ForwardSignOutWinsOverDefault()
{
if (SupportsSignOut)
{
var services = new ServiceCollection().AddLogging();
var builder = services.AddAuthentication(o =>
{
o.DefaultScheme = DefaultScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
});
RegisterAuth(builder, o =>
{
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.SignOutAsync();
Assert.Equal(1, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
}
[Fact]
public async Task ForwardForbidWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
var builder = services.AddAuthentication(o =>
{
o.DefaultScheme = DefaultScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
});
RegisterAuth(builder, o =>
{
o.ForwardDefault = "auth1";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ForbidAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(1, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardAuthenticateWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
var builder = services.AddAuthentication(o =>
{
o.DefaultScheme = DefaultScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
});
RegisterAuth(builder, o =>
{
o.ForwardDefault = "auth1";
o.ForwardAuthenticate = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(1, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardChallengeWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
var builder = services.AddAuthentication(o =>
{
o.DefaultScheme = DefaultScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
});
RegisterAuth(builder, o =>
{
o.ForwardDefault = "auth1";
o.ForwardChallenge = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ChallengeAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(1, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardSelectorWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
var builder = services.AddAuthentication(o =>
{
o.DefaultScheme = DefaultScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
});
RegisterAuth(builder, o =>
{
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, selector.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, selector.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, selector.ChallengeCount);
if (SupportsSignOut)
{
await context.SignOutAsync();
Assert.Equal(1, selector.SignOutCount);
}
else
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
}
if (SupportsSignIn)
{
await context.SignInAsync(new ClaimsPrincipal());
Assert.Equal(1, selector.SignInCount);
}
else
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task NullForwardSelectorUsesDefault()
{
var services = new ServiceCollection().AddLogging();
var builder = services.AddAuthentication(o =>
{
o.DefaultScheme = DefaultScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
});
RegisterAuth(builder, o =>
{
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => null;
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
if (SupportsSignOut)
{
await context.SignOutAsync();
Assert.Equal(1, forwardDefault.SignOutCount);
}
else
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
}
if (SupportsSignIn)
{
await context.SignInAsync(new ClaimsPrincipal());
Assert.Equal(1, forwardDefault.SignInCount);
}
else
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task SpecificForwardWinsOverSelectorAndDefault()
{
var services = new ServiceCollection().AddLogging();
var builder = services.AddAuthentication(o =>
{
o.DefaultScheme = DefaultScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
});
RegisterAuth(builder, o =>
{
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
o.ForwardAuthenticate = "specific";
o.ForwardChallenge = "specific";
o.ForwardSignIn = "specific";
o.ForwardSignOut = "specific";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, specific.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, specific.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, specific.ChallengeCount);
if (SupportsSignOut)
{
await context.SignOutAsync();
Assert.Equal(1, specific.SignOutCount);
}
else
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
}
if (SupportsSignIn)
{
await context.SignInAsync(new ClaimsPrincipal());
Assert.Equal(1, specific.SignInCount);
}
else
{
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
}
[Fact]
public async Task VerifySchemeDefaults()
{
var services = new ServiceCollection();
var builder = services.AddAuthentication();
RegisterAuth(builder, o => { });
var sp = services.BuildServiceProvider();
var schemeProvider = sp.GetRequiredService<IAuthenticationSchemeProvider>();
var scheme = await schemeProvider.GetSchemeAsync(DefaultScheme);
Assert.NotNull(scheme);
Assert.Equal(HandlerType, scheme.HandlerType);
Assert.Equal(DisplayName, scheme.DisplayName);
}
}
}

View File

@ -1,5 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers;
using System;
using System.Linq;
using System.Net;
@ -7,440 +13,33 @@ using System.Net.Http;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Tests;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers;
using Xunit;
namespace Microsoft.AspNetCore.Authentication.Twitter
{
public class TwitterTests
public class TwitterTests : RemoteAuthenticationTests<TwitterOptions>
{
private void ConfigureDefaults(TwitterOptions o)
protected override string DefaultScheme => TwitterDefaults.AuthenticationScheme;
protected override Type HandlerType => typeof(TwitterHandler);
protected override bool SupportsSignIn { get => false; }
protected override bool SupportsSignOut { get => false; }
protected override void RegisterAuth(AuthenticationBuilder services, Action<TwitterOptions> configure)
{
services.AddTwitter(o =>
{
ConfigureDefaults(o);
configure.Invoke(o);
});
}
protected override void ConfigureDefaults(TwitterOptions o)
{
o.ConsumerKey = "whatever";
o.ConsumerSecret = "whatever";
o.SignInScheme = "auth1";
}
[Fact]
public async Task CanForwardDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = TwitterDefaults.AuthenticationScheme;
o.AddScheme<TestHandler>("auth1", "auth1");
})
.AddTwitter(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
});
var forwardDefault = new TestHandler();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
[Fact]
public async Task ForwardSignInThrows()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = TwitterDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddTwitter(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
}
[Fact]
public async Task ForwardSignOutThrows()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = TwitterDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddTwitter(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardSignOut = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
}
[Fact]
public async Task ForwardForbidWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = TwitterDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddTwitter(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ForbidAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(1, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardAuthenticateWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = TwitterDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddTwitter(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardAuthenticate = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(1, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardChallengeWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = TwitterDefaults.AuthenticationScheme;
o.AddScheme<TestHandler>("specific", "specific");
o.AddScheme<TestHandler2>("auth1", "auth1");
})
.AddTwitter(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardChallenge = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.ChallengeAsync();
Assert.Equal(0, specific.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(1, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
}
[Fact]
public async Task ForwardSelectorWinsOverDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = TwitterDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddTwitter(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, selector.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, selector.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, selector.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task NullForwardSelectorUsesDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = TwitterDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddTwitter(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => null;
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, forwardDefault.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, forwardDefault.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, forwardDefault.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
Assert.Equal(0, specific.AuthenticateCount);
Assert.Equal(0, specific.ForbidCount);
Assert.Equal(0, specific.ChallengeCount);
Assert.Equal(0, specific.SignInCount);
Assert.Equal(0, specific.SignOutCount);
}
[Fact]
public async Task SpecificForwardWinsOverSelectorAndDefault()
{
var services = new ServiceCollection().AddLogging();
services.AddAuthentication(o =>
{
o.DefaultScheme = TwitterDefaults.AuthenticationScheme;
o.AddScheme<TestHandler2>("auth1", "auth1");
o.AddScheme<TestHandler3>("selector", "selector");
o.AddScheme<TestHandler>("specific", "specific");
})
.AddTwitter(o =>
{
ConfigureDefaults(o);
o.ForwardDefault = "auth1";
o.ForwardDefaultSelector = _ => "selector";
o.ForwardAuthenticate = "specific";
o.ForwardChallenge = "specific";
o.ForwardSignIn = "specific";
o.ForwardSignOut = "specific";
o.ForwardForbid = "specific";
});
var specific = new TestHandler();
services.AddSingleton(specific);
var forwardDefault = new TestHandler2();
services.AddSingleton(forwardDefault);
var selector = new TestHandler3();
services.AddSingleton(selector);
var sp = services.BuildServiceProvider();
var context = new DefaultHttpContext();
context.RequestServices = sp;
await context.AuthenticateAsync();
Assert.Equal(1, specific.AuthenticateCount);
await context.ForbidAsync();
Assert.Equal(1, specific.ForbidCount);
await context.ChallengeAsync();
Assert.Equal(1, specific.ChallengeCount);
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignOutAsync());
await Assert.ThrowsAsync<InvalidOperationException>(() => context.SignInAsync(new ClaimsPrincipal()));
Assert.Equal(0, forwardDefault.AuthenticateCount);
Assert.Equal(0, forwardDefault.ForbidCount);
Assert.Equal(0, forwardDefault.ChallengeCount);
Assert.Equal(0, forwardDefault.SignInCount);
Assert.Equal(0, forwardDefault.SignOutCount);
Assert.Equal(0, selector.AuthenticateCount);
Assert.Equal(0, selector.ForbidCount);
Assert.Equal(0, selector.ChallengeCount);
Assert.Equal(0, selector.SignInCount);
Assert.Equal(0, selector.SignOutCount);
}
[Fact]
public async Task VerifySignInSchemeCannotBeSetToSelf()
{
var server = CreateServer(o =>
{
o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret";
o.SignInScheme = TwitterDefaults.AuthenticationScheme;
});
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => server.SendAsync("https://example.com/challenge"));
Assert.Contains("cannot be set to itself", error.Message);
}
[Fact]
public async Task VerifySchemeDefaults()
{
var services = new ServiceCollection();
services.AddAuthentication().AddTwitter();
var sp = services.BuildServiceProvider();
var schemeProvider = sp.GetRequiredService<IAuthenticationSchemeProvider>();
var scheme = await schemeProvider.GetSchemeAsync(TwitterDefaults.AuthenticationScheme);
Assert.NotNull(scheme);
Assert.Equal("TwitterHandler", scheme.HandlerType.Name);
Assert.Equal(TwitterDefaults.AuthenticationScheme, scheme.DisplayName);
}
[Fact]
public async Task ChallengeWillTriggerApplyRedirectEvent()
{
@ -575,6 +174,94 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
Assert.Contains("https://api.twitter.com/oauth/authenticate?oauth_token=", location);
}
[Fact]
public async Task HandleRequestAsync_RedirectsToAccessDeniedPathWhenExplicitlySet()
{
var server = CreateServer(o =>
{
o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret";
o.BackchannelHttpHandler = new TestHttpMessageHandler
{
Sender = BackchannelRequestToken
};
o.AccessDeniedPath = "/access-denied";
o.Events.OnRemoteFailure = context => throw new InvalidOperationException("This event should not be called.");
},
async context =>
{
var properties = new AuthenticationProperties();
properties.Items["testkey"] = "testvalue";
await context.ChallengeAsync("Twitter", properties);
return true;
});
var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri;
Assert.Contains("https://api.twitter.com/oauth/authenticate?oauth_token=", location);
Assert.True(transaction.Response.Headers.TryGetValues(HeaderNames.SetCookie, out var setCookie));
Assert.True(SetCookieHeaderValue.TryParseList(setCookie.ToList(), out var setCookieValues));
Assert.Single(setCookieValues);
var setCookieValue = setCookieValues.Single();
var cookie = new CookieHeaderValue(setCookieValue.Name, setCookieValue.Value);
var request = new HttpRequestMessage(HttpMethod.Get, "/signin-twitter?denied=ABCDEFG");
request.Headers.Add(HeaderNames.Cookie, cookie.ToString());
var client = server.CreateClient();
var response = await client.SendAsync(request);
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
Assert.Equal("/access-denied?ReturnUrl=%2Fchallenge", response.Headers.Location.ToString());
}
[Fact]
public async Task BadCallbackCallsAccessDeniedWithState()
{
var server = CreateServer(o =>
{
o.ConsumerKey = "Test Consumer Key";
o.ConsumerSecret = "Test Consumer Secret";
o.BackchannelHttpHandler = new TestHttpMessageHandler
{
Sender = BackchannelRequestToken
};
o.Events = new TwitterEvents()
{
OnAccessDenied = context =>
{
Assert.NotNull(context.Properties);
Assert.Equal("testvalue", context.Properties.Items["testkey"]);
context.Response.StatusCode = StatusCodes.Status406NotAcceptable;
context.HandleResponse();
return Task.CompletedTask;
}
};
},
async context =>
{
var properties = new AuthenticationProperties();
properties.Items["testkey"] = "testvalue";
await context.ChallengeAsync("Twitter", properties);
return true;
});
var transaction = await server.SendAsync("http://example.com/challenge");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
var location = transaction.Response.Headers.Location.AbsoluteUri;
Assert.Contains("https://api.twitter.com/oauth/authenticate?oauth_token=", location);
Assert.True(transaction.Response.Headers.TryGetValues(HeaderNames.SetCookie, out var setCookie));
Assert.True(SetCookieHeaderValue.TryParseList(setCookie.ToList(), out var setCookieValues));
Assert.Single(setCookieValues);
var setCookieValue = setCookieValues.Single();
var cookie = new CookieHeaderValue(setCookieValue.Name, setCookieValue.Value);
var request = new HttpRequestMessage(HttpMethod.Get, "/signin-twitter?denied=ABCDEFG");
request.Headers.Add(HeaderNames.Cookie, cookie.ToString());
var client = server.CreateClient();
var response = await client.SendAsync(request);
Assert.Equal(HttpStatusCode.NotAcceptable, response.StatusCode);
}
[Fact]
public async Task BadCallbackCallsRemoteAuthFailedWithState()
{
@ -591,7 +278,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
OnRemoteFailure = context =>
{
Assert.NotNull(context.Failure);
Assert.Equal("The user denied permissions.", context.Failure.Message);
Assert.Equal("Access was denied by the resource owner or by the remote server.", context.Failure.Message);
Assert.NotNull(context.Properties);
Assert.Equal("testvalue", context.Properties.Items["testkey"]);
context.Response.StatusCode = StatusCodes.Status406NotAcceptable;

View File

@ -0,0 +1,65 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization.Test.TestObjects;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Builder.Internal;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Microsoft.AspNetCore.Authorization.Test
{
public class AuthorizationAppBuilderExtensionsTests
{
[Fact]
public async Task UseAuthorization_RegistersMiddleware()
{
// Arrange
var authenticationService = new TestAuthenticationService();
var services = CreateServices(authenticationService);
var app = new ApplicationBuilder(services);
app.UseAuthorization();
var appFunc = app.Build();
var endpoint = new Endpoint(
null,
new EndpointMetadataCollection(new AuthorizeAttribute()),
"Test endpoint");
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = services;
httpContext.SetEndpoint(endpoint);
// Act
await appFunc(httpContext);
// Assert
Assert.True(authenticationService.ChallengeCalled);
}
private IServiceProvider CreateServices(IAuthenticationService authenticationService)
{
var services = new ServiceCollection();
services.AddAuthorization(options => { });
services.AddAuthorizationPolicyEvaluator();
services.AddLogging();
services.AddSingleton(authenticationService);
var serviceProvder = services.BuildServiceProvider();
return serviceProvder;
}
}
}

View File

@ -0,0 +1,63 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Patterns;
using Xunit;
namespace Microsoft.AspNetCore.Authorization.Test
{
public class AuthorizationEndpointConventionBuilderExtensionsTests
{
[Fact]
public void RequireAuthorization_IAuthorizeData()
{
// Arrange
var builder = new TestEndpointConventionBuilder();
var metadata = new AuthorizeAttribute();
// Act
builder.RequireAuthorization(metadata);
// Assert
var convention = Assert.Single(builder.Conventions);
var endpointModel = new RouteEndpointModel((context) => Task.CompletedTask, RoutePatternFactory.Parse("/"), 0);
convention(endpointModel);
Assert.Equal(metadata, Assert.Single(endpointModel.Metadata));
}
[Fact]
public void RequireAuthorization_PolicyName()
{
// Arrange
var builder = new TestEndpointConventionBuilder();
// Act
builder.RequireAuthorization("policy");
// Assert
var convention = Assert.Single(builder.Conventions);
var endpointModel = new RouteEndpointModel((context) => Task.CompletedTask, RoutePatternFactory.Parse("/"), 0);
convention(endpointModel);
Assert.Equal("policy", Assert.IsAssignableFrom<IAuthorizeData>(Assert.Single(endpointModel.Metadata)).Policy);
}
private class TestEndpointConventionBuilder : IEndpointConventionBuilder
{
public IList<Action<EndpointModel>> Conventions { get; } = new List<Action<EndpointModel>>();
public void Apply(Action<EndpointModel> convention)
{
Conventions.Add(convention);
}
}
}
}

View File

@ -0,0 +1,459 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Microsoft.AspNetCore.Authorization.Test.TestObjects;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Authorization.Test
{
public class AuthorizationMiddlewareTests
{
[Fact]
public async Task NoEndpoint_AnonymousUser_Allows()
{
// Arrange
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(anonymous: true);
// Act
await middleware.Invoke(context);
// Assert
Assert.True(next.Called);
}
[Fact]
public async Task NoEndpointWithRequired_AnonymousUser_Challenges()
{
// Arrange
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetRequiredPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(anonymous: true);
// Act
await middleware.Invoke(context);
// Assert
Assert.False(next.Called);
}
[Fact]
public async Task HasEndpointWithoutAuth_AnonymousUser_Allows()
{
// Arrange
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(anonymous: true, endpoint: CreateEndpoint());
// Act
await middleware.Invoke(context);
// Assert
Assert.True(next.Called);
}
[Fact]
public async Task HasEndpointWithRequiredWithoutAuth_AnonymousUser_Challenges()
{
// Arrange
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
policyProvider.Setup(p => p.GetRequiredPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(anonymous: true, endpoint: CreateEndpoint());
// Act
await middleware.Invoke(context);
// Assert
Assert.False(next.Called);
}
[Fact]
public async Task HasEndpointWithAuth_AnonymousUser_Challenges()
{
// Arrange
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var authenticationService = new TestAuthenticationService();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(anonymous: true, endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService);
// Act
await middleware.Invoke(context);
// Assert
Assert.False(next.Called);
Assert.True(authenticationService.ChallengeCalled);
}
[Fact]
public async Task HasEndpointWithAuth_AnonymousUser_ChallengePerScheme()
{
// Arrange
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().AddAuthenticationSchemes("schema1", "schema2").Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var authenticationService = new TestAuthenticationService();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(anonymous: true, endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService);
// Act
await middleware.Invoke(context);
// Assert
Assert.False(next.Called);
Assert.Equal(2, authenticationService.ChallengeCount);
}
[Fact]
public async Task OnAuthorizationAsync_WillCallPolicyProvider()
{
// Arrange
var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
var getPolicyCount = 0;
var getRequiredPolicyCount = 0;
policyProvider.Setup(p => p.GetPolicyAsync(It.IsAny<string>())).ReturnsAsync(policy)
.Callback(() => getPolicyCount++);
policyProvider.Setup(p => p.GetRequiredPolicyAsync()).ReturnsAsync(policy)
.Callback(() => getRequiredPolicyCount++);
var next = new TestRequestDelegate();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(anonymous: true, endpoint: CreateEndpoint(new AuthorizeAttribute("whatever")));
// Act & Assert
await middleware.Invoke(context);
Assert.Equal(1, getPolicyCount);
Assert.Equal(1, getRequiredPolicyCount);
Assert.Equal(1, next.CalledCount);
await middleware.Invoke(context);
Assert.Equal(2, getPolicyCount);
Assert.Equal(2, getRequiredPolicyCount);
Assert.Equal(2, next.CalledCount);
await middleware.Invoke(context);
Assert.Equal(3, getPolicyCount);
Assert.Equal(3, getRequiredPolicyCount);
Assert.Equal(3, next.CalledCount);
}
[Fact]
public async Task Invoke_ValidClaimShouldNotFail()
{
// Arrange
var policy = new AuthorizationPolicyBuilder().RequireClaim("Permission", "CanViewPage").Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute()));
// Act
await middleware.Invoke(context);
// Assert
Assert.True(next.Called);
}
[Fact]
public async Task HasEndpointWithAuthAndAllowAnonymous_AnonymousUser_Allows()
{
// Arrange
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var authenticationService = new TestAuthenticationService();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(anonymous: true, endpoint: CreateEndpoint(new AuthorizeAttribute(), new AllowAnonymousAttribute()), authenticationService: authenticationService);
// Act
await middleware.Invoke(context);
// Assert
Assert.True(next.Called);
Assert.False(authenticationService.ChallengeCalled);
}
[Fact]
public async Task HasEndpointWithAuth_AuthenticatedUser_Allows()
{
// Arrange
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var authenticationService = new TestAuthenticationService();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService);
// Act
await middleware.Invoke(context);
// Assert
Assert.True(next.Called);
Assert.False(authenticationService.ChallengeCalled);
}
[Fact]
public async Task Invoke_AuthSchemesFailShouldSetEmptyPrincipalOnContext()
{
// Arrange
var policy = new AuthorizationPolicyBuilder("Fails").RequireAuthenticatedUser().Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var authenticationService = new TestAuthenticationService();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService);
// Act
await middleware.Invoke(context);
// Assert
Assert.False(next.Called);
Assert.NotNull(context.User?.Identity);
Assert.True(authenticationService.AuthenticateCalled);
Assert.True(authenticationService.ChallengeCalled);
}
[Fact]
public async Task Invoke_SingleValidClaimShouldSucceed()
{
// Arrange
var policy = new AuthorizationPolicyBuilder().RequireClaim("Permission", "CanViewComment", "CanViewPage").Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute()));
// Act
await middleware.Invoke(context);
// Assert
Assert.True(next.Called);
}
[Fact]
public async Task AuthZResourceShouldBeEndpoint()
{
// Arrange
object resource = null;
var policy = new AuthorizationPolicyBuilder().RequireAssertion(c =>
{
resource = c.Resource;
return true;
}).Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var endpoint = CreateEndpoint(new AuthorizeAttribute());
var context = GetHttpContext(endpoint: endpoint);
// Act
await middleware.Invoke(context);
// Assert
Assert.Equal(endpoint, resource);
}
[Fact]
public async Task Invoke_RequireUnknownRoleShouldForbid()
{
// Arrange
var policy = new AuthorizationPolicyBuilder().RequireRole("Wut").Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var authenticationService = new TestAuthenticationService();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService);
// Act
await middleware.Invoke(context);
// Assert
Assert.False(next.Called);
Assert.False(authenticationService.ChallengeCalled);
Assert.True(authenticationService.ForbidCalled);
}
[Fact]
public async Task Invoke_RequireUnknownRole_ForbidPerScheme()
{
// Arrange
var policy = new AuthorizationPolicyBuilder().RequireRole("Wut").AddAuthenticationSchemes("Basic", "Bearer").Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var authenticationService = new TestAuthenticationService();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService);
// Act
await middleware.Invoke(context);
// Assert
Assert.False(next.Called);
Assert.Equal(2, authenticationService.ForbidCount);
}
[Fact]
public async Task Invoke_InvalidClaimShouldForbid()
{
// Arrange
var policy = new AuthorizationPolicyBuilder()
.RequireClaim("Permission", "CanViewComment")
.Build();
var policyProvider = new Mock<IAuthorizationPolicyProvider>();
policyProvider.Setup(p => p.GetDefaultPolicyAsync()).ReturnsAsync(policy);
var next = new TestRequestDelegate();
var authenticationService = new TestAuthenticationService();
var middleware = CreateMiddleware(next.Invoke, policyProvider.Object);
var context = GetHttpContext(endpoint: CreateEndpoint(new AuthorizeAttribute()), authenticationService: authenticationService);
// Act
await middleware.Invoke(context);
// Assert
Assert.False(next.Called);
Assert.False(authenticationService.ChallengeCalled);
Assert.True(authenticationService.ForbidCalled);
}
private AuthorizationMiddleware CreateMiddleware(RequestDelegate requestDelegate = null, IAuthorizationPolicyProvider policyProvider = null)
{
requestDelegate = requestDelegate ?? ((context) => Task.CompletedTask);
return new AuthorizationMiddleware(requestDelegate, policyProvider);
}
private Endpoint CreateEndpoint(params object[] metadata)
{
return new Endpoint(context => Task.CompletedTask, new EndpointMetadataCollection(metadata), "Test endpoint");
}
private HttpContext GetHttpContext(
bool anonymous = false,
Action<IServiceCollection> registerServices = null,
Endpoint endpoint = null,
IAuthenticationService authenticationService = null)
{
var basicPrincipal = new ClaimsPrincipal(
new ClaimsIdentity(
new Claim[] {
new Claim("Permission", "CanViewPage"),
new Claim(ClaimTypes.Role, "Administrator"),
new Claim(ClaimTypes.Role, "User"),
new Claim(ClaimTypes.NameIdentifier, "John")},
"Basic"));
var validUser = basicPrincipal;
var bearerIdentity = new ClaimsIdentity(
new Claim[] {
new Claim("Permission", "CupBearer"),
new Claim(ClaimTypes.Role, "Token"),
new Claim(ClaimTypes.NameIdentifier, "John Bear")},
"Bearer");
validUser.AddIdentity(bearerIdentity);
// ServiceProvider
var serviceCollection = new ServiceCollection();
authenticationService = authenticationService ?? Mock.Of<IAuthenticationService>();
serviceCollection.AddSingleton(authenticationService);
serviceCollection.AddOptions();
serviceCollection.AddLogging();
serviceCollection.AddAuthorization();
serviceCollection.AddAuthorizationPolicyEvaluator();
registerServices?.Invoke(serviceCollection);
var serviceProvider = serviceCollection.BuildServiceProvider();
//// HttpContext
var httpContext = new DefaultHttpContext();
if (endpoint != null)
{
httpContext.SetEndpoint(endpoint);
}
httpContext.RequestServices = serviceProvider;
if (!anonymous)
{
httpContext.User = validUser;
}
return httpContext;
}
private class TestRequestDelegate
{
private readonly int _statusCode;
public bool Called => CalledCount > 0;
public int CalledCount { get; private set; }
public TestRequestDelegate(int statusCode = 200)
{
_statusCode = statusCode;
}
public Task Invoke(HttpContext context)
{
CalledCount++;
context.Response.StatusCode = _statusCode;
return Task.CompletedTask;
}
}
}
}

View File

@ -1025,6 +1025,11 @@ namespace Microsoft.AspNetCore.Authorization.Test
return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
}
public Task<AuthorizationPolicy> GetRequiredPolicyAsync()
{
return Task.FromResult<AuthorizationPolicy>(null);
}
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
@ -1059,6 +1064,11 @@ namespace Microsoft.AspNetCore.Authorization.Test
return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
}
public Task<AuthorizationPolicy> GetRequiredPolicyAsync()
{
return Task.FromResult<AuthorizationPolicy>(null);
}
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
return Task.FromResult(new AuthorizationPolicyBuilder().RequireClaim(policyName).Build());

View File

@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);NU1605</NoWarn>
</PropertyGroup>
<ItemGroup>
@ -11,8 +12,10 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="$(MicrosoftAspNetCoreHttpPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="$(MicrosoftAspNetCoreHttpAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsDependencyInjectionPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsLoggingPackageVersion)" />
<PackageReference Include="Moq" Version="$(MoqPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,58 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authorization.Test.TestObjects
{
public class TestAuthenticationService : IAuthenticationService
{
public bool ChallengeCalled => ChallengeCount > 0;
public bool ForbidCalled => ForbidCount > 0;
public bool AuthenticateCalled => AuthenticateCount > 0;
public int ChallengeCount { get; private set; }
public int ForbidCount { get; private set; }
public int AuthenticateCount { get; private set; }
public Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string scheme)
{
AuthenticateCount++;
var identity = context.User.Identities.SingleOrDefault(i => i.AuthenticationType == scheme);
if (identity != null)
{
return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(identity), scheme)));
}
return Task.FromResult(AuthenticateResult.Fail("Denied"));
}
public Task ChallengeAsync(HttpContext context, string scheme, AuthenticationProperties properties)
{
ChallengeCount++;
return Task.CompletedTask;
}
public Task ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties)
{
ForbidCount++;
return Task.CompletedTask;
}
public Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties)
{
throw new NotImplementedException();
}
public Task SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties)
{
throw new NotImplementedException();
}
}
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -1,6 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
/* See https://github.com/aspnet/AspNetCore/issues/4074.
This test is was disabled as a part of changing frameworks. This test will need to be re-written using separate .NET Core and .NET Framework processes.
using System.Collections.Generic;
using System.IO;
using System.Linq;
@ -330,3 +334,4 @@ namespace Microsoft.Owin.Security.Interop
}
}
*/

View File

@ -2,10 +2,11 @@
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<!-- Temporarily disables tests for this project. They need to be refactored now that aspnetcore only supports netcoreapp3.0. -->
<IsTestProject>false</IsTestProject>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
<ProjectReference Include="..\..\src\Microsoft.Owin.Security.Interop\Microsoft.Owin.Security.Interop.csproj" />
</ItemGroup>

View File

@ -1,6 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
/*
using System;
using System.Linq;
using System.Security.Claims;
@ -87,5 +89,6 @@ namespace Microsoft.Owin.Security.Interop.Test
}
}
}
*/

View File

@ -1,7 +1,7 @@
<Project>
<Project>
<PropertyGroup>
<VersionPrefix>2.2.0</VersionPrefix>
<VersionSuffix>rtm</VersionSuffix>
<VersionPrefix>3.0.0</VersionPrefix>
<VersionSuffix>alpha1</VersionSuffix>
<PackageVersion Condition="'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' == 'rtm' ">$(VersionPrefix)</PackageVersion>
<PackageVersion Condition="'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' != 'rtm' ">$(VersionPrefix)-$(VersionSuffix)-final</PackageVersion>
<BuildNumber Condition="'$(BuildNumber)' == ''">t000</BuildNumber>