AuthZ 2.0 changes + react to Http

This commit is contained in:
Hao Kung 2017-05-25 18:29:19 -07:00
parent 30392a1811
commit e940cdb36b
53 changed files with 1029 additions and 465 deletions

View File

@ -62,6 +62,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
build\repo.props = build\repo.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authorization.Policy", "src\Microsoft.AspNetCore.Authorization.Policy\Microsoft.AspNetCore.Authorization.Policy.csproj", "{58194599-F07D-47A3-9DF2-E21A22C5EF9E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Abstractions", "..\HttpAbstractions\src\Microsoft.AspNetCore.Authentication.Abstractions\Microsoft.AspNetCore.Authentication.Abstractions.csproj", "{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Core", "..\HttpAbstractions\src\Microsoft.AspNetCore.Authentication.Core\Microsoft.AspNetCore.Authentication.Core.csproj", "{85545633-7E70-47EA-8CD2-30654C80112C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -436,6 +442,54 @@ Global
{51563775-C659-4907-9BAF-9995BAB87D01}.Release|x64.Build.0 = Release|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Release|x86.ActiveCfg = Release|Any CPU
{51563775-C659-4907-9BAF-9995BAB87D01}.Release|x86.Build.0 = Release|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|x64.ActiveCfg = Debug|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|x64.Build.0 = Debug|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|x86.ActiveCfg = Debug|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|x86.Build.0 = Debug|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|Any CPU.Build.0 = Release|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|x64.ActiveCfg = Release|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|x64.Build.0 = Release|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|x86.ActiveCfg = Release|Any CPU
{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|x86.Build.0 = Release|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Debug|x64.ActiveCfg = Debug|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Debug|x64.Build.0 = Debug|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Debug|x86.ActiveCfg = Debug|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Debug|x86.Build.0 = Debug|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Release|Any CPU.Build.0 = Release|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Release|x64.ActiveCfg = Release|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Release|x64.Build.0 = Release|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Release|x86.ActiveCfg = Release|Any CPU
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D}.Release|x86.Build.0 = Release|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Debug|x64.ActiveCfg = Debug|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Debug|x64.Build.0 = Debug|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Debug|x86.ActiveCfg = Debug|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Debug|x86.Build.0 = Debug|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Release|Any CPU.Build.0 = Release|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Release|x64.ActiveCfg = Release|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Release|x64.Build.0 = Release|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Release|x86.ActiveCfg = Release|Any CPU
{85545633-7E70-47EA-8CD2-30654C80112C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -464,5 +518,8 @@ Global
{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
{3A7AD414-EBDE-4F92-B307-4E8F19B6117E} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
{51563775-C659-4907-9BAF-9995BAB87D01} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
{58194599-F07D-47A3-9DF2-E21A22C5EF9E} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
{97D7B36D-1C0D-4F6D-A6A2-808BB7A4574D} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
{85545633-7E70-47EA-8CD2-30654C80112C} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
EndGlobalSection
EndGlobal

View File

@ -247,7 +247,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
}
}
protected override async Task HandleSignInAsync(SignInContext signin)
protected override async Task HandleSignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
{
_signInCalled = true;
@ -259,8 +259,8 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
Context,
Scheme,
Options,
signin.Principal,
signin.Properties,
user,
properties,
cookieOptions);
DateTimeOffset issuedUtc;
@ -325,7 +325,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
await ApplyHeaders(shouldRedirect, signedInContext.Properties);
}
protected override async Task HandleSignOutAsync(SignOutContext signOutContext)
protected override async Task HandleSignOutAsync(AuthenticationProperties properties)
{
_signOutCalled = true;
@ -341,7 +341,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
Context,
Scheme,
Options,
signOutContext.Properties,
properties,
cookieOptions);
await Events.SigningOut(context);
@ -401,9 +401,8 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
return path[0] == '/' && path[1] != '/' && path[1] != '\\';
}
protected override async Task HandleForbiddenAsync(ChallengeContext context)
protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
{
var properties = context.Properties;
var returnUrl = properties.RedirectUri;
if (string.IsNullOrEmpty(returnUrl))
{
@ -414,14 +413,8 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
await Events.RedirectToAccessDenied(redirectContext);
}
protected override async Task HandleUnauthorizedAsync(ChallengeContext context)
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var properties = context.Properties;
var redirectUri = properties.RedirectUri;
if (string.IsNullOrEmpty(redirectUri))
{

View File

@ -2,15 +2,15 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
namespace Microsoft.AspNetCore.Authentication.Facebook
{
internal class FacebookConfigureOptions : ConfigureNamedOptions<FacebookOptions>
internal class FacebookConfigureOptions : ConfigureDefaultOptions<FacebookOptions>
{
public FacebookConfigureOptions(IConfiguration config) :
base(FacebookDefaults.AuthenticationScheme,
options => config.GetSection(FacebookDefaults.AuthenticationScheme).Bind(options))
options => config.GetSection("Microsoft:AspNetCore:Authentication:Schemes:"+FacebookDefaults.AuthenticationScheme).Bind(options))
{ }
}
}

View File

@ -3,29 +3,21 @@
using System;
using Microsoft.AspNetCore.Authentication.Facebook;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
namespace Microsoft.Extensions.DependencyInjection
{
public static class FacebookAuthenticationOptionsExtensions
{
/// <summary>
/// Adds facebook authentication with options bound against the "Facebook" section
/// from the IConfiguration in the service container.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddFacebookAuthentication(this IServiceCollection services)
{
services.AddSingleton<IConfigureOptions<FacebookOptions>, FacebookConfigureOptions>();
return services.AddFacebookAuthentication(FacebookDefaults.AuthenticationScheme, _ => { });
}
public static IServiceCollection AddFacebookAuthentication(this IServiceCollection services)
=> services.AddFacebookAuthentication(FacebookDefaults.AuthenticationScheme, _ => { });
public static IServiceCollection AddFacebookAuthentication(this IServiceCollection services, Action<FacebookOptions> configureOptions)
=> services.AddFacebookAuthentication(FacebookDefaults.AuthenticationScheme, configureOptions);
public static IServiceCollection AddFacebookAuthentication(this IServiceCollection services, string authenticationScheme, Action<FacebookOptions> configureOptions)
{
services.AddSingleton<ConfigureDefaultOptions<FacebookOptions>, FacebookConfigureOptions>();
return services.AddOAuthAuthentication<FacebookOptions, FacebookHandler>(authenticationScheme, configureOptions);
}
}

View File

@ -2,15 +2,15 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
namespace Microsoft.AspNetCore.Authentication.Google
{
internal class GoogleConfigureOptions : ConfigureNamedOptions<GoogleOptions>
internal class GoogleConfigureOptions : ConfigureDefaultOptions<GoogleOptions>
{
public GoogleConfigureOptions(IConfiguration config) :
base(GoogleDefaults.AuthenticationScheme,
options => config.GetSection(GoogleDefaults.AuthenticationScheme).Bind(options))
options => config.GetSection("Microsoft:AspNetCore:Authentication:Schemes:"+GoogleDefaults.AuthenticationScheme).Bind(options))
{ }
}
}

View File

@ -3,29 +3,21 @@
using System;
using Microsoft.AspNetCore.Authentication.Google;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
namespace Microsoft.Extensions.DependencyInjection
{
public static class GoogleExtensions
{
/// <summary>
/// Adds google authentication with options bound against the "Google" section
/// from the IConfiguration in the service container.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddGoogleAuthentication(this IServiceCollection services)
{
services.AddSingleton<IConfigureOptions<GoogleOptions>, GoogleConfigureOptions>();
return services.AddGoogleAuthentication(GoogleDefaults.AuthenticationScheme, _ => { });
}
public static IServiceCollection AddGoogleAuthentication(this IServiceCollection services)
=> services.AddGoogleAuthentication(GoogleDefaults.AuthenticationScheme, _ => { });
public static IServiceCollection AddGoogleAuthentication(this IServiceCollection services, Action<GoogleOptions> configureOptions)
=> services.AddGoogleAuthentication(GoogleDefaults.AuthenticationScheme, configureOptions);
public static IServiceCollection AddGoogleAuthentication(this IServiceCollection services, string authenticationScheme, Action<GoogleOptions> configureOptions)
{
services.AddSingleton<ConfigureDefaultOptions<GoogleOptions>, GoogleConfigureOptions>();
return services.AddOAuthAuthentication<GoogleOptions, GoogleHandler>(authenticationScheme, configureOptions);
}
}

View File

@ -2,16 +2,16 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
namespace Microsoft.AspNetCore.Authentication.JwtBearer
{
internal class JwtBearerConfigureOptions : ConfigureNamedOptions<JwtBearerOptions>
internal class JwtBearerConfigureOptions : ConfigureDefaultOptions<JwtBearerOptions>
{
// Bind to "Bearer" section by default
public JwtBearerConfigureOptions(IConfiguration config) :
base(JwtBearerDefaults.AuthenticationScheme,
options => config.GetSection(JwtBearerDefaults.AuthenticationScheme).Bind(options))
options => config.GetSection("Microsoft:AspNetCore:Authentication:Schemes:"+JwtBearerDefaults.AuthenticationScheme).Bind(options))
{ }
}
}

View File

@ -5,22 +5,14 @@ using System;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
namespace Microsoft.Extensions.DependencyInjection
{
public static class JwtBearerExtensions
{
/// <summary>
/// Adds JwtBearer authentication with options bound against the "Bearer" section
/// from the IConfiguration in the service container.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddJwtBearerAuthentication(this IServiceCollection services)
{
services.AddSingleton<IConfigureOptions<JwtBearerOptions>, JwtBearerConfigureOptions>();
return services.AddJwtBearerAuthentication(JwtBearerDefaults.AuthenticationScheme, _ => { });
}
public static IServiceCollection AddJwtBearerAuthentication(this IServiceCollection services)
=> services.AddJwtBearerAuthentication(JwtBearerDefaults.AuthenticationScheme, _ => { });
public static IServiceCollection AddJwtBearerAuthentication(this IServiceCollection services, Action<JwtBearerOptions> configureOptions)
=> services.AddJwtBearerAuthentication(JwtBearerDefaults.AuthenticationScheme, configureOptions);
@ -28,6 +20,7 @@ namespace Microsoft.Extensions.DependencyInjection
public static IServiceCollection AddJwtBearerAuthentication(this IServiceCollection services, string authenticationScheme, Action<JwtBearerOptions> configureOptions)
{
services.TryAddEnumerable(ServiceDescriptor.Singleton<IInitializeOptions<JwtBearerOptions>, JwtBearerInitializer>());
services.AddSingleton<ConfigureDefaultOptions<JwtBearerOptions>, JwtBearerConfigureOptions>();
return services.AddScheme<JwtBearerOptions, JwtBearerHandler>(authenticationScheme, configureOptions);
}
}

View File

@ -201,10 +201,10 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}
}
protected override async Task HandleUnauthorizedAsync(ChallengeContext context)
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
{
var authResult = await HandleAuthenticateOnceSafeAsync();
var eventContext = new JwtBearerChallengeContext(Context, Scheme, Options, context.Properties)
var eventContext = new JwtBearerChallengeContext(Context, Scheme, Options, properties)
{
AuthenticateFailure = authResult?.Failure
};
@ -330,12 +330,12 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
return string.Join("; ", messages);
}
protected override Task HandleSignOutAsync(SignOutContext context)
protected override Task HandleSignOutAsync(AuthenticationProperties properties)
{
throw new NotSupportedException();
}
protected override Task HandleSignInAsync(SignInContext context)
protected override Task HandleSignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
{
throw new NotSupportedException();
}

View File

@ -2,16 +2,16 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
{
internal class MicrosoftAccountConfigureOptions : ConfigureNamedOptions<MicrosoftAccountOptions>
internal class MicrosoftAccountConfigureOptions : ConfigureDefaultOptions<MicrosoftAccountOptions>
{
// Bind to "Microsoft" section by default
public MicrosoftAccountConfigureOptions(IConfiguration config) :
base(MicrosoftAccountDefaults.AuthenticationScheme,
options => config.GetSection(MicrosoftAccountDefaults.AuthenticationScheme).Bind(options))
options => config.GetSection("Microsoft:AspNetCore:Authentication:Schemes:"+MicrosoftAccountDefaults.AuthenticationScheme).Bind(options))
{ }
}
}

View File

@ -3,29 +3,21 @@
using System;
using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
namespace Microsoft.Extensions.DependencyInjection
{
public static class MicrosoftAccountExtensions
{
/// <summary>
/// Adds MicrosoftAccount authentication with options bound against the "Microsoft" section
/// from the IConfiguration in the service container.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddMicrosoftAccountAuthentication(this IServiceCollection services)
{
services.AddSingleton<IConfigureOptions<MicrosoftAccountOptions>, MicrosoftAccountConfigureOptions>();
return services.AddMicrosoftAccountAuthentication(MicrosoftAccountDefaults.AuthenticationScheme, o => { });
}
public static IServiceCollection AddMicrosoftAccountAuthentication(this IServiceCollection services)
=> services.AddMicrosoftAccountAuthentication(MicrosoftAccountDefaults.AuthenticationScheme, _ => { });
public static IServiceCollection AddMicrosoftAccountAuthentication(this IServiceCollection services, Action<MicrosoftAccountOptions> configureOptions) =>
services.AddMicrosoftAccountAuthentication(MicrosoftAccountDefaults.AuthenticationScheme, configureOptions);
public static IServiceCollection AddMicrosoftAccountAuthentication(this IServiceCollection services, Action<MicrosoftAccountOptions> configureOptions)
=> services.AddMicrosoftAccountAuthentication(MicrosoftAccountDefaults.AuthenticationScheme, configureOptions);
public static IServiceCollection AddMicrosoftAccountAuthentication(this IServiceCollection services, string authenticationScheme, Action<MicrosoftAccountOptions> configureOptions)
{
services.AddSingleton<ConfigureDefaultOptions<MicrosoftAccountOptions>, MicrosoftAccountConfigureOptions>();
return services.AddOAuthAuthentication<MicrosoftAccountOptions, MicrosoftAccountHandler>(authenticationScheme, configureOptions);
}
}

View File

@ -191,14 +191,8 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
return context.Ticket;
}
protected override async Task HandleUnauthorizedAsync(ChallengeContext context)
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var properties = context.Properties;
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = CurrentUri;

View File

@ -2,16 +2,16 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
{
internal class OpenIdConnectConfigureOptions : ConfigureNamedOptions<OpenIdConnectOptions>
internal class OpenIdConnectConfigureOptions : ConfigureDefaultOptions<OpenIdConnectOptions>
{
// Bind to "OpenIdConnect" section by default
public OpenIdConnectConfigureOptions(IConfiguration config) :
base(OpenIdConnectDefaults.AuthenticationScheme,
options => config.GetSection(OpenIdConnectDefaults.AuthenticationScheme).Bind(options))
options => config.GetSection("Microsoft:AspNetCore:Authentication:Schemes:"+OpenIdConnectDefaults.AuthenticationScheme).Bind(options))
{ }
}
}

View File

@ -5,22 +5,14 @@ using System;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
namespace Microsoft.Extensions.DependencyInjection
{
public static class OpenIdConnectExtensions
{
/// <summary>
/// Adds OpenIdConnect authentication with options bound against the "OpenIdConnect" section
/// from the IConfiguration in the service container.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddOpenIdConnectAuthentication(this IServiceCollection services)
{
services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, OpenIdConnectConfigureOptions>();
return services.AddOpenIdConnectAuthentication(OpenIdConnectDefaults.AuthenticationScheme, _ => { });
}
=> services.AddOpenIdConnectAuthentication(OpenIdConnectDefaults.AuthenticationScheme, _ => { });
public static IServiceCollection AddOpenIdConnectAuthentication(this IServiceCollection services, Action<OpenIdConnectOptions> configureOptions)
=> services.AddOpenIdConnectAuthentication(OpenIdConnectDefaults.AuthenticationScheme, configureOptions);
@ -28,6 +20,7 @@ namespace Microsoft.Extensions.DependencyInjection
public static IServiceCollection AddOpenIdConnectAuthentication(this IServiceCollection services, string authenticationScheme, Action<OpenIdConnectOptions> configureOptions)
{
services.TryAddEnumerable(ServiceDescriptor.Singleton<IInitializeOptions<OpenIdConnectOptions>, OpenIdConnectInitializer>());
services.AddSingleton<ConfigureDefaultOptions<OpenIdConnectOptions>, OpenIdConnectConfigureOptions>();
return services.AddRemoteScheme<OpenIdConnectOptions, OpenIdConnectHandler>(authenticationScheme, authenticationScheme, configureOptions);
}
}

View File

@ -161,7 +161,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// Redirect user to the identity provider for sign out
/// </summary>
/// <returns>A task executing the sign out procedure</returns>
protected override async Task HandleSignOutAsync(SignOutContext signout)
protected override async Task HandleSignOutAsync(AuthenticationProperties properties)
{
Logger.EnteringOpenIdAuthenticationHandlerHandleSignOutAsync(GetType().FullName);
@ -180,7 +180,6 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
};
// Get the post redirect URI.
var properties = signout.Properties;
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = BuildRedirectUriIfRelative(Options.PostLogoutRedirectUri);
@ -292,19 +291,13 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
/// Responds to a 401 Challenge. Sends an OpenIdConnect message to the 'identity authority' to obtain an identity.
/// </summary>
/// <returns></returns>
protected override async Task HandleUnauthorizedAsync(ChallengeContext context)
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
Logger.EnteringOpenIdAuthenticationHandlerHandleUnauthorizedAsync(GetType().FullName);
// order for local RedirectUri
// 1. challenge.Properties.RedirectUri
// 2. CurrentUri if RedirectUri is not set)
var properties = context.Properties;
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = CurrentUri;

View File

@ -2,16 +2,16 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
namespace Microsoft.AspNetCore.Authentication.Twitter
{
internal class TwitterConfigureOptions : ConfigureNamedOptions<TwitterOptions>
internal class TwitterConfigureOptions : ConfigureDefaultOptions<TwitterOptions>
{
// Bind to "Twitter" section by default
public TwitterConfigureOptions(IConfiguration config) :
base(TwitterDefaults.AuthenticationScheme,
options => config.GetSection(TwitterDefaults.AuthenticationScheme).Bind(options))
options => config.GetSection("Microsoft:AspNetCore:Authentication:Schemes:"+TwitterDefaults.AuthenticationScheme).Bind(options))
{ }
}
}

View File

@ -5,22 +5,14 @@ using System;
using Microsoft.AspNetCore.Authentication.Twitter;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
namespace Microsoft.Extensions.DependencyInjection
{
public static class TwitterExtensions
{
/// <summary>
/// Adds Twitter authentication with options bound against the "Twitter" section
/// from the IConfiguration in the service container.
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddTwitterAuthentication(this IServiceCollection services)
{
services.AddSingleton<IConfigureOptions<TwitterOptions>, TwitterConfigureOptions>();
return services.AddTwitterAuthentication(TwitterDefaults.AuthenticationScheme, _ => { });
}
=> services.AddTwitterAuthentication(TwitterDefaults.AuthenticationScheme, _ => { });
public static IServiceCollection AddTwitterAuthentication(this IServiceCollection services, Action<TwitterOptions> configureOptions)
=> services.AddTwitterAuthentication(TwitterDefaults.AuthenticationScheme, configureOptions);
@ -28,6 +20,7 @@ namespace Microsoft.Extensions.DependencyInjection
public static IServiceCollection AddTwitterAuthentication(this IServiceCollection services, string authenticationScheme, Action<TwitterOptions> configureOptions)
{
services.TryAddEnumerable(ServiceDescriptor.Singleton<IInitializeOptions<TwitterOptions>, TwitterInitializer>());
services.AddSingleton<ConfigureDefaultOptions<TwitterOptions>, TwitterConfigureOptions>();
return services.AddRemoteScheme<TwitterOptions, TwitterHandler>(authenticationScheme, authenticationScheme, configureOptions);
}
}

View File

@ -140,15 +140,8 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
}
protected override async Task HandleUnauthorizedAsync(ChallengeContext context)
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var properties = context.Properties;
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = CurrentUri;

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
@ -178,44 +179,41 @@ namespace Microsoft.AspNetCore.Authentication
protected abstract Task<AuthenticateResult> HandleAuthenticateAsync();
public async Task SignInAsync(SignInContext context)
public async Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
{
if (context == null)
if (user == null)
{
throw new ArgumentNullException(nameof(context));
throw new ArgumentNullException(nameof(user));
}
await HandleSignInAsync(context);
properties = properties ?? new AuthenticationProperties();
await HandleSignInAsync(user, properties);
Logger.AuthenticationSchemeSignedIn(Scheme.Name);
}
protected virtual Task HandleSignInAsync(SignInContext context)
protected virtual Task HandleSignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
{
return TaskCache.CompletedTask;
}
public async Task SignOutAsync(SignOutContext context)
public async Task SignOutAsync(AuthenticationProperties properties)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
await HandleSignOutAsync(context);
properties = properties ?? new AuthenticationProperties();
await HandleSignOutAsync(properties);
Logger.AuthenticationSchemeSignedOut(Scheme.Name);
}
protected virtual Task HandleSignOutAsync(SignOutContext context)
protected virtual Task HandleSignOutAsync(AuthenticationProperties properties)
{
return TaskCache.CompletedTask;
}
/// <summary>
/// Override this method to deal with a challenge that is forbidden.
/// Override this method to handle Forbid.
/// </summary>
/// <param name="context"></param>
/// <param name="properties"></param>
/// <returns>A Task.</returns>
protected virtual Task HandleForbiddenAsync(ChallengeContext context)
protected virtual Task HandleForbiddenAsync(AuthenticationProperties properties)
{
Response.StatusCode = 403;
return TaskCache.CompletedTask;
@ -226,35 +224,26 @@ namespace Microsoft.AspNetCore.Authentication
/// deals an authentication interaction as part of it's request flow. (like adding a response header, or
/// changing the 401 result to 302 of a login page or external sign-in location.)
/// </summary>
/// <param name="context"></param>
/// <param name="properties"></param>
/// <returns>A Task.</returns>
protected virtual Task HandleUnauthorizedAsync(ChallengeContext context)
protected virtual Task HandleChallengeAsync(AuthenticationProperties properties)
{
Response.StatusCode = 401;
return TaskCache.CompletedTask;
}
public async Task ChallengeAsync(ChallengeContext context)
public async Task ChallengeAsync(AuthenticationProperties properties)
{
switch (context.Behavior)
{
case ChallengeBehavior.Automatic:
// If there is a principal already, invoke the forbidden code path
var result = await HandleAuthenticateOnceSafeAsync();
if (result?.Principal != null)
{
goto case ChallengeBehavior.Forbidden;
}
goto case ChallengeBehavior.Unauthorized;
case ChallengeBehavior.Unauthorized:
await HandleUnauthorizedAsync(context);
Logger.AuthenticationSchemeChallenged(Scheme.Name);
break;
case ChallengeBehavior.Forbidden:
await HandleForbiddenAsync(context);
Logger.AuthenticationSchemeForbidden(Scheme.Name);
break;
}
properties = properties ?? new AuthenticationProperties();
await HandleChallengeAsync(properties);
Logger.AuthenticationSchemeChallenged(Scheme.Name);
}
public async Task ForbidAsync(AuthenticationProperties properties)
{
properties = properties ?? new AuthenticationProperties();
await HandleForbiddenAsync(properties);
Logger.AuthenticationSchemeForbidden(Scheme.Name);
}
}
}

View File

@ -0,0 +1,41 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authentication
{
/// <summary>
/// Base context for authentication.
/// </summary>
public abstract class BaseAuthenticationContext : BaseContext
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="authenticationScheme">The name of the scheme.</param>
/// <param name="properties">The properties.</param>
protected BaseAuthenticationContext(HttpContext context, string authenticationScheme, AuthenticationProperties properties) : base(context)
{
if (string.IsNullOrEmpty(authenticationScheme))
{
throw new ArgumentException(nameof(authenticationScheme));
}
AuthenticationScheme = authenticationScheme;
Properties = properties ?? new AuthenticationProperties();
}
/// <summary>
/// The name of the scheme.
/// </summary>
public string AuthenticationScheme { get; }
/// <summary>
/// Contains the extra meta-data arriving with the authentication. May be altered.
/// </summary>
public AuthenticationProperties Properties { get; protected set; }
}
}

View File

@ -0,0 +1,49 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authentication
{
/// <summary>
/// Base class used by other context classes.
/// </summary>
public abstract class BaseContext
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="context">The request context.</param>
protected BaseContext(HttpContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
HttpContext = context;
}
/// <summary>
/// The context.
/// </summary>
public HttpContext HttpContext { get; }
/// <summary>
/// The request.
/// </summary>
public HttpRequest Request
{
get { return HttpContext.Request; }
}
/// <summary>
/// The response.
/// </summary>
public HttpResponse Response
{
get { return HttpContext.Response; }
}
}
}

View File

@ -2,6 +2,7 @@
// 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.Security.Cryptography;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
@ -173,18 +174,17 @@ namespace Microsoft.AspNetCore.Authentication
return AuthenticateResult.Fail("Remote authentication does not directly support AuthenticateAsync");
}
protected override Task HandleSignOutAsync(SignOutContext context)
protected override Task HandleSignOutAsync(AuthenticationProperties properties)
{
throw new NotSupportedException();
}
protected override Task HandleSignInAsync(SignInContext context)
protected override Task HandleSignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
{
throw new NotSupportedException();
}
// REVIEW: This behaviour needs a test (forwarding of forbidden to sign in scheme)
protected override Task HandleForbiddenAsync(ChallengeContext context)
protected override Task HandleForbiddenAsync(AuthenticationProperties properties)
{
return Context.ForbidAsync(SignInScheme);
}

View File

@ -0,0 +1,36 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Authorization.Policy
{
/// <summary>
/// Base class for authorization handlers that need to be called for a specific requirement type.
/// </summary>
public interface IPolicyEvaluator
{
/// <summary>
/// Does authentication for <see cref="AuthorizationPolicy.AuthenticationSchemes"/> and sets the resulting
/// <see cref="ClaimsPrincipal"/> to <see cref="HttpContext.User"/>. If no schemes are set, this is a no-op.
/// </summary>
/// <param name="policy">The <see cref="AuthorizationPolicy"/>.</param>
/// <param name="context">The <see cref="HttpContext"/>.</param>
/// <returns><see cref="AuthenticateResult.Success"/> unless all schemes specified by <see cref="AuthorizationPolicy.AuthenticationSchemes"/> fail to authenticate. </returns>
Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy policy, HttpContext context);
/// <summary>
/// Attempts authorization for a policy using <see cref="IAuthorizationService"/>.
/// </summary>
/// <param name="policy">The <see cref="AuthorizationPolicy"/>.</param>
/// <param name="authenticationResult">The result of a call to <see cref="AuthenticateAsync(AuthorizationPolicy, HttpContext)"/>.</param>
/// <param name="context">The <see cref="HttpContext"/>.</param>
/// <returns>Returns <see cref="PolicyAuthorizationResult.Success"/> if authorization succeeds.
/// Otherwise returns <see cref="PolicyAuthorizationResult.Forbid"/> if <see cref="AuthenticateResult.Succeeded"/>, otherwise
/// returns <see cref="PolicyAuthorizationResult.Challenge"/></returns>
Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context);
}
}

View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\common.props" />
<PropertyGroup>
<Description>ASP.NET Core authorization policy helper classes.</Description>
<TargetFramework>netstandard2.0</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;authorization</PackageTags>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Authorization\Microsoft.AspNetCore.Authorization.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.Abstractions" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.SecurityHelper.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PackageReference Include="System.Security.Claims" Version="$(CoreFxVersion)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,35 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Authorization.Policy
{
public class PolicyAuthorizationResult
{
private PolicyAuthorizationResult() { }
/// <summary>
/// If true, means the callee should challenge and try again.
/// </summary>
public bool Challenged { get; private set; }
/// <summary>
/// Authorization was forbidden.
/// </summary>
public bool Forbidden { get; private set; }
/// <summary>
/// Authorization was successful.
/// </summary>
public bool Succeeded { get; private set; }
public static PolicyAuthorizationResult Challenge()
=> new PolicyAuthorizationResult { Challenged = true };
public static PolicyAuthorizationResult Forbid()
=> new PolicyAuthorizationResult { Forbidden = true };
public static PolicyAuthorizationResult Success()
=> new PolicyAuthorizationResult { Succeeded = true };
}
}

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 System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Authorization.Policy
{
public class PolicyEvaluator : IPolicyEvaluator
{
private readonly IAuthorizationService _authorization;
/// <summary>
/// Constructor
/// </summary>
/// <param name="authorization">The authorization service.</param>
public PolicyEvaluator(IAuthorizationService authorization)
{
_authorization = authorization;
}
/// <summary>
/// Does authentication for <see cref="AuthorizationPolicy.AuthenticationSchemes"/> and sets the resulting
/// <see cref="ClaimsPrincipal"/> to <see cref="HttpContext.User"/>. If no schemes are set, this is a no-op.
/// </summary>
/// <param name="policy">The <see cref="AuthorizationPolicy"/>.</param>
/// <param name="context">The <see cref="HttpContext"/>.</param>
/// <returns><see cref="AuthenticateResult.Success"/> unless all schemes specified by <see cref="AuthorizationPolicy.AuthenticationSchemes"/> failed to authenticate. </returns>
public virtual async Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy policy, HttpContext context)
{
if (policy.AuthenticationSchemes != null && policy.AuthenticationSchemes.Count > 0)
{
ClaimsPrincipal newPrincipal = null;
foreach (var scheme in policy.AuthenticationSchemes)
{
var result = await context.AuthenticateAsync(scheme);
if (result != null && result.Succeeded)
{
newPrincipal = SecurityHelper.MergeUserPrincipal(newPrincipal, result.Principal);
}
}
if (newPrincipal != null)
{
context.User = newPrincipal;
return AuthenticateResult.Success(new AuthenticationTicket(newPrincipal, string.Join(";", policy.AuthenticationSchemes)));
}
else
{
context.User = new ClaimsPrincipal(new ClaimsIdentity());
return AuthenticateResult.None();
}
}
return (context.User?.Identity?.IsAuthenticated ?? false)
? AuthenticateResult.Success(new AuthenticationTicket(context.User, "context.User"))
: AuthenticateResult.None();
}
/// <summary>
/// Attempts authorization for a policy using <see cref="IAuthorizationService"/>.
/// </summary>
/// <param name="policy">The <see cref="AuthorizationPolicy"/>.</param>
/// <param name="authenticationResult">The result of a call to <see cref="AuthenticateAsync(AuthorizationPolicy, HttpContext)"/>.</param>
/// <param name="context">The <see cref="HttpContext"/>.</param>
/// <returns>Returns <see cref="PolicyAuthorizationResult.Success"/> if authorization succeeds.
/// Otherwise returns <see cref="PolicyAuthorizationResult.Forbid"/> if <see cref="AuthenticateResult.Succeeded"/>, otherwise
/// returns <see cref="PolicyAuthorizationResult.Challenge"/></returns>
public virtual async Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context)
{
if (policy == null)
{
throw new ArgumentNullException(nameof(policy));
}
var result = await _authorization.AuthorizeAsync(context.User, context, policy);
if (result.Succeeded)
{
return PolicyAuthorizationResult.Success();
}
// If authentication was successful, return forbidden, otherwise challenge
return (authenticationResult.Succeeded)
? PolicyAuthorizationResult.Forbid()
: PolicyAuthorizationResult.Challenge();
}
}
}

View File

@ -0,0 +1,31 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Extension methods for setting up authorization services in an <see cref="IServiceCollection" />.
/// </summary>
public static class PolicyServiceCollectionExtensions
{
/// <summary>
/// Adds authorization policy services to the specified <see cref="IServiceCollection" />.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
public static IServiceCollection AddAuthorizationPolicyEvaluator(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
services.TryAdd(ServiceDescriptor.Transient<IPolicyEvaluator, PolicyEvaluator>());
return services;
}
}
}

View File

@ -0,0 +1,46 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Security.Claims;
namespace Microsoft.AspNetCore.Authorization
{
/// <summary>
/// Encapsulates a failure result of <see cref="IAuthorizationService.AuthorizeAsync(ClaimsPrincipal, object, IEnumerable{IAuthorizationRequirement})"/>.
/// </summary>
public class AuthorizationFailure
{
private AuthorizationFailure() { }
/// <summary>
/// Failure was due to <see cref="AuthorizationHandlerContext.Fail"/> being called.
/// </summary>
public bool FailCalled { get; private set; }
/// <summary>
/// Failure was due to these requirements not being met via <see cref="AuthorizationHandlerContext.Succeed(IAuthorizationRequirement)"/>.
/// </summary>
public IEnumerable<IAuthorizationRequirement> FailedRequirements { get; private set; }
/// <summary>
/// Return a failure due to <see cref="AuthorizationHandlerContext.Fail"/> being called.
/// </summary>
/// <returns>The failure.</returns>
public static AuthorizationFailure ExplicitFail()
=> new AuthorizationFailure
{
FailCalled = true,
FailedRequirements = new IAuthorizationRequirement[0]
};
/// <summary>
/// Return a failure due to some requirements not being met via <see cref="AuthorizationHandlerContext.Succeed(IAuthorizationRequirement)"/>.
/// </summary>
/// <param name="failed">The requirements that were not met.</param>
/// <returns>The failure.</returns>
public static AuthorizationFailure Failed(IEnumerable<IAuthorizationRequirement> failed)
=> new AuthorizationFailure { FailedRequirements = failed };
}
}

View File

@ -143,7 +143,7 @@ namespace Microsoft.AspNetCore.Authorization
policyBuilder.RequireRole(trimmedRolesSplit);
useDefaultPolicy = false;
}
var authTypesSplit = authorizeDatum.ActiveAuthenticationSchemes?.Split(',');
var authTypesSplit = authorizeDatum.AuthenticationSchemes?.Split(',');
if (authTypesSplit != null && authTypesSplit.Any())
{
foreach (var authType in authTypesSplit)

View File

@ -0,0 +1,37 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Security.Claims;
namespace Microsoft.AspNetCore.Authorization
{
/// <summary>
/// Encapsulates the result of <see cref="IAuthorizationService.AuthorizeAsync(ClaimsPrincipal, object, IEnumerable{IAuthorizationRequirement})"/>.
/// </summary>
public class AuthorizationResult
{
private AuthorizationResult() { }
/// <summary>
/// True if authorization was successful.
/// </summary>
public bool Succeeded { get; private set; }
/// <summary>
/// Contains information about why authorization failed.
/// </summary>
public AuthorizationFailure Failure { get; private set; }
/// <summary>
/// Returns a successful result.
/// </summary>
/// <returns>A successful result.</returns>
public static AuthorizationResult Success() => new AuthorizationResult { Succeeded = true };
public static AuthorizationResult Failed(AuthorizationFailure failure) => new AuthorizationResult { Failure = failure };
public static AuthorizationResult Failed() => new AuthorizationResult { Failure = AuthorizationFailure.ExplicitFail() };
}
}

View File

@ -27,6 +27,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationService, DefaultAuthorizationService>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationPolicyProvider, DefaultAuthorizationPolicyProvider>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationHandlerProvider, DefaultAuthorizationHandlerProvider>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationEvaluator, DefaultAuthorizationEvaluator>());
services.TryAdd(ServiceDescriptor.Transient<IAuthorizationHandlerContextFactory, DefaultAuthorizationHandlerContextFactory>());
services.TryAddEnumerable(ServiceDescriptor.Transient<IAuthorizationHandler, PassThroughAuthorizationHandler>());

View File

@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Authorization
/// A flag indicating whether requirement evaluation has succeeded or failed.
/// This value is <value>true</value> when the user fulfills the policy, otherwise <value>false</value>.
/// </returns>
public static Task<bool> AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, object resource, IAuthorizationRequirement requirement)
public static Task<AuthorizationResult> AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, object resource, IAuthorizationRequirement requirement)
{
if (service == null)
{
@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Authorization
/// A flag indicating whether policy evaluation has succeeded or failed.
/// This value is <value>true</value> when the user fulfills the policy, otherwise <value>false</value>.
/// </returns>
public static Task<bool> AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, object resource, AuthorizationPolicy policy)
public static Task<AuthorizationResult> AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, object resource, AuthorizationPolicy policy)
{
if (service == null)
{
@ -75,7 +75,7 @@ namespace Microsoft.AspNetCore.Authorization
/// A flag indicating whether policy evaluation has succeeded or failed.
/// This value is <value>true</value> when the user fulfills the policy, otherwise <value>false</value>.
/// </returns>
public static Task<bool> AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, AuthorizationPolicy policy)
public static Task<AuthorizationResult> AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, AuthorizationPolicy policy)
{
if (service == null)
{
@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Authorization
/// A flag indicating whether policy evaluation has succeeded or failed.
/// This value is <value>true</value> when the user fulfills the policy, otherwise <value>false</value>.
/// </returns>
public static Task<bool> AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, string policyName)
public static Task<AuthorizationResult> AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, string policyName)
{
if (service == null)
{

View File

@ -25,13 +25,29 @@ namespace Microsoft.AspNetCore.Authorization
Policy = policy;
}
/// <inheritdoc />
/// <summary>
/// Gets or sets the policy name that determines access to the resource.
/// </summary>
public string Policy { get; set; }
/// <inheritdoc />
/// <summary>
/// Gets or sets a comma delimited list of roles that are allowed to access the resource.
/// </summary>
public string Roles { get; set; }
/// <inheritdoc />
public string ActiveAuthenticationSchemes { get; set; }
/// <summary>
/// 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

@ -9,23 +9,15 @@ namespace Microsoft.AspNetCore.Authorization
public class DefaultAuthorizationEvaluator : IAuthorizationEvaluator
{
/// <summary>
/// Returns true, if authorization has failed.
/// Determines whether the authorization result was successful or not.
/// </summary>
/// <param name="context">The authorization information.</param>
/// <returns>True if authorization has failed.</returns>
public virtual bool HasFailed(AuthorizationHandlerContext context)
{
return context.HasFailed;
}
/// <summary>
/// Returns true, if authorization has succeeded.
/// </summary>
/// <param name="context">The authorization information.</param>
/// <returns>True if authorization has succeeded.</returns>
public virtual bool HasSucceeded(AuthorizationHandlerContext context)
{
return context.HasSucceeded;
}
/// <returns>The <see cref="AuthorizationResult"/>.</returns>
public AuthorizationResult Evaluate(AuthorizationHandlerContext context)
=> context.HasSucceeded
? AuthorizationResult.Success()
: AuthorizationResult.Failed(context.HasFailed
? AuthorizationFailure.ExplicitFail()
: AuthorizationFailure.Failed(context.PendingRequirements));
}
}

View File

@ -0,0 +1,35 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Authorization
{
/// <summary>
/// The default implementation of a handler provider,
/// which provides the <see cref="IAuthorizationHandler"/>s for an authorization request.
/// </summary>
public class DefaultAuthorizationHandlerProvider : IAuthorizationHandlerProvider
{
private readonly IEnumerable<IAuthorizationHandler> _handlers;
/// <summary>
/// Creates a new instance of <see cref="DefaultAuthorizationHandlerProvider"/>.
/// </summary>
/// <param name="handlers">The <see cref="IAuthorizationHandler"/>s.</param>
public DefaultAuthorizationHandlerProvider(IEnumerable<IAuthorizationHandler> handlers)
{
if (handlers == null)
{
throw new ArgumentNullException(nameof(handlers));
}
_handlers = handlers;
}
public Task<IEnumerable<IAuthorizationHandler>> GetHandlersAsync(AuthorizationHandlerContext context)
=> Task.FromResult(_handlers);
}
}

View File

@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
@ -19,19 +18,11 @@ namespace Microsoft.AspNetCore.Authorization
{
private readonly AuthorizationOptions _options;
private readonly IAuthorizationHandlerContextFactory _contextFactory;
private readonly IAuthorizationHandlerProvider _handlers;
private readonly IAuthorizationEvaluator _evaluator;
private readonly IAuthorizationPolicyProvider _policyProvider;
private readonly IList<IAuthorizationHandler> _handlers;
private readonly ILogger _logger;
/// <summary>
/// Creates a new instance of <see cref="DefaultAuthorizationService"/>.
/// </summary>
/// <param name="policyProvider">The <see cref="IAuthorizationPolicyProvider"/> used to provide policies.</param>
/// <param name="handlers">The handlers used to fulfill <see cref="IAuthorizationRequirement"/>s.</param>
/// <param name="logger">The logger used to log messages, warnings and errors.</param>
public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IEnumerable<IAuthorizationHandler> handlers, ILogger<DefaultAuthorizationService> logger) : this(policyProvider, handlers, logger, new DefaultAuthorizationHandlerContextFactory(), new DefaultAuthorizationEvaluator(), Options.Create(new AuthorizationOptions())) { }
/// <summary>
/// Creates a new instance of <see cref="DefaultAuthorizationService"/>.
/// </summary>
@ -41,7 +32,7 @@ namespace Microsoft.AspNetCore.Authorization
/// <param name="contextFactory">The <see cref="IAuthorizationHandlerContextFactory"/> used to create the context to handle the authorization.</param>
/// <param name="evaluator">The <see cref="IAuthorizationEvaluator"/> used to determine if authorzation was successful.</param>
/// <param name="options">The <see cref="AuthorizationOptions"/> used.</param>
public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IEnumerable<IAuthorizationHandler> handlers, ILogger<DefaultAuthorizationService> logger, IAuthorizationHandlerContextFactory contextFactory, IAuthorizationEvaluator evaluator, IOptions<AuthorizationOptions> options)
public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IAuthorizationHandlerProvider handlers, ILogger<DefaultAuthorizationService> logger, IAuthorizationHandlerContextFactory contextFactory, IAuthorizationEvaluator evaluator, IOptions<AuthorizationOptions> options)
{
if (options == null)
{
@ -69,7 +60,7 @@ namespace Microsoft.AspNetCore.Authorization
}
_options = options.Value;
_handlers = handlers.ToArray();
_handlers = handlers;
_policyProvider = policyProvider;
_logger = logger;
_evaluator = evaluator;
@ -86,7 +77,7 @@ namespace Microsoft.AspNetCore.Authorization
/// A flag indicating whether authorization has succeded.
/// This value is <value>true</value> when the user fulfills the policy otherwise <value>false</value>.
/// </returns>
public async Task<bool> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements)
public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements)
{
if (requirements == null)
{
@ -94,7 +85,8 @@ namespace Microsoft.AspNetCore.Authorization
}
var authContext = _contextFactory.CreateContext(requirements, user, resource);
foreach (var handler in _handlers)
var handlers = await _handlers.GetHandlersAsync(authContext);
foreach (var handler in handlers)
{
await handler.HandleAsync(authContext);
if (!_options.InvokeHandlersAfterFailure && authContext.HasFailed)
@ -103,16 +95,16 @@ namespace Microsoft.AspNetCore.Authorization
}
}
if (_evaluator.HasSucceeded(authContext))
var result = _evaluator.Evaluate(authContext);
if (result.Succeeded)
{
_logger.UserAuthorizationSucceeded(GetUserNameForLogging(user));
return true;
}
else
{
_logger.UserAuthorizationFailed(GetUserNameForLogging(user));
return false;
}
return result;
}
private string GetUserNameForLogging(ClaimsPrincipal user)
@ -147,7 +139,7 @@ namespace Microsoft.AspNetCore.Authorization
/// A flag indicating whether authorization has succeded.
/// This value is <value>true</value> when the user fulfills the policy otherwise <value>false</value>.
/// </returns>
public async Task<bool> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName)
public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName)
{
if (policyName == null)
{

View File

@ -9,17 +9,10 @@ namespace Microsoft.AspNetCore.Authorization
public interface IAuthorizationEvaluator
{
/// <summary>
/// Returns true, if authorization has failed.
/// Determines whether the authorization result was successful or not.
/// </summary>
/// <param name="context">The authorization information.</param>
/// <returns>True if authorization has failed.</returns>
bool HasFailed(AuthorizationHandlerContext context);
/// <summary>
/// Returns true, if authorization has succeeded.
/// </summary>
/// <param name="context">The authorization information.</param>
/// <returns>True if authorization has succeeded.</returns>
bool HasSucceeded(AuthorizationHandlerContext context);
/// <returns>The <see cref="AuthorizationResult"/>.</returns>
AuthorizationResult Evaluate(AuthorizationHandlerContext context);
}
}

View File

@ -0,0 +1,21 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Authorization
{
/// <summary>
/// A type which can provide the <see cref="IAuthorizationHandler"/>s for an authorization request.
/// </summary>
public interface IAuthorizationHandlerProvider
{
/// <summary>
/// Return the handlers that will be called for the authorization request.
/// </summary>
/// <param name="context">The <see cref="AuthorizationHandlerContext"/>.</param>
/// <returns>The list of handlers.</returns>
Task<IEnumerable<IAuthorizationHandler>> GetHandlersAsync(AuthorizationHandlerContext context);
}
}

View File

@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Authorization
/// Resource is an optional parameter and may be null. Please ensure that you check it is not
/// null before acting upon it.
/// </remarks>
Task<bool> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements);
/// <summary>
/// Checks if a user meets a specific authorization policy
@ -49,6 +49,6 @@ namespace Microsoft.AspNetCore.Authorization
/// Resource is an optional parameter and may be null. Please ensure that you check it is not
/// null before acting upon it.
/// </remarks>
Task<bool> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName);
}
}

View File

@ -21,6 +21,6 @@ namespace Microsoft.AspNetCore.Authorization
/// <summary>
/// Gets or sets a comma delimited list of schemes from which user information is constructed.
/// </summary>
string ActiveAuthenticationSchemes { get; set; }
string AuthenticationSchemes { get; set; }
}
}

View File

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Net;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
@ -77,7 +77,12 @@ namespace Microsoft.AspNetCore.Authentication
throw new NotImplementedException();
}
public Task ChallengeAsync(ChallengeContext context)
public Task ChallengeAsync(AuthenticationProperties properties)
{
throw new NotImplementedException();
}
public Task ForbidAsync(AuthenticationProperties properties)
{
throw new NotImplementedException();
}
@ -94,12 +99,12 @@ namespace Microsoft.AspNetCore.Authentication
return Task.FromResult(0);
}
public Task SignInAsync(SignInContext context)
public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
{
throw new NotImplementedException();
}
public Task SignOutAsync(SignOutContext context)
public Task SignOutAsync(AuthenticationProperties properties)
{
throw new NotImplementedException();
}
@ -114,7 +119,12 @@ namespace Microsoft.AspNetCore.Authentication
throw new NotImplementedException();
}
public Task ChallengeAsync(ChallengeContext context)
public Task ChallengeAsync(AuthenticationProperties properties)
{
throw new NotImplementedException();
}
public Task ForbidAsync(AuthenticationProperties properties)
{
throw new NotImplementedException();
}
@ -130,12 +140,12 @@ namespace Microsoft.AspNetCore.Authentication
return Task.FromResult(0);
}
public Task SignInAsync(SignInContext context)
public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
{
throw new NotImplementedException();
}
public Task SignOutAsync(SignOutContext context)
public Task SignOutAsync(AuthenticationProperties properties)
{
throw new NotImplementedException();
}
@ -150,7 +160,12 @@ namespace Microsoft.AspNetCore.Authentication
throw new NotImplementedException();
}
public Task ChallengeAsync(ChallengeContext context)
public Task ChallengeAsync(AuthenticationProperties properties)
{
throw new NotImplementedException();
}
public Task ForbidAsync(AuthenticationProperties properties)
{
throw new NotImplementedException();
}
@ -166,12 +181,12 @@ namespace Microsoft.AspNetCore.Authentication
return Task.FromResult(0);
}
public Task SignInAsync(SignInContext context)
public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
{
throw new NotImplementedException();
}
public Task SignOutAsync(SignOutContext context)
public Task SignOutAsync(AuthenticationProperties properties)
{
throw new NotImplementedException();
}

View File

@ -702,22 +702,6 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
Assert.True(transaction1.SetCookie.Contains("path=/base"));
}
[Fact]
public async Task CookieTurnsChallengeIntoForbidWithCookie()
{
var server = CreateServer(o => { }, SignInAsAlice);
var transaction1 = await SendAsync(server, "http://example.com/testpath");
var url = "http://example.com/challenge";
var transaction2 = await SendAsync(server, url, transaction1.CookieNameValue);
Assert.Equal(HttpStatusCode.Redirect, transaction2.Response.StatusCode);
var location = transaction2.Response.Headers.Location;
Assert.Equal("/Account/AccessDenied", location.LocalPath);
Assert.Equal("?ReturnUrl=%2Fchallenge", location.Query);
}
[Fact]
public async Task CookieChallengeRedirectsToLoginWithoutCookie()
{
@ -744,25 +728,6 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
Assert.Equal("/Account/AccessDenied", location.LocalPath);
}
[Fact]
public async Task CookieTurns401ToAccessDeniedWhenSetWithCookie()
{
var server = CreateServer(o =>
{
o.AccessDeniedPath = new PathString("/accessdenied");
},
SignInAsAlice);
var transaction1 = await SendAsync(server, "http://example.com/testpath");
var transaction2 = await SendAsync(server, "http://example.com/challenge", transaction1.CookieNameValue);
Assert.Equal(HttpStatusCode.Redirect, transaction2.Response.StatusCode);
var location = transaction2.Response.Headers.Location;
Assert.Equal("/accessdenied", location.LocalPath);
}
[Fact]
public async Task CookieChallengeRedirectsWithLoginPath()
{
@ -799,7 +764,8 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
public async Task MapWillAffectChallengeOnlyWithUseAuth(bool useAuth)
{
var builder = new WebHostBuilder()
.Configure(app => {
.Configure(app =>
{
if (useAuth)
{
app.UseAuthentication();
@ -1296,7 +1262,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
}
else if (req.Path == new PathString("/unauthorized"))
{
await context.ChallengeAsync(CookieAuthenticationDefaults.AuthenticationScheme, new AuthenticationProperties(), ChallengeBehavior.Unauthorized);
await context.ChallengeAsync(CookieAuthenticationDefaults.AuthenticationScheme, new AuthenticationProperties());
}
else if (req.Path == new PathString("/protected/CustomRedirect"))
{

View File

@ -20,6 +20,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
using Newtonsoft.Json;
using Xunit;
@ -44,23 +45,26 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
{
var dic = new Dictionary<string, string>
{
{"Facebook:AppId", "<id>"},
{"Facebook:AppSecret", "<secret>"},
{"Facebook:AuthorizationEndpoint", "<authEndpoint>"},
{"Facebook:BackchannelTimeout", "0.0:0:30"},
{"Microsoft:AspNetCore:Authentication:Schemes:Facebook:AppId", "<id>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Facebook:AppSecret", "<secret>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Facebook:AuthorizationEndpoint", "<authEndpoint>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Facebook:BackchannelTimeout", "0.0:0:30"},
//{"Facebook:CallbackPath", "/callbackpath"}, // PathString doesn't convert
{"Facebook:ClaimsIssuer", "<issuer>"},
{"Facebook:RemoteAuthenticationTimeout", "0.0:0:30"},
{"Facebook:SaveTokens", "true"},
{"Facebook:SendAppSecretProof", "true"},
{"Facebook:SignInScheme", "<signIn>"},
{"Facebook:TokenEndpoint", "<tokenEndpoint>"},
{"Facebook:UserInformationEndpoint", "<userEndpoint>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Facebook:ClaimsIssuer", "<issuer>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Facebook:RemoteAuthenticationTimeout", "0.0:0:30"},
{"Microsoft:AspNetCore:Authentication:Schemes:Facebook:SaveTokens", "true"},
{"Microsoft:AspNetCore:Authentication:Schemes:Facebook:SendAppSecretProof", "true"},
{"Microsoft:AspNetCore:Authentication:Schemes:Facebook:SignInScheme", "<signIn>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Facebook:TokenEndpoint", "<tokenEndpoint>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Facebook:UserInformationEndpoint", "<userEndpoint>"},
};
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddInMemoryCollection(dic);
var config = configurationBuilder.Build();
var services = new ServiceCollection().AddFacebookAuthentication().AddSingleton<IConfiguration>(config);
var services = new ServiceCollection()
.AddSingleton<IConfigureOptions<FacebookOptions>, ConfigureDefaults<FacebookOptions>>()
.AddFacebookAuthentication()
.AddSingleton<IConfiguration>(config);
var sp = services.BuildServiceProvider();
var options = sp.GetRequiredService<IOptionsSnapshot<FacebookOptions>>().Get(FacebookDefaults.AuthenticationScheme);

View File

@ -19,6 +19,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
using Newtonsoft.Json;
using Xunit;
@ -43,23 +44,26 @@ namespace Microsoft.AspNetCore.Authentication.Google
{
var dic = new Dictionary<string, string>
{
{"Google:ClientId", "<id>"},
{"Google:ClientSecret", "<secret>"},
{"Google:AuthorizationEndpoint", "<authEndpoint>"},
{"Google:BackchannelTimeout", "0.0:0:30"},
{"Microsoft:AspNetCore:Authentication:Schemes:Google:ClientId", "<id>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Google:ClientSecret", "<secret>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Google:AuthorizationEndpoint", "<authEndpoint>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Google:BackchannelTimeout", "0.0:0:30"},
//{"Google:CallbackPath", "/callbackpath"}, // PathString doesn't convert
{"Google:ClaimsIssuer", "<issuer>"},
{"Google:RemoteAuthenticationTimeout", "0.0:0:30"},
{"Google:SaveTokens", "true"},
{"Google:SendAppSecretProof", "true"},
{"Google:SignInScheme", "<signIn>"},
{"Google:TokenEndpoint", "<tokenEndpoint>"},
{"Google:UserInformationEndpoint", "<userEndpoint>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Google:ClaimsIssuer", "<issuer>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Google:RemoteAuthenticationTimeout", "0.0:0:30"},
{"Microsoft:AspNetCore:Authentication:Schemes:Google:SaveTokens", "true"},
{"Microsoft:AspNetCore:Authentication:Schemes:Google:SendAppSecretProof", "true"},
{"Microsoft:AspNetCore:Authentication:Schemes:Google:SignInScheme", "<signIn>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Google:TokenEndpoint", "<tokenEndpoint>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Google:UserInformationEndpoint", "<userEndpoint>"},
};
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddInMemoryCollection(dic);
var config = configurationBuilder.Build();
var services = new ServiceCollection().AddGoogleAuthentication().AddSingleton<IConfiguration>(config);
var services = new ServiceCollection()
.AddSingleton<IConfigureOptions<GoogleOptions>, ConfigureDefaults<GoogleOptions>>()
.AddGoogleAuthentication()
.AddSingleton<IConfiguration>(config);
var sp = services.BuildServiceProvider();
var options = sp.GetRequiredService<IOptionsSnapshot<GoogleOptions>>().Get(GoogleDefaults.AuthenticationScheme);
@ -883,42 +887,6 @@ namespace Microsoft.AspNetCore.Authentication.Google
Assert.Equal("yup", transaction.FindClaimValue("xform"));
}
[Fact]
public async Task ChallengeGoogleWhenAlreadySignedInReturnsForbidden()
{
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider(NullLoggerFactory.Instance).CreateProtector("GoogleTest"));
var server = CreateServer(o =>
{
o.ClientId = "Test Id";
o.ClientSecret = "Test Secret";
o.StateDataFormat = stateFormat;
o.SaveTokens = true;
o.BackchannelHttpHandler = CreateBackchannel();
});
// Skip the challenge step, go directly to the callback path
var properties = new AuthenticationProperties();
var correlationKey = ".xsrf";
var correlationValue = "TestCorrelationId";
properties.Items.Add(correlationKey, correlationValue);
properties.RedirectUri = "/me";
var state = stateFormat.Protect(properties);
var transaction = await server.SendAsync(
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.Encode(state),
$".AspNetCore.Correlation.Google.{correlationValue}=N");
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
Assert.Equal("/me", transaction.Response.Headers.GetValues("Location").First());
Assert.Equal(2, transaction.SetCookie.Count);
Assert.Contains($".AspNetCore.Correlation.Google.{correlationValue}", transaction.SetCookie[0]); // Delete
Assert.Contains(".AspNetCore." + TestExtensions.CookieAuthenticationScheme, transaction.SetCookie[1]);
var authCookie = transaction.AuthenticationCookieValue;
transaction = await server.SendAsync("https://example.com/challenge", authCookie);
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
Assert.StartsWith("https://example.com/Account/AccessDenied?", transaction.Response.Headers.Location.OriginalString);
}
[Fact]
public async Task AuthenticateFacebookWhenAlreadySignedWithGoogleReturnsNull()
{

View File

@ -19,6 +19,7 @@ using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
using Microsoft.IdentityModel.Tokens;
using Xunit;
@ -43,21 +44,24 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
{
var dic = new Dictionary<string, string>
{
{"Bearer:Audience", "<audience>"},
{"Bearer:Authority", "<authority>"},
{"Bearer:BackchannelTimeout", "0.0:0:30"},
{"Bearer:Challenge", "<challenge>"},
{"Bearer:ClaimsIssuer", "<issuer>"},
{"Bearer:IncludeErrorDetails", "true"},
{"Bearer:MetadataAddress", "<metadata>"},
{"Bearer:RefreshOnIssuerKeyNotFound", "true"},
{"Bearer:RequireHttpsMetadata", "false"},
{"Bearer:SaveToken", "true"},
{"Microsoft:AspNetCore:Authentication:Schemes:Bearer:Audience", "<audience>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Bearer:Authority", "<authority>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Bearer:BackchannelTimeout", "0.0:0:30"},
{"Microsoft:AspNetCore:Authentication:Schemes:Bearer:Challenge", "<challenge>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Bearer:ClaimsIssuer", "<issuer>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Bearer:IncludeErrorDetails", "true"},
{"Microsoft:AspNetCore:Authentication:Schemes:Bearer:MetadataAddress", "<metadata>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Bearer:RefreshOnIssuerKeyNotFound", "true"},
{"Microsoft:AspNetCore:Authentication:Schemes:Bearer:RequireHttpsMetadata", "false"},
{"Microsoft:AspNetCore:Authentication:Schemes:Bearer:SaveToken", "true"},
};
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddInMemoryCollection(dic);
var config = configurationBuilder.Build();
var services = new ServiceCollection().AddJwtBearerAuthentication().AddSingleton<IConfiguration>(config);
var services = new ServiceCollection()
.AddSingleton<IConfigureOptions<JwtBearerOptions>, ConfigureDefaults<JwtBearerOptions>>()
.AddJwtBearerAuthentication()
.AddSingleton<IConfiguration>(config);
var sp = services.BuildServiceProvider();
var options = sp.GetRequiredService<IOptionsSnapshot<JwtBearerOptions>>().Get(JwtBearerDefaults.AuthenticationScheme);
@ -74,21 +78,26 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
}
[Fact]
public void AddWithDelegateIgnoresConfig()
public void AddWithDelegateOverridesConfig()
{
var dic = new Dictionary<string, string>
{
{"Bearer:Audience", "<audience>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Bearer:Audience", "<audience>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Bearer:Authority", "<authority>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Bearer:RequireHttpsMetadata", "false"}
};
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddInMemoryCollection(dic);
var config = configurationBuilder.Build();
var services = new ServiceCollection().AddJwtBearerAuthentication(o => o.IncludeErrorDetails = true).AddSingleton<IConfiguration>(config);
var services = new ServiceCollection()
.AddSingleton<IConfigureOptions<JwtBearerOptions>, ConfigureDefaults<JwtBearerOptions>>()
.AddJwtBearerAuthentication(o => o.Authority = "authority")
.AddSingleton<IConfiguration>(config);
var sp = services.BuildServiceProvider();
var options = sp.GetRequiredService<IOptionsSnapshot<JwtBearerOptions>>().Get(JwtBearerDefaults.AuthenticationScheme);
Assert.Null(options.Audience);
Assert.True(options.IncludeErrorDetails);
Assert.Equal("<audience>", options.Audience);
Assert.Equal("authority", options.Authority);
}
[ConditionalFact(Skip = "Need to remove dependency on AAD since the generated tokens will expire")]
@ -440,27 +449,6 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
Assert.Equal("Bob le Tout Puissant", response.ResponseText);
}
[Fact]
public async Task BearerTurns401To403IfAuthenticated()
{
var server = CreateServer(options =>
{
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new BlobTokenValidator("JWT"));
});
var response = await SendAsync(server, "http://example.com/unauthorized", "Bearer Token");
Assert.Equal(HttpStatusCode.Forbidden, response.Response.StatusCode);
}
[Fact]
public async Task BearerDoesNothingTo401IfNotAuthenticated()
{
var server = CreateServer();
var response = await SendAsync(server, "http://example.com/unauthorized");
Assert.Equal(HttpStatusCode.Unauthorized, response.Response.StatusCode);
}
[Fact]
public async Task EventOnMessageReceivedSkip_NoMoreEventsExecuted()
{

View File

@ -20,6 +20,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
using Newtonsoft.Json;
using Xunit;
@ -44,23 +45,26 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
{
var dic = new Dictionary<string, string>
{
{"Microsoft:ClientId", "<id>"},
{"Microsoft:ClientSecret", "<secret>"},
{"Microsoft:AuthorizationEndpoint", "<authEndpoint>"},
{"Microsoft:BackchannelTimeout", "0.0:0:30"},
{"Microsoft:AspNetCore:Authentication:Schemes:Microsoft:ClientId", "<id>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Microsoft:ClientSecret", "<secret>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Microsoft:AuthorizationEndpoint", "<authEndpoint>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Microsoft:BackchannelTimeout", "0.0:0:30"},
//{"Microsoft:CallbackPath", "/callbackpath"}, // PathString doesn't convert
{"Microsoft:ClaimsIssuer", "<issuer>"},
{"Microsoft:RemoteAuthenticationTimeout", "0.0:0:30"},
{"Microsoft:SaveTokens", "true"},
{"Microsoft:SendAppSecretProof", "true"},
{"Microsoft:SignInScheme", "<signIn>"},
{"Microsoft:TokenEndpoint", "<tokenEndpoint>"},
{"Microsoft:UserInformationEndpoint", "<userEndpoint>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Microsoft:ClaimsIssuer", "<issuer>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Microsoft:RemoteAuthenticationTimeout", "0.0:0:30"},
{"Microsoft:AspNetCore:Authentication:Schemes:Microsoft:SaveTokens", "true"},
{"Microsoft:AspNetCore:Authentication:Schemes:Microsoft:SendAppSecretProof", "true"},
{"Microsoft:AspNetCore:Authentication:Schemes:Microsoft:SignInScheme", "<signIn>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Microsoft:TokenEndpoint", "<tokenEndpoint>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Microsoft:UserInformationEndpoint", "<userEndpoint>"},
};
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddInMemoryCollection(dic);
var config = configurationBuilder.Build();
var services = new ServiceCollection().AddMicrosoftAccountAuthentication().AddSingleton<IConfiguration>(config);
var services = new ServiceCollection()
.AddSingleton<IConfigureOptions<MicrosoftAccountOptions>, ConfigureDefaults<MicrosoftAccountOptions>>()
.AddMicrosoftAccountAuthentication()
.AddSingleton<IConfiguration>(config);
var sp = services.BuildServiceProvider();
var options = sp.GetRequiredService<IOptionsSnapshot<MicrosoftAccountOptions>>().Get(MicrosoftAccountDefaults.AuthenticationScheme);

View File

@ -15,6 +15,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Xunit;
@ -34,15 +35,18 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
{
var dic = new Dictionary<string, string>
{
{"OpenIdConnect:ClientId", "<id>"},
{"OpenIdConnect:ClientSecret", "<secret>"},
{"OpenIdConnect:RequireHttpsMetadata", "false"},
{"OpenIdConnect:Authority", "<auth>"}
{"Microsoft:AspNetCore:Authentication:Schemes:OpenIdConnect:ClientId", "<id>"},
{"Microsoft:AspNetCore:Authentication:Schemes:OpenIdConnect:ClientSecret", "<secret>"},
{"Microsoft:AspNetCore:Authentication:Schemes:OpenIdConnect:RequireHttpsMetadata", "false"},
{"Microsoft:AspNetCore:Authentication:Schemes:OpenIdConnect:Authority", "<auth>"}
};
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddInMemoryCollection(dic);
var config = configurationBuilder.Build();
var services = new ServiceCollection().AddOpenIdConnectAuthentication().AddSingleton<IConfiguration>(config);
var services = new ServiceCollection()
.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, ConfigureDefaults<OpenIdConnectOptions>>()
.AddOpenIdConnectAuthentication()
.AddSingleton<IConfiguration>(config);
var sp = services.BuildServiceProvider();
var options = sp.GetRequiredService<IOptionsSnapshot<OpenIdConnectOptions>>().Get(OpenIdConnectDefaults.AuthenticationScheme);

View File

@ -5,7 +5,7 @@ using System;
using System.IO;
using System.Linq;
using System.Security.Claims;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;

View File

@ -14,6 +14,7 @@ using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options.Infrastructure;
using Xunit;
namespace Microsoft.AspNetCore.Authentication.Twitter
@ -37,20 +38,23 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
{
var dic = new Dictionary<string, string>
{
{"Twitter:ConsumerKey", "<key>"},
{"Twitter:ConsumerSecret", "<secret>"},
{"Twitter:BackchannelTimeout", "0.0:0:30"},
{"Microsoft:AspNetCore:Authentication:Schemes:Twitter:ConsumerKey", "<key>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Twitter:ConsumerSecret", "<secret>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Twitter:BackchannelTimeout", "0.0:0:30"},
//{"Twitter:CallbackPath", "/callbackpath"}, // PathString doesn't convert
{"Twitter:ClaimsIssuer", "<issuer>"},
{"Twitter:RemoteAuthenticationTimeout", "0.0:0:30"},
{"Twitter:SaveTokens", "true"},
{"Twitter:SendAppSecretProof", "true"},
{"Twitter:SignInScheme", "<signIn>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Twitter:ClaimsIssuer", "<issuer>"},
{"Microsoft:AspNetCore:Authentication:Schemes:Twitter:RemoteAuthenticationTimeout", "0.0:0:30"},
{"Microsoft:AspNetCore:Authentication:Schemes:Twitter:SaveTokens", "true"},
{"Microsoft:AspNetCore:Authentication:Schemes:Twitter:SendAppSecretProof", "true"},
{"Microsoft:AspNetCore:Authentication:Schemes:Twitter:SignInScheme", "<signIn>"},
};
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddInMemoryCollection(dic);
var config = configurationBuilder.Build();
var services = new ServiceCollection().AddTwitterAuthentication().AddSingleton<IConfiguration>(config);
var services = new ServiceCollection()
.AddSingleton<IConfigureOptions<TwitterOptions>, ConfigureDefaults<TwitterOptions>>()
.AddTwitterAuthentication()
.AddSingleton<IConfiguration>(config);
var sp = services.BuildServiceProvider();
var options = sp.GetRequiredService<IOptionsSnapshot<TwitterOptions>>().Get(TwitterDefaults.AuthenticationScheme);

View File

@ -25,9 +25,9 @@ namespace Microsoft.AspNetCore.Authroization.Test
// Arrange
var attributes = new AuthorizeAttribute[] {
new AuthorizeAttribute(),
new AuthorizeAttribute("1") { ActiveAuthenticationSchemes = "dupe" },
new AuthorizeAttribute("2") { ActiveAuthenticationSchemes = "dupe" },
new AuthorizeAttribute { Roles = "r1,r2", ActiveAuthenticationSchemes = "roles" },
new AuthorizeAttribute("1") { AuthenticationSchemes = "dupe" },
new AuthorizeAttribute("2") { AuthenticationSchemes = "dupe" },
new AuthorizeAttribute { Roles = "r1,r2", AuthenticationSchemes = "roles" },
};
var options = new AuthorizationOptions();
options.AddPolicy("1", policy => policy.RequireClaim("1"));
@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Authroization.Test
// Arrange
var attributes = new AuthorizeAttribute[] {
new AuthorizeAttribute(),
new AuthorizeAttribute("2") { ActiveAuthenticationSchemes = "dupe" }
new AuthorizeAttribute("2") { AuthenticationSchemes = "dupe" }
};
var options = new AuthorizationOptions();
options.DefaultPolicy = new AuthorizationPolicyBuilder("default").RequireClaim("default").Build();
@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Authroization.Test
{
// Arrange
var attributes = new AuthorizeAttribute[] {
new AuthorizeAttribute() { ActiveAuthenticationSchemes = "a1 , a2" }
new AuthorizeAttribute() { AuthenticationSchemes = "a1 , a2" }
};
var options = new AuthorizationOptions();
@ -120,7 +120,7 @@ namespace Microsoft.AspNetCore.Authroization.Test
{
// Arrange
var attributes = new AuthorizeAttribute[] {
new AuthorizeAttribute() { ActiveAuthenticationSchemes = "a1 , , ,,, a2" }
new AuthorizeAttribute() { AuthenticationSchemes = "a1 , , ,,, a2" }
};
var options = new AuthorizationOptions();

View File

@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Basic");
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Basic");
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -103,7 +103,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Basic");
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -126,7 +126,8 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(new ClaimsPrincipal(), "Custom");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
Assert.True(allowed.Failure.FailCalled);
Assert.True(handler1.Invoked);
Assert.True(handler2.Invoked);
}
@ -154,7 +155,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(new ClaimsPrincipal(), "Custom");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
Assert.True(handler1.Invoked);
Assert.Equal(invokeAllHandlers, handler2.Invoked);
}
@ -171,8 +172,6 @@ namespace Microsoft.AspNetCore.Authorization.Test
}
}
[Fact]
public async Task Authorize_ShouldFailWhenAllRequirementsNotHandled()
{
@ -196,7 +195,8 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Basic");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
Assert.IsType<ClaimsAuthorizationRequirement>(allowed.Failure.FailedRequirements.First());
}
[Fact]
@ -222,7 +222,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Basic");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
}
[Fact]
@ -248,7 +248,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Basic");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
}
[Fact]
@ -272,7 +272,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Basic");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
}
[Fact]
@ -291,7 +291,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(null, null, "Basic");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
}
[Fact]
@ -311,7 +311,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Basic");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
}
[Fact]
@ -337,7 +337,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Basic");
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -372,7 +372,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, policy.Build());
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -393,7 +393,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, policy.Build());
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -410,7 +410,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, policy.Build());
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -427,7 +427,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, null, policy.Build());
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -443,7 +443,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, policy.Build());
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -464,7 +464,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, policy.Build());
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
}
[Fact]
@ -489,7 +489,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Basic");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
}
[Fact]
@ -527,7 +527,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Hao");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
}
[Fact]
@ -553,7 +553,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Hao");
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -575,7 +575,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Hao");
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -597,7 +597,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Hao");
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -622,7 +622,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, null, "Any");
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -642,7 +642,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, null, "Any");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
}
public class CustomRequirement : IAuthorizationRequirement { }
@ -675,7 +675,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, null, "Custom");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
}
[Fact]
@ -696,7 +696,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, null, "Custom");
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
public class PassThroughRequirement : AuthorizationHandler<PassThroughRequirement>, IAuthorizationRequirement
@ -736,7 +736,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, null, "Passthrough");
// Assert
Assert.Equal(shouldSucceed, allowed);
Assert.Equal(shouldSucceed, allowed.Succeeded);
}
[Fact]
@ -764,7 +764,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, null, "Combined");
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -791,7 +791,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, null, "Combined");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
}
[Fact]
@ -818,7 +818,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, null, "Combined");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
}
public class ExpenseReport { }
@ -880,9 +880,9 @@ namespace Microsoft.AspNetCore.Authorization.Test
// Act
// Assert
Assert.True(await authorizationService.AuthorizeAsync(user, null, Operations.Edit));
Assert.True(await authorizationService.AuthorizeAsync(user, null, Operations.Delete));
Assert.True(await authorizationService.AuthorizeAsync(user, null, Operations.Create));
Assert.True((await authorizationService.AuthorizeAsync(user, null, Operations.Edit)).Succeeded);
Assert.True((await authorizationService.AuthorizeAsync(user, null, Operations.Delete)).Succeeded);
Assert.True((await authorizationService.AuthorizeAsync(user, null, Operations.Create)).Succeeded);
}
public class NotCalledHandler : AuthorizationHandler<OperationAuthorizationRequirement, string>
@ -922,8 +922,8 @@ namespace Microsoft.AspNetCore.Authorization.Test
// Act
// Assert
Assert.False(await authorizationService.AuthorizeAsync(user, 1, Operations.Edit));
Assert.True(await authorizationService.AuthorizeAsync(user, 2, Operations.Edit));
Assert.False((await authorizationService.AuthorizeAsync(user, 1, Operations.Edit)).Succeeded);
Assert.True((await authorizationService.AuthorizeAsync(user, 2, Operations.Edit)).Succeeded);
}
@ -945,7 +945,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
// Act
// Assert
Assert.False(await authorizationService.AuthorizeAsync(user, 1, Operations.Edit));
Assert.False((await authorizationService.AuthorizeAsync(user, 1, Operations.Edit)).Succeeded);
}
[Fact]
@ -960,9 +960,9 @@ namespace Microsoft.AspNetCore.Authorization.Test
// Act
// Assert
Assert.True(await authorizationService.AuthorizeAsync(user, new ExpenseReport(), Operations.Edit));
Assert.False(await authorizationService.AuthorizeAsync(user, new ExpenseReport(), Operations.Delete));
Assert.False(await authorizationService.AuthorizeAsync(user, new ExpenseReport(), Operations.Create));
Assert.True((await authorizationService.AuthorizeAsync(user, new ExpenseReport(), Operations.Edit)).Succeeded);
Assert.False((await authorizationService.AuthorizeAsync(user, new ExpenseReport(), Operations.Delete)).Succeeded);
Assert.False((await authorizationService.AuthorizeAsync(user, new ExpenseReport(), Operations.Create)).Succeeded);
}
[Fact]
@ -977,7 +977,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
// Act
// Assert
Assert.False(await authorizationService.AuthorizeAsync(user, null, Operations.Edit));
Assert.False((await authorizationService.AuthorizeAsync(user, null, Operations.Edit)).Succeeded);
}
[Fact]
@ -996,7 +996,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Basic");
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
[Fact]
@ -1015,7 +1015,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Basic");
// Assert
Assert.True(allowed);
Assert.True(allowed.Succeeded);
}
public class StaticPolicyProvider : IAuthorizationPolicyProvider
@ -1049,7 +1049,7 @@ namespace Microsoft.AspNetCore.Authorization.Test
var allowed = await authorizationService.AuthorizeAsync(user, "Basic");
// Assert
Assert.False(allowed);
Assert.False(allowed.Succeeded);
}
public class DynamicPolicyProvider : IAuthorizationPolicyProvider
@ -1081,23 +1081,15 @@ namespace Microsoft.AspNetCore.Authorization.Test
// Act
// Assert
Assert.False(await authorizationService.AuthorizeAsync(user, "0"));
Assert.True(await authorizationService.AuthorizeAsync(user, "1"));
Assert.True(await authorizationService.AuthorizeAsync(user, "2"));
Assert.False(await authorizationService.AuthorizeAsync(user, "3"));
Assert.False((await authorizationService.AuthorizeAsync(user, "0")).Succeeded);
Assert.True((await authorizationService.AuthorizeAsync(user, "1")).Succeeded);
Assert.True((await authorizationService.AuthorizeAsync(user, "2")).Succeeded);
Assert.False((await authorizationService.AuthorizeAsync(user, "3")).Succeeded);
}
public class SuccessEvaluator : IAuthorizationEvaluator
{
public bool HasFailed(AuthorizationHandlerContext context)
{
return false;
}
public bool HasSucceeded(AuthorizationHandlerContext context)
{
return true;
}
public AuthorizationResult Evaluate(AuthorizationHandlerContext context) => AuthorizationResult.Success();
}
[Fact]
@ -1108,7 +1100,8 @@ namespace Microsoft.AspNetCore.Authorization.Test
services.AddSingleton<IAuthorizationEvaluator, SuccessEvaluator>();
services.AddAuthorization(options => options.AddPolicy("Fail", p => p.RequireAssertion(c => false)));
});
Assert.True(await authorizationService.AuthorizeAsync(null, "Fail"));
var result = await authorizationService.AuthorizeAsync(null, "Fail");
Assert.True(result.Succeeded);
}
@ -1149,7 +1142,26 @@ namespace Microsoft.AspNetCore.Authorization.Test
services.AddSingleton<IAuthorizationHandlerContextFactory, BadContextMaker>();
services.AddAuthorization(options => options.AddPolicy("Success", p => p.RequireAssertion(c => true)));
});
Assert.False(await authorizationService.AuthorizeAsync(null, "Success"));
Assert.False((await authorizationService.AuthorizeAsync(null, "Success")).Succeeded);
}
public class SadHandlerProvider : IAuthorizationHandlerProvider
{
public Task<IEnumerable<IAuthorizationHandler>> GetHandlersAsync(AuthorizationHandlerContext context)
{
return Task.FromResult<IEnumerable<IAuthorizationHandler>>(new IAuthorizationHandler[1] { new FailHandler() });
}
}
[Fact]
public async Task CanUseCustomHandlerProvider()
{
var authorizationService = BuildAuthorizationService(services =>
{
services.AddSingleton<IAuthorizationHandlerProvider, SadHandlerProvider>();
services.AddAuthorization(options => options.AddPolicy("Success", p => p.RequireAssertion(c => true)));
});
Assert.False((await authorizationService.AuthorizeAsync(null, "Success")).Succeeded);
}
}

View File

@ -9,9 +9,11 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authorization\Microsoft.AspNetCore.Authorization.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authorization.Policy\Microsoft.AspNetCore.Authorization.Policy.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Testing" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(AspNetCoreVersion)" />

View File

@ -0,0 +1,179 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Microsoft.AspNetCore.Authorization.Policy.Test
{
public class PolicyEvaluatorTests
{
[Fact]
public async Task AuthenticateFailsIfNoPrincipalReturned()
{
// Arrange
var evaluator = new PolicyEvaluator(new HappyAuthorization());
var context = new DefaultHttpContext();
var services = new ServiceCollection().AddSingleton<IAuthenticationService, SadAuthentication>();
context.RequestServices = services.BuildServiceProvider();
var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build();
// Act
var result = await evaluator.AuthenticateAsync(policy, context);
// Assert
Assert.False(result.Succeeded);
}
[Fact]
public async Task AuthenticateMergeSchemes()
{
// Arrange
var evaluator = new PolicyEvaluator(new HappyAuthorization());
var context = new DefaultHttpContext();
var services = new ServiceCollection().AddSingleton<IAuthenticationService, EchoAuthentication>();
context.RequestServices = services.BuildServiceProvider();
var policy = new AuthorizationPolicyBuilder().AddAuthenticationSchemes("A","B","C").RequireAssertion(_ => true).Build();
// Act
var result = await evaluator.AuthenticateAsync(policy, context);
// Assert
Assert.True(result.Succeeded);
Assert.Equal(3, result.Principal.Identities.Count());
}
[Fact]
public async Task AuthorizeSucceedsEvenIfAuthenticationFails()
{
// Arrange
var evaluator = new PolicyEvaluator(new HappyAuthorization());
var context = new DefaultHttpContext();
var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build();
// Act
var result = await evaluator.AuthorizeAsync(policy, AuthenticateResult.Fail("Nooo"), context);
// Assert
Assert.True(result.Succeeded);
Assert.False(result.Challenged);
Assert.False(result.Forbidden);
}
[Fact]
public async Task AuthorizeChallengesIfAuthenticationFails()
{
// Arrange
var evaluator = new PolicyEvaluator(new SadAuthorization());
var context = new DefaultHttpContext();
var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build();
// Act
var result = await evaluator.AuthorizeAsync(policy, AuthenticateResult.Fail("Nooo"), context);
// Assert
Assert.False(result.Succeeded);
Assert.True(result.Challenged);
Assert.False(result.Forbidden);
}
[Fact]
public async Task AuthorizeForbidsIfAuthenticationSuceeds()
{
// Arrange
var evaluator = new PolicyEvaluator(new SadAuthorization());
var context = new DefaultHttpContext();
var policy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build();
// Act
var result = await evaluator.AuthorizeAsync(policy, AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(), "scheme")), context);
// Assert
Assert.False(result.Succeeded);
Assert.False(result.Challenged);
Assert.True(result.Forbidden);
}
public class HappyAuthorization : IAuthorizationService
{
public Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements)
=> Task.FromResult(AuthorizationResult.Success());
public Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName)
=> Task.FromResult(AuthorizationResult.Success());
}
public class SadAuthorization : IAuthorizationService
{
public Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements)
=> Task.FromResult(AuthorizationResult.Failed());
public Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName)
=> Task.FromResult(AuthorizationResult.Failed());
}
public class SadAuthentication : IAuthenticationService
{
public Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string scheme)
{
return Task.FromResult(AuthenticateResult.Fail("Sad."));
}
public Task ChallengeAsync(HttpContext context, string scheme, AuthenticationProperties properties)
{
throw new System.NotImplementedException();
}
public Task ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties)
{
throw new System.NotImplementedException();
}
public Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties)
{
throw new System.NotImplementedException();
}
public Task SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties)
{
throw new System.NotImplementedException();
}
}
public class EchoAuthentication : IAuthenticationService
{
public Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string scheme)
{
return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(new ClaimsIdentity(scheme)), scheme)));
}
public Task ChallengeAsync(HttpContext context, string scheme, AuthenticationProperties properties)
{
throw new System.NotImplementedException();
}
public Task ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties)
{
throw new System.NotImplementedException();
}
public Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties)
{
throw new System.NotImplementedException();
}
public Task SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties)
{
throw new System.NotImplementedException();
}
}
}
}