Switch to Options Initializer
This commit is contained in:
parent
bdd4d21996
commit
1f5a27e20a
|
|
@ -75,7 +75,6 @@ namespace SocialSample
|
|||
// https://console.developers.google.com/project
|
||||
services.AddOAuthAuthentication("Google-AccessToken", o =>
|
||||
{
|
||||
o.DisplayName = "Google-AccessToken";
|
||||
o.ClientId = Configuration["google:clientid"];
|
||||
o.ClientSecret = Configuration["google:clientsecret"];
|
||||
o.CallbackPath = new PathString("/signin-google-token");
|
||||
|
|
@ -137,7 +136,6 @@ namespace SocialSample
|
|||
// https://apps.dev.microsoft.com/
|
||||
services.AddOAuthAuthentication("Microsoft-AccessToken", o =>
|
||||
{
|
||||
o.DisplayName = "MicrosoftAccount-AccessToken";
|
||||
o.ClientId = Configuration["microsoftaccount:clientid"];
|
||||
o.ClientSecret = Configuration["microsoftaccount:clientsecret"];
|
||||
o.CallbackPath = new PathString("/signin-microsoft-token");
|
||||
|
|
@ -160,7 +158,6 @@ namespace SocialSample
|
|||
// https://github.com/settings/applications/
|
||||
services.AddOAuthAuthentication("GitHub-AccessToken", o =>
|
||||
{
|
||||
o.DisplayName = "Github-AccessToken";
|
||||
o.ClientId = Configuration["github-token:clientid"];
|
||||
o.ClientSecret = Configuration["github-token:clientsecret"];
|
||||
o.CallbackPath = new PathString("/signin-github-token");
|
||||
|
|
@ -178,7 +175,6 @@ namespace SocialSample
|
|||
// https://github.com/settings/applications/
|
||||
services.AddOAuthAuthentication("GitHub", o =>
|
||||
{
|
||||
o.DisplayName = "Github";
|
||||
o.ClientId = Configuration["github:clientid"];
|
||||
o.ClientSecret = Configuration["github:clientsecret"];
|
||||
o.CallbackPath = new PathString("/signin-github");
|
||||
|
|
|
|||
|
|
@ -59,39 +59,6 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
|
|||
/// <returns>A new instance of the events instance.</returns>
|
||||
protected override Task<object> CreateEventsAsync() => Task.FromResult<object>(new CookieAuthenticationEvents());
|
||||
|
||||
protected override void InitializeOptions()
|
||||
{
|
||||
base.InitializeOptions();
|
||||
|
||||
if (String.IsNullOrEmpty(Options.CookieName))
|
||||
{
|
||||
Options.CookieName = CookieAuthenticationDefaults.CookiePrefix + Scheme.Name;
|
||||
}
|
||||
if (Options.TicketDataFormat == null)
|
||||
{
|
||||
var provider = Options.DataProtectionProvider ?? Context.RequestServices.GetRequiredService<IDataProtectionProvider>();
|
||||
// Note: the purpose for the data protector must remain fixed for interop to work.
|
||||
var dataProtector = provider.CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", Scheme.Name, "v2");
|
||||
Options.TicketDataFormat = new TicketDataFormat(dataProtector);
|
||||
}
|
||||
if (Options.CookieManager == null)
|
||||
{
|
||||
Options.CookieManager = new ChunkingCookieManager();
|
||||
}
|
||||
if (!Options.LoginPath.HasValue)
|
||||
{
|
||||
Options.LoginPath = CookieAuthenticationDefaults.LoginPath;
|
||||
}
|
||||
if (!Options.LogoutPath.HasValue)
|
||||
{
|
||||
Options.LogoutPath = CookieAuthenticationDefaults.LogoutPath;
|
||||
}
|
||||
if (!Options.AccessDeniedPath.HasValue)
|
||||
{
|
||||
Options.AccessDeniedPath = CookieAuthenticationDefaults.AccessDeniedPath;
|
||||
}
|
||||
}
|
||||
|
||||
private Task<AuthenticateResult> EnsureCookieTicket()
|
||||
{
|
||||
// We only need to read the ticket once
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to setup defaults for all <see cref="CookieAuthenticationOptions"/>.
|
||||
/// </summary>
|
||||
public class CookieAuthenticationInitializer : IInitializeOptions<CookieAuthenticationOptions>
|
||||
{
|
||||
private readonly IDataProtectionProvider _dp;
|
||||
|
||||
public CookieAuthenticationInitializer(IDataProtectionProvider dataProtection)
|
||||
{
|
||||
_dp = dataProtection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked to initialize a TOptions instance.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the options instance being initialized.</param>
|
||||
/// <param name="options">The options instance to initialize.</param>
|
||||
public void Initialize(string name, CookieAuthenticationOptions options)
|
||||
{
|
||||
options.DataProtectionProvider = options.DataProtectionProvider ?? _dp;
|
||||
|
||||
if (String.IsNullOrEmpty(options.CookieName))
|
||||
{
|
||||
options.CookieName = CookieAuthenticationDefaults.CookiePrefix + name;
|
||||
}
|
||||
if (options.TicketDataFormat == null)
|
||||
{
|
||||
// Note: the purpose for the data protector must remain fixed for interop to work.
|
||||
var dataProtector = options.DataProtectionProvider.CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", name, "v2");
|
||||
options.TicketDataFormat = new TicketDataFormat(dataProtector);
|
||||
}
|
||||
if (options.CookieManager == null)
|
||||
{
|
||||
options.CookieManager = new ChunkingCookieManager();
|
||||
}
|
||||
if (!options.LoginPath.HasValue)
|
||||
{
|
||||
options.LoginPath = CookieAuthenticationDefaults.LoginPath;
|
||||
}
|
||||
if (!options.LogoutPath.HasValue)
|
||||
{
|
||||
options.LogoutPath = CookieAuthenticationDefaults.LogoutPath;
|
||||
}
|
||||
if (!options.AccessDeniedPath.HasValue)
|
||||
{
|
||||
options.AccessDeniedPath = CookieAuthenticationDefaults.AccessDeniedPath;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies
|
||||
{
|
||||
|
|
@ -71,7 +72,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
|
|||
public CookieSecurePolicy CookieSecure { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If set this will be used by the CookieAuthenticationMiddleware for data protection.
|
||||
/// If set this will be used by the CookieAuthenticationHandler for data protection.
|
||||
/// </summary>
|
||||
public IDataProtectionProvider DataProtectionProvider { get; set; }
|
||||
|
||||
|
|
@ -129,9 +130,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
|
|||
|
||||
/// <summary>
|
||||
/// The TicketDataFormat is used to protect and unprotect the identity and other properties which are stored in the
|
||||
/// cookie value. If it is not provided a default data handler is created using the data protection service contained
|
||||
/// in the IApplicationBuilder.Properties. The default data protection service is based on machine key when running on ASP.NET,
|
||||
/// and on DPAPI when running in a different process.
|
||||
/// cookie value. If not provided one will be created using <see cref="DataProtectionProvider"/>.
|
||||
/// </summary>
|
||||
public ISecureDataFormat<AuthenticationTicket> TicketDataFormat { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
|
|
@ -15,7 +19,10 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
public static IServiceCollection AddCookieAuthentication(this IServiceCollection services, Action<CookieAuthenticationOptions> configureOptions) =>
|
||||
services.AddCookieAuthentication(CookieAuthenticationDefaults.AuthenticationScheme, configureOptions);
|
||||
|
||||
public static IServiceCollection AddCookieAuthentication(this IServiceCollection services, string authenticationScheme, Action<CookieAuthenticationOptions> configureOptions) =>
|
||||
services.AddScheme<CookieAuthenticationOptions, CookieAuthenticationHandler>(authenticationScheme, configureOptions);
|
||||
public static IServiceCollection AddCookieAuthentication(this IServiceCollection services, string authenticationScheme, Action<CookieAuthenticationOptions> configureOptions)
|
||||
{
|
||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<IInitializeOptions<CookieAuthenticationOptions>, CookieAuthenticationInitializer>());
|
||||
return services.AddScheme<CookieAuthenticationOptions, CookieAuthenticationHandler>(authenticationScheme, configureOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
|
||||
public static IServiceCollection AddFacebookAuthentication(this IServiceCollection services, string authenticationScheme, Action<FacebookOptions> configureOptions)
|
||||
{
|
||||
return services.AddScheme<FacebookOptions, FacebookHandler>(authenticationScheme, authenticationScheme, configureOptions);
|
||||
return services.AddOAuthAuthentication<FacebookOptions, FacebookHandler>(authenticationScheme, configureOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ using System.Text;
|
|||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
|
@ -19,8 +18,8 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
|
|||
{
|
||||
internal class FacebookHandler : OAuthHandler<FacebookOptions>
|
||||
{
|
||||
public FacebookHandler(IOptions<AuthenticationOptions> sharedOptions, IOptionsSnapshot<FacebookOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
|
||||
: base(sharedOptions, options, logger, encoder, dataProtection, clock)
|
||||
public FacebookHandler(IOptionsSnapshot<FacebookOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||
: base(options, logger, encoder, clock)
|
||||
{ }
|
||||
|
||||
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
|
||||
public static IServiceCollection AddGoogleAuthentication(this IServiceCollection services, string authenticationScheme, Action<GoogleOptions> configureOptions)
|
||||
{
|
||||
return services.AddScheme<GoogleOptions, GoogleHandler>(authenticationScheme, authenticationScheme, configureOptions);
|
||||
return services.AddOAuthAuthentication<GoogleOptions, GoogleHandler>(authenticationScheme, configureOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ using System.Security.Claims;
|
|||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
|
@ -19,8 +18,8 @@ namespace Microsoft.AspNetCore.Authentication.Google
|
|||
{
|
||||
internal class GoogleHandler : OAuthHandler<GoogleOptions>
|
||||
{
|
||||
public GoogleHandler(IOptions<AuthenticationOptions> sharedOptions, IOptionsSnapshot<GoogleOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
|
||||
: base(sharedOptions, options, logger, encoder, dataProtection, clock)
|
||||
public GoogleHandler(IOptionsSnapshot<GoogleOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||
: base(options, logger, encoder, clock)
|
||||
{ }
|
||||
|
||||
protected override async Task<AuthenticationTicket> CreateTicketAsync(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
|
|
@ -26,6 +27,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
|
||||
public static IServiceCollection AddJwtBearerAuthentication(this IServiceCollection services, string authenticationScheme, Action<JwtBearerOptions> configureOptions)
|
||||
{
|
||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<IInitializeOptions<JwtBearerOptions>, JwtBearerInitializer>());
|
||||
return services.AddScheme<JwtBearerOptions, JwtBearerHandler>(authenticationScheme, configureOptions);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,49 +40,6 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
|
||||
protected override Task<object> CreateEventsAsync() => Task.FromResult<object>(new JwtBearerEvents());
|
||||
|
||||
protected override void InitializeOptions()
|
||||
{
|
||||
base.InitializeOptions();
|
||||
|
||||
if (string.IsNullOrEmpty(Options.TokenValidationParameters.ValidAudience) && !string.IsNullOrEmpty(Options.Audience))
|
||||
{
|
||||
Options.TokenValidationParameters.ValidAudience = Options.Audience;
|
||||
}
|
||||
|
||||
if (Options.ConfigurationManager == null)
|
||||
{
|
||||
if (Options.Configuration != null)
|
||||
{
|
||||
Options.ConfigurationManager = new StaticConfigurationManager<OpenIdConnectConfiguration>(Options.Configuration);
|
||||
}
|
||||
else if (!(string.IsNullOrEmpty(Options.MetadataAddress) && string.IsNullOrEmpty(Options.Authority)))
|
||||
{
|
||||
if (string.IsNullOrEmpty(Options.MetadataAddress) && !string.IsNullOrEmpty(Options.Authority))
|
||||
{
|
||||
Options.MetadataAddress = Options.Authority;
|
||||
if (!Options.MetadataAddress.EndsWith("/", StringComparison.Ordinal))
|
||||
{
|
||||
Options.MetadataAddress += "/";
|
||||
}
|
||||
|
||||
Options.MetadataAddress += ".well-known/openid-configuration";
|
||||
}
|
||||
|
||||
if (Options.RequireHttpsMetadata && !Options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidOperationException("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.");
|
||||
}
|
||||
|
||||
var httpClient = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
|
||||
httpClient.Timeout = Options.BackchannelTimeout;
|
||||
httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
|
||||
|
||||
Options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(Options.MetadataAddress, new OpenIdConnectConfigurationRetriever(),
|
||||
new HttpDocumentRetriever(httpClient) { RequireHttps = Options.RequireHttpsMetadata });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the 'Authorization' header for a 'Bearer' token. If the 'Bearer' token is found, it is validated using <see cref="TokenValidationParameters"/> set in the options.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Protocols;
|
||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to setup defaults for all <see cref="JwtBearerOptions"/>.
|
||||
/// </summary>
|
||||
public class JwtBearerInitializer : IInitializeOptions<JwtBearerOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked to initialize a JwtBearerOptions instance.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the options instance being initialized.</param>
|
||||
/// <param name="options">The options instance to initialize.</param>
|
||||
public void Initialize(string name, JwtBearerOptions options)
|
||||
{
|
||||
if (string.IsNullOrEmpty(options.TokenValidationParameters.ValidAudience) && !string.IsNullOrEmpty(options.Audience))
|
||||
{
|
||||
options.TokenValidationParameters.ValidAudience = options.Audience;
|
||||
}
|
||||
|
||||
if (options.ConfigurationManager == null)
|
||||
{
|
||||
if (options.Configuration != null)
|
||||
{
|
||||
options.ConfigurationManager = new StaticConfigurationManager<OpenIdConnectConfiguration>(options.Configuration);
|
||||
}
|
||||
else if (!(string.IsNullOrEmpty(options.MetadataAddress) && string.IsNullOrEmpty(options.Authority)))
|
||||
{
|
||||
if (string.IsNullOrEmpty(options.MetadataAddress) && !string.IsNullOrEmpty(options.Authority))
|
||||
{
|
||||
options.MetadataAddress = options.Authority;
|
||||
if (!options.MetadataAddress.EndsWith("/", StringComparison.Ordinal))
|
||||
{
|
||||
options.MetadataAddress += "/";
|
||||
}
|
||||
|
||||
options.MetadataAddress += ".well-known/openid-configuration";
|
||||
}
|
||||
|
||||
if (options.RequireHttpsMetadata && !options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidOperationException("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.");
|
||||
}
|
||||
|
||||
var httpClient = new HttpClient(options.BackchannelHttpHandler ?? new HttpClientHandler());
|
||||
httpClient.Timeout = options.BackchannelTimeout;
|
||||
httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
|
||||
|
||||
options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(options.MetadataAddress, new OpenIdConnectConfigurationRetriever(),
|
||||
new HttpDocumentRetriever(httpClient) { RequireHttps = options.RequireHttpsMetadata });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
|
||||
public static IServiceCollection AddMicrosoftAccountAuthentication(this IServiceCollection services, string authenticationScheme, Action<MicrosoftAccountOptions> configureOptions)
|
||||
{
|
||||
return services.AddScheme<MicrosoftAccountOptions, MicrosoftAccountHandler>(authenticationScheme, authenticationScheme, configureOptions);
|
||||
return services.AddOAuthAuthentication<MicrosoftAccountOptions, MicrosoftAccountHandler>(authenticationScheme, configureOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@ using System.Security.Claims;
|
|||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
|
@ -16,8 +15,8 @@ namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
|
|||
{
|
||||
internal class MicrosoftAccountHandler : OAuthHandler<MicrosoftAccountOptions>
|
||||
{
|
||||
public MicrosoftAccountHandler(IOptions<AuthenticationOptions> sharedOptions, IOptionsSnapshot<MicrosoftAccountOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
|
||||
: base(sharedOptions, options, logger, encoder, dataProtection, clock)
|
||||
public MicrosoftAccountHandler(IOptionsSnapshot<MicrosoftAccountOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||
: base(options, logger, encoder, clock)
|
||||
{ }
|
||||
|
||||
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
|||
|
||||
foreach (var action in Options.ClaimActions)
|
||||
{
|
||||
action.Run(userData, Identity, Options.ClaimsIssuer);
|
||||
action.Run(userData, Identity, Options.ClaimsIssuer ?? Scheme.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,24 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
public static class OAuthExtensions
|
||||
{
|
||||
public static IServiceCollection AddOAuthAuthentication(this IServiceCollection services, string authenticationScheme, Action<OAuthOptions> configureOptions) =>
|
||||
services.AddScheme<OAuthOptions, OAuthHandler<OAuthOptions>>(authenticationScheme, authenticationScheme, configureOptions);
|
||||
public static IServiceCollection AddOAuthAuthentication(this IServiceCollection services, string authenticationScheme, Action<OAuthOptions> configureOptions)
|
||||
{
|
||||
return services.AddScheme<OAuthOptions, OAuthHandler<OAuthOptions>>(authenticationScheme, authenticationScheme, configureOptions);
|
||||
}
|
||||
|
||||
public static IServiceCollection AddOAuthAuthentication<TOptions, THandler>(this IServiceCollection services, string authenticationScheme, Action<TOptions> configureOptions)
|
||||
where TOptions : OAuthOptions, new()
|
||||
where THandler : OAuthHandler<TOptions>
|
||||
{
|
||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<IInitializeOptions<TOptions>, OAuthInitializer<TOptions, THandler>>());
|
||||
return services.AddRemoteScheme<TOptions, THandler>(authenticationScheme, authenticationScheme, configureOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ using System.Security.Claims;
|
|||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
|
@ -33,30 +32,10 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
|||
set { base.Events = value; }
|
||||
}
|
||||
|
||||
public OAuthHandler(IOptions<AuthenticationOptions> sharedOptions, IOptionsSnapshot<TOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
|
||||
: base(sharedOptions, options, dataProtection, logger, encoder, clock)
|
||||
public OAuthHandler(IOptionsSnapshot<TOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||
: base(options, logger, encoder, clock)
|
||||
{ }
|
||||
|
||||
protected override void InitializeOptions()
|
||||
{
|
||||
base.InitializeOptions();
|
||||
|
||||
if (Options.Backchannel == null)
|
||||
{
|
||||
Options.Backchannel = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
|
||||
Options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OAuth handler");
|
||||
Options.Backchannel.Timeout = Options.BackchannelTimeout;
|
||||
Options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
|
||||
}
|
||||
|
||||
if (Options.StateDataFormat == null)
|
||||
{
|
||||
var dataProtector = DataProtection.CreateProtector(
|
||||
GetType().FullName, Scheme.Name, "v1");
|
||||
Options.StateDataFormat = new PropertiesDataFormat(dataProtector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the events instance.
|
||||
/// </summary>
|
||||
|
|
@ -119,7 +98,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
|||
return AuthenticateResult.Fail("Failed to retrieve access token.");
|
||||
}
|
||||
|
||||
var identity = new ClaimsIdentity(Options.ClaimsIssuer);
|
||||
var identity = new ClaimsIdentity(ClaimsIssuer);
|
||||
|
||||
if (Options.SaveTokens)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to setup defaults for the OAuthOptions.
|
||||
/// </summary>
|
||||
public class OAuthInitializer<TOptions, THandler> : IInitializeOptions<TOptions>
|
||||
where TOptions : OAuthOptions, new()
|
||||
where THandler : OAuthHandler<TOptions>
|
||||
{
|
||||
private readonly IDataProtectionProvider _dp;
|
||||
|
||||
public OAuthInitializer(IDataProtectionProvider dataProtection)
|
||||
{
|
||||
_dp = dataProtection;
|
||||
}
|
||||
|
||||
public void Initialize(string name, TOptions options)
|
||||
{
|
||||
options.DataProtectionProvider = options.DataProtectionProvider ?? _dp;
|
||||
if (options.Backchannel == null)
|
||||
{
|
||||
options.Backchannel = new HttpClient(options.BackchannelHttpHandler ?? new HttpClientHandler());
|
||||
options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OAuth handler");
|
||||
options.Backchannel.Timeout = options.BackchannelTimeout;
|
||||
options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
|
||||
}
|
||||
|
||||
if (options.StateDataFormat == null)
|
||||
{
|
||||
var dataProtector = options.DataProtectionProvider.CreateProtector(
|
||||
typeof(THandler).FullName, name, "v1");
|
||||
options.StateDataFormat = new PropertiesDataFormat(dataProtector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
|
|
@ -26,7 +27,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
|
||||
public static IServiceCollection AddOpenIdConnectAuthentication(this IServiceCollection services, string authenticationScheme, Action<OpenIdConnectOptions> configureOptions)
|
||||
{
|
||||
return services.AddScheme<OpenIdConnectOptions, OpenIdConnectHandler>(authenticationScheme, authenticationScheme, configureOptions);
|
||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<IInitializeOptions<OpenIdConnectOptions>, OpenIdConnectInitializer>());
|
||||
return services.AddRemoteScheme<OpenIdConnectOptions, OpenIdConnectHandler>(authenticationScheme, authenticationScheme, configureOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,10 @@ using System.Security.Cryptography;
|
|||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.IdentityModel.Protocols;
|
||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
|
@ -57,8 +55,8 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
|||
|
||||
protected HtmlEncoder HtmlEncoder { get; }
|
||||
|
||||
public OpenIdConnectHandler(IOptions<AuthenticationOptions> sharedOptions, IOptionsSnapshot<OpenIdConnectOptions> options, ILoggerFactory logger, HtmlEncoder htmlEncoder, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
|
||||
: base(sharedOptions, options, dataProtection, logger, encoder, clock)
|
||||
public OpenIdConnectHandler(IOptionsSnapshot<OpenIdConnectOptions> options, ILoggerFactory logger, HtmlEncoder htmlEncoder, UrlEncoder encoder, ISystemClock clock)
|
||||
: base(options, logger, encoder, clock)
|
||||
{
|
||||
HtmlEncoder = htmlEncoder;
|
||||
}
|
||||
|
|
@ -75,76 +73,6 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
|||
|
||||
protected override Task<object> CreateEventsAsync() => Task.FromResult<object>(new OpenIdConnectEvents());
|
||||
|
||||
protected override void InitializeOptions()
|
||||
{
|
||||
base.InitializeOptions();
|
||||
|
||||
if (string.IsNullOrEmpty(Options.SignOutScheme))
|
||||
{
|
||||
Options.SignOutScheme = SignInScheme;
|
||||
}
|
||||
|
||||
if (Options.StateDataFormat == null)
|
||||
{
|
||||
var dataProtector = DataProtection.CreateProtector(
|
||||
GetType().FullName, Scheme.Name, "v1");
|
||||
Options.StateDataFormat = new PropertiesDataFormat(dataProtector);
|
||||
}
|
||||
|
||||
if (Options.StringDataFormat == null)
|
||||
{
|
||||
var dataProtector = DataProtection.CreateProtector(
|
||||
GetType().FullName,
|
||||
typeof(string).FullName,
|
||||
Scheme.Name,
|
||||
"v1");
|
||||
|
||||
Options.StringDataFormat = new SecureDataFormat<string>(new StringSerializer(), dataProtector);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(Options.TokenValidationParameters.ValidAudience) && !string.IsNullOrEmpty(Options.ClientId))
|
||||
{
|
||||
Options.TokenValidationParameters.ValidAudience = Options.ClientId;
|
||||
}
|
||||
|
||||
if (Options.Backchannel == null)
|
||||
{
|
||||
Options.Backchannel = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
|
||||
Options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OpenIdConnect handler");
|
||||
Options.Backchannel.Timeout = Options.BackchannelTimeout;
|
||||
Options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
|
||||
}
|
||||
|
||||
if (Options.ConfigurationManager == null)
|
||||
{
|
||||
if (Options.Configuration != null)
|
||||
{
|
||||
Options.ConfigurationManager = new StaticConfigurationManager<OpenIdConnectConfiguration>(Options.Configuration);
|
||||
}
|
||||
else if (!(string.IsNullOrEmpty(Options.MetadataAddress) && string.IsNullOrEmpty(Options.Authority)))
|
||||
{
|
||||
if (string.IsNullOrEmpty(Options.MetadataAddress) && !string.IsNullOrEmpty(Options.Authority))
|
||||
{
|
||||
Options.MetadataAddress = Options.Authority;
|
||||
if (!Options.MetadataAddress.EndsWith("/", StringComparison.Ordinal))
|
||||
{
|
||||
Options.MetadataAddress += "/";
|
||||
}
|
||||
|
||||
Options.MetadataAddress += ".well-known/openid-configuration";
|
||||
}
|
||||
|
||||
if (Options.RequireHttpsMetadata && !Options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidOperationException("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.");
|
||||
}
|
||||
|
||||
Options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(Options.MetadataAddress, new OpenIdConnectConfigurationRetriever(),
|
||||
new HttpDocumentRetriever(Backchannel) { RequireHttps = Options.RequireHttpsMetadata });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Task<bool> HandleRequestAsync()
|
||||
{
|
||||
if (Options.RemoteSignOutPath.HasValue && Options.RemoteSignOutPath == Request.Path)
|
||||
|
|
@ -749,7 +677,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
|||
var identity = (ClaimsIdentity)ticket.Principal.Identity;
|
||||
foreach (var action in Options.ClaimActions)
|
||||
{
|
||||
action.Run(null, identity, Options.ClaimsIssuer);
|
||||
action.Run(null, identity, ClaimsIssuer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -902,7 +830,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
|||
|
||||
foreach (var action in Options.ClaimActions)
|
||||
{
|
||||
action.Run(user, identity, Options.ClaimsIssuer);
|
||||
action.Run(user, identity, ClaimsIssuer);
|
||||
}
|
||||
|
||||
return AuthenticateResult.Success(ticket);
|
||||
|
|
@ -1301,18 +1229,5 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
|||
description,
|
||||
errorUri));
|
||||
}
|
||||
|
||||
private class StringSerializer : IDataSerializer<string>
|
||||
{
|
||||
public string Deserialize(byte[] data)
|
||||
{
|
||||
return Encoding.UTF8.GetString(data);
|
||||
}
|
||||
|
||||
public byte[] Serialize(string model)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Protocols;
|
||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to setup defaults for all <see cref="OpenIdConnectOptions"/>.
|
||||
/// </summary>
|
||||
public class OpenIdConnectInitializer : IInitializeOptions<OpenIdConnectOptions>
|
||||
{
|
||||
private readonly IDataProtectionProvider _dp;
|
||||
|
||||
public OpenIdConnectInitializer(IDataProtectionProvider dataProtection)
|
||||
{
|
||||
_dp = dataProtection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked to initialize a TOptions instance.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the options instance being initialized.</param>
|
||||
/// <param name="options">The options instance to initialize.</param>
|
||||
public void Initialize(string name, OpenIdConnectOptions options)
|
||||
{
|
||||
options.DataProtectionProvider = options.DataProtectionProvider ?? _dp;
|
||||
|
||||
if (string.IsNullOrEmpty(options.SignOutScheme))
|
||||
{
|
||||
options.SignOutScheme = options.SignInScheme;
|
||||
}
|
||||
|
||||
if (options.StateDataFormat == null)
|
||||
{
|
||||
var dataProtector = options.DataProtectionProvider.CreateProtector(
|
||||
typeof(OpenIdConnectHandler).FullName, name, "v1");
|
||||
options.StateDataFormat = new PropertiesDataFormat(dataProtector);
|
||||
}
|
||||
|
||||
if (options.StringDataFormat == null)
|
||||
{
|
||||
var dataProtector = options.DataProtectionProvider.CreateProtector(
|
||||
typeof(OpenIdConnectHandler).FullName,
|
||||
typeof(string).FullName,
|
||||
name,
|
||||
"v1");
|
||||
|
||||
options.StringDataFormat = new SecureDataFormat<string>(new StringSerializer(), dataProtector);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(options.TokenValidationParameters.ValidAudience) && !string.IsNullOrEmpty(options.ClientId))
|
||||
{
|
||||
options.TokenValidationParameters.ValidAudience = options.ClientId;
|
||||
}
|
||||
|
||||
if (options.Backchannel == null)
|
||||
{
|
||||
options.Backchannel = new HttpClient(options.BackchannelHttpHandler ?? new HttpClientHandler());
|
||||
options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core OpenIdConnect handler");
|
||||
options.Backchannel.Timeout = options.BackchannelTimeout;
|
||||
options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
|
||||
}
|
||||
|
||||
if (options.ConfigurationManager == null)
|
||||
{
|
||||
if (options.Configuration != null)
|
||||
{
|
||||
options.ConfigurationManager = new StaticConfigurationManager<OpenIdConnectConfiguration>(options.Configuration);
|
||||
}
|
||||
else if (!(string.IsNullOrEmpty(options.MetadataAddress) && string.IsNullOrEmpty(options.Authority)))
|
||||
{
|
||||
if (string.IsNullOrEmpty(options.MetadataAddress) && !string.IsNullOrEmpty(options.Authority))
|
||||
{
|
||||
options.MetadataAddress = options.Authority;
|
||||
if (!options.MetadataAddress.EndsWith("/", StringComparison.Ordinal))
|
||||
{
|
||||
options.MetadataAddress += "/";
|
||||
}
|
||||
|
||||
options.MetadataAddress += ".well-known/openid-configuration";
|
||||
}
|
||||
|
||||
if (options.RequireHttpsMetadata && !options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidOperationException("The MetadataAddress or Authority must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.");
|
||||
}
|
||||
|
||||
options.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(options.MetadataAddress, new OpenIdConnectConfigurationRetriever(),
|
||||
new HttpDocumentRetriever(options.Backchannel) { RequireHttps = options.RequireHttpsMetadata });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class StringSerializer : IDataSerializer<string>
|
||||
{
|
||||
public string Deserialize(byte[] data)
|
||||
{
|
||||
return Encoding.UTF8.GetString(data);
|
||||
}
|
||||
|
||||
public byte[] Serialize(string model)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -39,7 +39,6 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
|||
/// </remarks>
|
||||
public OpenIdConnectOptions()
|
||||
{
|
||||
DisplayName = OpenIdConnectDefaults.Caption;
|
||||
CallbackPath = new PathString("/signin-oidc");
|
||||
SignedOutCallbackPath = new PathString("/signout-callback-oidc");
|
||||
RemoteSignOutPath = new PathString("/signout-oidc");
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authentication.Twitter;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
|
|
@ -26,7 +27,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
|
||||
public static IServiceCollection AddTwitterAuthentication(this IServiceCollection services, string authenticationScheme, Action<TwitterOptions> configureOptions)
|
||||
{
|
||||
return services.AddScheme<TwitterOptions, TwitterHandler>(authenticationScheme, authenticationScheme, configureOptions);
|
||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<IInitializeOptions<TwitterOptions>, TwitterInitializer>());
|
||||
return services.AddRemoteScheme<TwitterOptions, TwitterHandler>(authenticationScheme, authenticationScheme, configureOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,36 +40,12 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
|||
set { base.Events = value; }
|
||||
}
|
||||
|
||||
public TwitterHandler(IOptions<AuthenticationOptions> sharedOptions, IOptionsSnapshot<TwitterOptions> options, ILoggerFactory logger, UrlEncoder encoder, IDataProtectionProvider dataProtection, ISystemClock clock)
|
||||
: base(sharedOptions, options, dataProtection, logger, encoder, clock)
|
||||
public TwitterHandler(IOptionsSnapshot<TwitterOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||
: base(options, logger, encoder, clock)
|
||||
{ }
|
||||
|
||||
protected override Task<object> CreateEventsAsync() => Task.FromResult<object>(new TwitterEvents());
|
||||
|
||||
protected override void InitializeOptions()
|
||||
{
|
||||
base.InitializeOptions();
|
||||
|
||||
if (Options.StateDataFormat == null)
|
||||
{
|
||||
var dataProtector = DataProtection.CreateProtector(
|
||||
GetType().FullName, Scheme.Name, "v1");
|
||||
Options.StateDataFormat = new SecureDataFormat<RequestToken>(
|
||||
new RequestTokenSerializer(),
|
||||
dataProtector);
|
||||
}
|
||||
|
||||
if (Options.Backchannel == null)
|
||||
{
|
||||
Options.Backchannel = new HttpClient(Options.BackchannelHttpHandler ?? new HttpClientHandler());
|
||||
Options.Backchannel.Timeout = Options.BackchannelTimeout;
|
||||
Options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
|
||||
Options.Backchannel.DefaultRequestHeaders.Accept.ParseAdd("*/*");
|
||||
Options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core Twitter handler");
|
||||
Options.Backchannel.DefaultRequestHeaders.ExpectContinue = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task<AuthenticateResult> HandleRemoteAuthenticateAsync()
|
||||
{
|
||||
AuthenticationProperties properties = null;
|
||||
|
|
@ -116,12 +92,12 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
|||
|
||||
var identity = new ClaimsIdentity(new[]
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, accessToken.UserId, ClaimValueTypes.String, Options.ClaimsIssuer),
|
||||
new Claim(ClaimTypes.Name, accessToken.ScreenName, ClaimValueTypes.String, Options.ClaimsIssuer),
|
||||
new Claim("urn:twitter:userid", accessToken.UserId, ClaimValueTypes.String, Options.ClaimsIssuer),
|
||||
new Claim("urn:twitter:screenname", accessToken.ScreenName, ClaimValueTypes.String, Options.ClaimsIssuer)
|
||||
new Claim(ClaimTypes.NameIdentifier, accessToken.UserId, ClaimValueTypes.String, ClaimsIssuer),
|
||||
new Claim(ClaimTypes.Name, accessToken.ScreenName, ClaimValueTypes.String, ClaimsIssuer),
|
||||
new Claim("urn:twitter:userid", accessToken.UserId, ClaimValueTypes.String, ClaimsIssuer),
|
||||
new Claim("urn:twitter:screenname", accessToken.ScreenName, ClaimValueTypes.String, ClaimsIssuer)
|
||||
},
|
||||
Options.ClaimsIssuer);
|
||||
ClaimsIssuer);
|
||||
|
||||
JObject user = null;
|
||||
if (Options.RetrieveUserDetails)
|
||||
|
|
@ -145,7 +121,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
|||
{
|
||||
foreach (var action in Options.ClaimActions)
|
||||
{
|
||||
action.Run(user, identity, Options.ClaimsIssuer);
|
||||
action.Run(user, identity, ClaimsIssuer);
|
||||
}
|
||||
|
||||
var context = new TwitterCreatingTicketContext(Context, Scheme, Options, properties, token.UserId, token.ScreenName, token.Token, token.TokenSecret, user)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to setup defaults for all <see cref="TwitterOptions"/>.
|
||||
/// </summary>
|
||||
public class TwitterInitializer : IInitializeOptions<TwitterOptions>
|
||||
{
|
||||
private readonly IDataProtectionProvider _dp;
|
||||
|
||||
public TwitterInitializer(IDataProtectionProvider dataProtection)
|
||||
{
|
||||
_dp = dataProtection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked to initialize a TOptions instance.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the options instance being initialized.</param>
|
||||
/// <param name="options">The options instance to initialize.</param>
|
||||
public void Initialize(string name, TwitterOptions options)
|
||||
{
|
||||
options.DataProtectionProvider = options.DataProtectionProvider ?? _dp;
|
||||
|
||||
if (options.StateDataFormat == null)
|
||||
{
|
||||
var dataProtector = options.DataProtectionProvider.CreateProtector(
|
||||
typeof(TwitterHandler).FullName, name, "v1");
|
||||
options.StateDataFormat = new SecureDataFormat<RequestToken>(
|
||||
new RequestTokenSerializer(),
|
||||
dataProtector);
|
||||
}
|
||||
|
||||
if (options.Backchannel == null)
|
||||
{
|
||||
options.Backchannel = new HttpClient(options.BackchannelHttpHandler ?? new HttpClientHandler());
|
||||
options.Backchannel.Timeout = options.BackchannelTimeout;
|
||||
options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
|
||||
options.Backchannel.DefaultRequestHeaders.Accept.ParseAdd("*/*");
|
||||
options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET Core Twitter handler");
|
||||
options.Backchannel.DefaultRequestHeaders.ExpectContinue = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -48,6 +48,8 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
/// </summary>
|
||||
protected virtual object Events { get; set; }
|
||||
|
||||
protected virtual string ClaimsIssuer => Options.ClaimsIssuer ?? Scheme.Name;
|
||||
|
||||
protected string CurrentUri
|
||||
{
|
||||
get
|
||||
|
|
@ -85,18 +87,6 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
Context = context;
|
||||
|
||||
Options = OptionsSnapshot.Get(Scheme.Name) ?? new TOptions();
|
||||
if (!Options.Initialized)
|
||||
{
|
||||
lock (Options.InitializeLock)
|
||||
{
|
||||
if (!Options.Initialized)
|
||||
{
|
||||
InitializeOptions();
|
||||
Options.Initialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Options.Validate();
|
||||
|
||||
await InitializeEventsAsync();
|
||||
|
|
@ -122,16 +112,6 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
/// <returns>A new instance of the events instance.</returns>
|
||||
protected virtual Task<object> CreateEventsAsync() => Task.FromResult(new object());
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the options, will be called only once by <see cref="InitializeAsync(AuthenticationScheme, HttpContext)"/>.
|
||||
/// </summary>
|
||||
protected virtual void InitializeOptions()
|
||||
{
|
||||
// REVIEW: is there a better place for this default?
|
||||
Options.DisplayName = Options.DisplayName ?? Scheme.Name;
|
||||
Options.ClaimsIssuer = Options.ClaimsIssuer ?? Scheme.Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after options/events have been initialized for the handler to finish initializing itself.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -2,9 +2,18 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication
|
||||
{
|
||||
public class InitializeAuthenticationSchemeOptions<TOptions> : InitializeOptions<TOptions>
|
||||
where TOptions : AuthenticationSchemeOptions
|
||||
{
|
||||
public InitializeAuthenticationSchemeOptions(string name)
|
||||
: base(name, options => options.ClaimsIssuer = options.ClaimsIssuer ?? name)
|
||||
{ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains the options used by the <see cref="AuthenticationHandler{T}"/>.
|
||||
/// </summary>
|
||||
|
|
@ -17,11 +26,6 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the display name for the authentication provider.
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the issuer that should be used for any claims that are created
|
||||
/// </summary>
|
||||
|
|
@ -36,15 +40,5 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
/// If set, will be used as the service type to get the Events instance instead of the property.
|
||||
/// </summary>
|
||||
public Type EventsType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to ensure that the options are only initialized once.
|
||||
/// </summary>
|
||||
public bool Initialized { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to prevent concurrent access during intialization.
|
||||
/// </summary>
|
||||
public object InitializeLock { get; } = new object();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,5 +74,30 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
where TOptions : AuthenticationSchemeOptions, new()
|
||||
where THandler : AuthenticationHandler<TOptions>
|
||||
=> services.AddScheme<TOptions, THandler>(authenticationScheme, displayName, configureScheme: null, configureOptions: configureOptions);
|
||||
|
||||
public static IServiceCollection AddRemoteScheme<TOptions, THandler>(this IServiceCollection services, string authenticationScheme, string displayName, Action<TOptions> configureOptions)
|
||||
where TOptions : RemoteAuthenticationOptions, new()
|
||||
where THandler : RemoteAuthenticationHandler<TOptions>
|
||||
{
|
||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<IInitializeOptions<TOptions>, EnsureSignInScheme<TOptions>>());
|
||||
return services.AddScheme<TOptions, THandler>(authenticationScheme, displayName, configureScheme: null, configureOptions: configureOptions);
|
||||
}
|
||||
|
||||
// Used to ensure that there's always a default data protection provider
|
||||
private class EnsureSignInScheme<TOptions> : IInitializeOptions<TOptions> where TOptions : RemoteAuthenticationOptions
|
||||
{
|
||||
private readonly AuthenticationOptions _authOptions;
|
||||
|
||||
public EnsureSignInScheme(IOptions<AuthenticationOptions> authOptions)
|
||||
{
|
||||
_authOptions = authOptions.Value;
|
||||
}
|
||||
|
||||
public void Initialize(string name, TOptions options)
|
||||
{
|
||||
options.SignInScheme = options.SignInScheme ?? _authOptions.DefaultSignInScheme;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ using System;
|
|||
using System.Security.Cryptography;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
|
|
@ -25,10 +23,6 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
|
||||
protected string SignInScheme => Options.SignInScheme;
|
||||
|
||||
protected IDataProtectionProvider DataProtection { get; set; }
|
||||
|
||||
private readonly AuthenticationOptions _authOptions;
|
||||
|
||||
/// <summary>
|
||||
/// The handler calls methods on the events which give the application control at certain points where processing is occurring.
|
||||
/// If it is not provided a default instance is supplied which does nothing when the methods are called.
|
||||
|
|
@ -39,17 +33,9 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
set { base.Events = value; }
|
||||
}
|
||||
|
||||
protected RemoteAuthenticationHandler(IOptions<AuthenticationOptions> sharedOptions, IOptionsSnapshot<TOptions> options, IDataProtectionProvider dataProtection, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||
protected RemoteAuthenticationHandler(IOptionsSnapshot<TOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
|
||||
: base(options, logger, encoder, clock)
|
||||
{
|
||||
_authOptions = sharedOptions.Value;
|
||||
DataProtection = dataProtection;
|
||||
}
|
||||
|
||||
protected override Task InitializeHandlerAsync()
|
||||
{
|
||||
DataProtection = Options.DataProtectionProvider ?? DataProtection;
|
||||
return TaskCache.CompletedTask;
|
||||
}
|
||||
|
||||
protected override Task<object> CreateEventsAsync()
|
||||
|
|
@ -57,16 +43,6 @@ namespace Microsoft.AspNetCore.Authentication
|
|||
return Task.FromResult<object>(new RemoteAuthenticationEvents());
|
||||
}
|
||||
|
||||
protected override void InitializeOptions()
|
||||
{
|
||||
base.InitializeOptions();
|
||||
|
||||
if (Options.SignInScheme == null)
|
||||
{
|
||||
Options.SignInScheme = _authOptions.DefaultSignInScheme;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Task<bool> ShouldHandleRequestAsync()
|
||||
{
|
||||
return Task.FromResult(Options.CallbackPath == Request.Path);
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
|
|||
{"Facebook:BackchannelTimeout", "0.0:0:30"},
|
||||
//{"Facebook:CallbackPath", "/callbackpath"}, // PathString doesn't convert
|
||||
{"Facebook:ClaimsIssuer", "<issuer>"},
|
||||
{"Facebook:DisplayName", "<display>"},
|
||||
{"Facebook:RemoteAuthenticationTimeout", "0.0:0:30"},
|
||||
{"Facebook:SaveTokens", "true"},
|
||||
{"Facebook:SendAppSecretProof", "true"},
|
||||
|
|
@ -73,7 +72,6 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
|
|||
Assert.Equal("<issuer>", options.ClaimsIssuer);
|
||||
Assert.Equal("<id>", options.ClientId);
|
||||
Assert.Equal("<secret>", options.ClientSecret);
|
||||
Assert.Equal("<display>", options.DisplayName);
|
||||
Assert.Equal(new TimeSpan(0, 0, 0, 30), options.RemoteAuthenticationTimeout);
|
||||
Assert.True(options.SaveTokens);
|
||||
Assert.True(options.SendAppSecretProof);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ namespace Microsoft.AspNetCore.Authentication.Google
|
|||
{"Google:BackchannelTimeout", "0.0:0:30"},
|
||||
//{"Google:CallbackPath", "/callbackpath"}, // PathString doesn't convert
|
||||
{"Google:ClaimsIssuer", "<issuer>"},
|
||||
{"Google:DisplayName", "<display>"},
|
||||
{"Google:RemoteAuthenticationTimeout", "0.0:0:30"},
|
||||
{"Google:SaveTokens", "true"},
|
||||
{"Google:SendAppSecretProof", "true"},
|
||||
|
|
@ -70,7 +69,6 @@ namespace Microsoft.AspNetCore.Authentication.Google
|
|||
Assert.Equal("<issuer>", options.ClaimsIssuer);
|
||||
Assert.Equal("<id>", options.ClientId);
|
||||
Assert.Equal("<secret>", options.ClientSecret);
|
||||
Assert.Equal("<display>", options.DisplayName);
|
||||
Assert.Equal(new TimeSpan(0, 0, 0, 30), options.RemoteAuthenticationTimeout);
|
||||
Assert.True(options.SaveTokens);
|
||||
Assert.Equal("<signIn>", options.SignInScheme);
|
||||
|
|
|
|||
|
|
@ -48,11 +48,10 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
{"Bearer:BackchannelTimeout", "0.0:0:30"},
|
||||
{"Bearer:Challenge", "<challenge>"},
|
||||
{"Bearer:ClaimsIssuer", "<issuer>"},
|
||||
{"Bearer:DisplayName", "<display>"},
|
||||
{"Bearer:IncludeErrorDetails", "true"},
|
||||
{"Bearer:MetadataAddress", "<metadata>"},
|
||||
{"Bearer:RefreshOnIssuerKeyNotFound", "true"},
|
||||
{"Bearer:RequireHttpsMetadata", "true"},
|
||||
{"Bearer:RequireHttpsMetadata", "false"},
|
||||
{"Bearer:SaveToken", "true"},
|
||||
};
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
|
|
@ -67,11 +66,10 @@ namespace Microsoft.AspNetCore.Authentication.JwtBearer
|
|||
Assert.Equal("<authority>", options.Authority);
|
||||
Assert.Equal("<challenge>", options.Challenge);
|
||||
Assert.Equal("<issuer>", options.ClaimsIssuer);
|
||||
Assert.Equal("<display>", options.DisplayName);
|
||||
Assert.True(options.IncludeErrorDetails);
|
||||
Assert.Equal("<metadata>", options.MetadataAddress);
|
||||
Assert.True(options.RefreshOnIssuerKeyNotFound);
|
||||
Assert.True(options.RequireHttpsMetadata);
|
||||
Assert.False(options.RequireHttpsMetadata);
|
||||
Assert.True(options.SaveToken);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
|
|||
{"Microsoft:BackchannelTimeout", "0.0:0:30"},
|
||||
//{"Microsoft:CallbackPath", "/callbackpath"}, // PathString doesn't convert
|
||||
{"Microsoft:ClaimsIssuer", "<issuer>"},
|
||||
{"Microsoft:DisplayName", "<display>"},
|
||||
{"Microsoft:RemoteAuthenticationTimeout", "0.0:0:30"},
|
||||
{"Microsoft:SaveTokens", "true"},
|
||||
{"Microsoft:SendAppSecretProof", "true"},
|
||||
|
|
@ -71,7 +70,6 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
|
|||
Assert.Equal("<issuer>", options.ClaimsIssuer);
|
||||
Assert.Equal("<id>", options.ClientId);
|
||||
Assert.Equal("<secret>", options.ClientSecret);
|
||||
Assert.Equal("<display>", options.DisplayName);
|
||||
Assert.Equal(new TimeSpan(0, 0, 0, 30), options.RemoteAuthenticationTimeout);
|
||||
Assert.True(options.SaveTokens);
|
||||
Assert.Equal("<signIn>", options.SignInScheme);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
|
|||
{
|
||||
{"OpenIdConnect:ClientId", "<id>"},
|
||||
{"OpenIdConnect:ClientSecret", "<secret>"},
|
||||
{"OpenIdConnect:RequireHttpsMetadata", "false"},
|
||||
{"OpenIdConnect:Authority", "<auth>"}
|
||||
};
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
|
|
@ -48,6 +49,7 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect
|
|||
Assert.Equal("<id>", options.ClientId);
|
||||
Assert.Equal("<secret>", options.ClientSecret);
|
||||
Assert.Equal("<auth>", options.Authority);
|
||||
Assert.False(options.RequireHttpsMetadata);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
|||
{"Twitter:BackchannelTimeout", "0.0:0:30"},
|
||||
//{"Twitter:CallbackPath", "/callbackpath"}, // PathString doesn't convert
|
||||
{"Twitter:ClaimsIssuer", "<issuer>"},
|
||||
{"Twitter:DisplayName", "<display>"},
|
||||
{"Twitter:RemoteAuthenticationTimeout", "0.0:0:30"},
|
||||
{"Twitter:SaveTokens", "true"},
|
||||
{"Twitter:SendAppSecretProof", "true"},
|
||||
|
|
@ -60,7 +59,6 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
|||
Assert.Equal("<issuer>", options.ClaimsIssuer);
|
||||
Assert.Equal("<key>", options.ConsumerKey);
|
||||
Assert.Equal("<secret>", options.ConsumerSecret);
|
||||
Assert.Equal("<display>", options.DisplayName);
|
||||
Assert.Equal(new TimeSpan(0, 0, 0, 30), options.RemoteAuthenticationTimeout);
|
||||
Assert.True(options.SaveTokens);
|
||||
Assert.Equal("<signIn>", options.SignInScheme);
|
||||
|
|
|
|||
Loading…
Reference in New Issue