diff --git a/samples/CookieSample/Startup.cs b/samples/CookieSample/Startup.cs index 2e5602b9c4..fc78aec37d 100644 --- a/samples/CookieSample/Startup.cs +++ b/samples/CookieSample/Startup.cs @@ -9,9 +9,9 @@ namespace CookieSample { public void Configure(IApplicationBuilder app) { - app.UseCookieAuthentication(new CookieAuthenticationOptions() + app.UseServices(services => { }); + app.UseCookieAuthentication(options => { - }); app.Run(async context => diff --git a/samples/CookieSessionSample/Startup.cs b/samples/CookieSessionSample/Startup.cs index 890e63116f..a4217e6d2b 100644 --- a/samples/CookieSessionSample/Startup.cs +++ b/samples/CookieSessionSample/Startup.cs @@ -10,9 +10,10 @@ namespace CookieSessionSample { public void Configure(IApplicationBuilder app) { - app.UseCookieAuthentication(new CookieAuthenticationOptions() + app.UseServices(services => { }); + app.UseCookieAuthentication(options => { - SessionStore = new MemoryCacheSessionStore(), + options.SessionStore = new MemoryCacheSessionStore(); }); app.Run(async context => diff --git a/samples/SocialSample/SocialSample.kproj b/samples/SocialSample/SocialSample.kproj index 4447d1b1d7..982c0c8f5f 100644 --- a/samples/SocialSample/SocialSample.kproj +++ b/samples/SocialSample/SocialSample.kproj @@ -7,7 +7,7 @@ 8c73d216-332d-41d8-bfd0-45bc4bc36552 - Library + Web ConsoleDebugger @@ -21,6 +21,7 @@ 2.0 + 50113 \ No newline at end of file diff --git a/samples/SocialSample/Startup.cs b/samples/SocialSample/Startup.cs index 06309f541b..35480c1cc3 100644 --- a/samples/SocialSample/Startup.cs +++ b/samples/SocialSample/Startup.cs @@ -14,6 +14,7 @@ using Microsoft.AspNet.Security.MicrosoftAccount; using Microsoft.AspNet.Security.OAuth; using Microsoft.AspNet.Security.Twitter; using Newtonsoft.Json.Linq; +using Microsoft.Framework.DependencyInjection; namespace CookieSample { @@ -23,39 +24,48 @@ namespace CookieSample { app.UseErrorPage(); - app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType); - - app.UseCookieAuthentication(new CookieAuthenticationOptions() + app.UseServices(services => { - LoginPath = new PathString("/login"), + services.ConfigureOptions(options => + { + + options.SignInAsAuthenticationType = CookieAuthenticationDefaults.AuthenticationType; + }); }); - app.UseFacebookAuthentication(new FacebookAuthenticationOptions() + app.UseCookieAuthentication(options => + { + options.LoginPath = new PathString("/login"); + }); + + app.UseFacebookAuthentication(options => { - AppId = "569522623154478", - AppSecret = "a124463c4719c94b4228d9a240e5dc1a", + options.AppId = "569522623154478"; + options.AppSecret = "a124463c4719c94b4228d9a240e5dc1a"; }); - app.UseOAuthAuthentication(new OAuthAuthenticationOptions("Google-AccessToken") + app.UseOAuthAuthentication("Google-AccessToken", options => { - ClientId = "560027070069-37ldt4kfuohhu3m495hk2j4pjp92d382.apps.googleusercontent.com", - ClientSecret = "n2Q-GEw9RQjzcRbU3qhfTj8f", - CallbackPath = new PathString("/signin-google-token"), - AuthorizationEndpoint = GoogleAuthenticationDefaults.AuthorizationEndpoint, - TokenEndpoint = GoogleAuthenticationDefaults.TokenEndpoint, - Scope = { "openid", "profile", "email" }, + options.ClientId = "560027070069-37ldt4kfuohhu3m495hk2j4pjp92d382.apps.googleusercontent.com"; + options.ClientSecret = "n2Q-GEw9RQjzcRbU3qhfTj8f"; + options.CallbackPath = new PathString("/signin-google-token"); + options.AuthorizationEndpoint = GoogleAuthenticationDefaults.AuthorizationEndpoint; + options.TokenEndpoint = GoogleAuthenticationDefaults.TokenEndpoint; + options.Scope.Add("openid"); + options.Scope.Add("profile"); + options.Scope.Add("email"); }); - app.UseGoogleAuthentication(new GoogleAuthenticationOptions() + app.UseGoogleAuthentication(options => { - ClientId = "560027070069-37ldt4kfuohhu3m495hk2j4pjp92d382.apps.googleusercontent.com", - ClientSecret = "n2Q-GEw9RQjzcRbU3qhfTj8f", + options.ClientId = "560027070069-37ldt4kfuohhu3m495hk2j4pjp92d382.apps.googleusercontent.com"; + options.ClientSecret = "n2Q-GEw9RQjzcRbU3qhfTj8f"; }); - app.UseTwitterAuthentication(new TwitterAuthenticationOptions() + app.UseTwitterAuthentication(options => { - ConsumerKey = "6XaCTaLbMqfj6ww3zvZ5g", - ConsumerSecret = "Il2eFzGIrYhz6BWjYhVXBPQSfZuS4xoHpSSyD9PI", + options.ConsumerKey = "6XaCTaLbMqfj6ww3zvZ5g"; + options.ConsumerSecret = "Il2eFzGIrYhz6BWjYhVXBPQSfZuS4xoHpSSyD9PI"; }); /* @@ -75,43 +85,43 @@ namespace CookieSample The sample app can then be run via: k web */ - app.UseOAuthAuthentication(new OAuthAuthenticationOptions("Microsoft-AccessToken") + app.UseOAuthAuthentication("Microsoft-AccessToken", options => { - Caption = "MicrosoftAccount-AccessToken - Requires project changes", - ClientId = "00000000480FF62E", - ClientSecret = "bLw2JIvf8Y1TaToipPEqxTVlOeJwCUsr", - CallbackPath = new PathString("/signin-microsoft-token"), - AuthorizationEndpoint = MicrosoftAccountAuthenticationDefaults.AuthorizationEndpoint, - TokenEndpoint = MicrosoftAccountAuthenticationDefaults.TokenEndpoint, - Scope = { "wl.basic" }, + options.Caption = "MicrosoftAccount-AccessToken - Requires project changes"; + options.ClientId = "00000000480FF62E"; + options.ClientSecret = "bLw2JIvf8Y1TaToipPEqxTVlOeJwCUsr"; + options.CallbackPath = new PathString("/signin-microsoft-token"); + options.AuthorizationEndpoint = MicrosoftAccountAuthenticationDefaults.AuthorizationEndpoint; + options.TokenEndpoint = MicrosoftAccountAuthenticationDefaults.TokenEndpoint; + options.Scope.Add("wl.basic"); }); - app.UseMicrosoftAccountAuthentication(new MicrosoftAccountAuthenticationOptions() + app.UseMicrosoftAccountAuthentication(options => { - Caption = "MicrosoftAccount - Requires project changes", - ClientId = "00000000480FF62E", - ClientSecret = "bLw2JIvf8Y1TaToipPEqxTVlOeJwCUsr", + options.Caption = "MicrosoftAccount - Requires project changes"; + options.ClientId = "00000000480FF62E"; + options.ClientSecret = "bLw2JIvf8Y1TaToipPEqxTVlOeJwCUsr"; }); - app.UseOAuthAuthentication(new OAuthAuthenticationOptions("GitHub-AccessToken") + app.UseOAuthAuthentication("GitHub-AccessToken", options => { - ClientId = "8c0c5a572abe8fe89588", - ClientSecret = "e1d95eaf03461d27acd6f49d4fc7bf19d6ac8cda", - CallbackPath = new PathString("/signin-github-token"), - AuthorizationEndpoint = "https://github.com/login/oauth/authorize", - TokenEndpoint = "https://github.com/login/oauth/access_token", + options.ClientId = "8c0c5a572abe8fe89588"; + options.ClientSecret = "e1d95eaf03461d27acd6f49d4fc7bf19d6ac8cda"; + options.CallbackPath = new PathString("/signin-github-token"); + options.AuthorizationEndpoint = "https://github.com/login/oauth/authorize"; + options.TokenEndpoint = "https://github.com/login/oauth/access_token"; }); - app.UseOAuthAuthentication(new OAuthAuthenticationOptions("GitHub") + app.UseOAuthAuthentication("GitHub", options => { - ClientId = "49e302895d8b09ea5656", - ClientSecret = "98f1bf028608901e9df91d64ee61536fe562064b", - CallbackPath = new PathString("/signin-github"), - AuthorizationEndpoint = "https://github.com/login/oauth/authorize", - TokenEndpoint = "https://github.com/login/oauth/access_token", - UserInformationEndpoint = "https://api.github.com/user", + options.ClientId = "49e302895d8b09ea5656"; + options.ClientSecret = "98f1bf028608901e9df91d64ee61536fe562064b"; + options.CallbackPath = new PathString("/signin-github"); + options.AuthorizationEndpoint = "https://github.com/login/oauth/authorize"; + options.TokenEndpoint = "https://github.com/login/oauth/access_token"; + options.UserInformationEndpoint = "https://api.github.com/user"; // Retrieving user information is unique to each provider. - Notifications = new OAuthAuthenticationNotifications() + options.Notifications = new OAuthAuthenticationNotifications() { OnGetUserInformationAsync = async (context) => { @@ -153,7 +163,7 @@ namespace CookieSample context.Identity = identity; }, - }, + }; }); // Choose an authentication type diff --git a/samples/SocialSample/project.json b/samples/SocialSample/project.json index b1942aa64d..84bb6d1c95 100644 --- a/samples/SocialSample/project.json +++ b/samples/SocialSample/project.json @@ -8,7 +8,8 @@ "Microsoft.AspNet.Security.MicrosoftAccount": "1.0.0-*", "Microsoft.AspNet.Security.Twitter": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*", - "Microsoft.Framework.DependencyInjection": "1.0.0-*" + "Microsoft.Framework.DependencyInjection": "1.0.0-*", + "Microsoft.Framework.OptionsModel": "1.0.0-*" }, "commands": { "web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:12345" }, "frameworks": { diff --git a/src/Microsoft.AspNet.Security.Cookies/CookieAuthenticationExtensions.cs b/src/Microsoft.AspNet.Security.Cookies/CookieAuthenticationExtensions.cs index 03af44a43d..98d39cca71 100644 --- a/src/Microsoft.AspNet.Security.Cookies/CookieAuthenticationExtensions.cs +++ b/src/Microsoft.AspNet.Security.Cookies/CookieAuthenticationExtensions.cs @@ -2,6 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNet.Security.Cookies; +using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.OptionsModel; +using System; namespace Microsoft.AspNet.Builder { @@ -10,15 +13,25 @@ namespace Microsoft.AspNet.Builder /// public static class CookieAuthenticationExtensions { + public static IServiceCollection ConfigureCookieAuthentication([NotNull] this IServiceCollection services, [NotNull] Action configure) + { + return services.ConfigureOptions(configure); + } + /// /// Adds a cookie-based authentication middleware to your web application pipeline. /// /// The IApplicationBuilder passed to your configuration method - /// An options class that controls the middleware behavior + /// Used to configure the options for the middleware + /// The name of the options class that controls the middleware behavior, null will use the default options /// The original app parameter - public static IApplicationBuilder UseCookieAuthentication([NotNull] this IApplicationBuilder app, [NotNull] CookieAuthenticationOptions options) + public static IApplicationBuilder UseCookieAuthentication([NotNull] this IApplicationBuilder app, Action configureOptions = null, string optionsName = "") { - return app.UseMiddleware(options); + return app.UseMiddleware( + new OptionsAction(configureOptions ?? (o => { })) + { + Name = optionsName + }); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Security.Cookies/CookieAuthenticationMiddleware.cs b/src/Microsoft.AspNet.Security.Cookies/CookieAuthenticationMiddleware.cs index 92ab1b1225..fff6906658 100644 --- a/src/Microsoft.AspNet.Security.Cookies/CookieAuthenticationMiddleware.cs +++ b/src/Microsoft.AspNet.Security.Cookies/CookieAuthenticationMiddleware.cs @@ -9,6 +9,7 @@ using Microsoft.AspNet.Security.DataHandler; using Microsoft.AspNet.Security.DataProtection; using Microsoft.AspNet.Security.Infrastructure; using Microsoft.Framework.Logging; +using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Security.Cookies { @@ -16,8 +17,12 @@ namespace Microsoft.AspNet.Security.Cookies { private readonly ILogger _logger; - public CookieAuthenticationMiddleware(RequestDelegate next, IDataProtectionProvider dataProtectionProvider, ILoggerFactory loggerFactory, CookieAuthenticationOptions options) - : base(next, options) + public CookieAuthenticationMiddleware(RequestDelegate next, + IDataProtectionProvider dataProtectionProvider, + ILoggerFactory loggerFactory, + IOptionsAccessor options, + IOptionsAction configureOptions) + : base(next, options, configureOptions) { if (Options.Notifications == null) { @@ -27,11 +32,11 @@ namespace Microsoft.AspNet.Security.Cookies { Options.CookieName = CookieAuthenticationDefaults.CookiePrefix + Options.AuthenticationType; } - if (options.TicketDataFormat == null) + if (Options.TicketDataFormat == null) { IDataProtector dataProtector = DataProtectionHelpers.CreateDataProtector(dataProtectionProvider, - typeof(CookieAuthenticationMiddleware).FullName, options.AuthenticationType, "v1"); - options.TicketDataFormat = new TicketDataFormat(dataProtector); + typeof(CookieAuthenticationMiddleware).FullName, Options.AuthenticationType, "v1"); + Options.TicketDataFormat = new TicketDataFormat(dataProtector); } if (Options.CookieManager == null) { diff --git a/src/Microsoft.AspNet.Security.Cookies/CookieAuthenticationOptions.cs b/src/Microsoft.AspNet.Security.Cookies/CookieAuthenticationOptions.cs index c6373a0ec9..121ff409b2 100644 --- a/src/Microsoft.AspNet.Security.Cookies/CookieAuthenticationOptions.cs +++ b/src/Microsoft.AspNet.Security.Cookies/CookieAuthenticationOptions.cs @@ -21,8 +21,8 @@ namespace Microsoft.AspNet.Security.Cookies /// Create an instance of the options initialized with the default values /// public CookieAuthenticationOptions() - : base(CookieAuthenticationDefaults.AuthenticationType) { + AuthenticationType = CookieAuthenticationDefaults.AuthenticationType; ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter; CookiePath = "/"; ExpireTimeSpan = TimeSpan.FromDays(14); diff --git a/src/Microsoft.AspNet.Security.Facebook/FacebookAuthenticationExtensions.cs b/src/Microsoft.AspNet.Security.Facebook/FacebookAuthenticationExtensions.cs index 5438272090..aa59e2efee 100644 --- a/src/Microsoft.AspNet.Security.Facebook/FacebookAuthenticationExtensions.cs +++ b/src/Microsoft.AspNet.Security.Facebook/FacebookAuthenticationExtensions.cs @@ -2,6 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNet.Security.Facebook; +using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.OptionsModel; +using System; namespace Microsoft.AspNet.Builder { @@ -10,35 +13,23 @@ namespace Microsoft.AspNet.Builder /// public static class FacebookAuthenticationExtensions { - /// - /// Authenticate users using Facebook. - /// - /// The passed to the configure method. - /// The appId assigned by Facebook. - /// The appSecret assigned by Facebook. - /// The updated . - public static IApplicationBuilder UseFacebookAuthentication([NotNull] this IApplicationBuilder app, [NotNull] string appId, [NotNull] string appSecret) + public static IServiceCollection ConfigureFacebookAuthentication([NotNull] this IServiceCollection services, [NotNull] Action configure) { - return app.UseFacebookAuthentication(new FacebookAuthenticationOptions() - { - AppId = appId, - AppSecret = appSecret, - }); + return services.ConfigureOptions(configure); } /// /// Authenticate users using Facebook. /// /// The passed to the configure method. - /// The middleware configuration options. /// The updated . - public static IApplicationBuilder UseFacebookAuthentication([NotNull] this IApplicationBuilder app, [NotNull] FacebookAuthenticationOptions options) + public static IApplicationBuilder UseFacebookAuthentication([NotNull] this IApplicationBuilder app, Action configureOptions = null, string optionsName = "") { - if (string.IsNullOrEmpty(options.SignInAsAuthenticationType)) - { - options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(); - } - return app.UseMiddleware(options); + return app.UseMiddleware( + new OptionsAction(configureOptions ?? (o => { })) + { + Name = optionsName + }); } } } diff --git a/src/Microsoft.AspNet.Security.Facebook/FacebookAuthenticationMiddleware.cs b/src/Microsoft.AspNet.Security.Facebook/FacebookAuthenticationMiddleware.cs index 2d653d7c28..a453e085a0 100644 --- a/src/Microsoft.AspNet.Security.Facebook/FacebookAuthenticationMiddleware.cs +++ b/src/Microsoft.AspNet.Security.Facebook/FacebookAuthenticationMiddleware.cs @@ -8,6 +8,7 @@ using Microsoft.AspNet.Security.DataProtection; using Microsoft.AspNet.Security.Infrastructure; using Microsoft.AspNet.Security.OAuth; using Microsoft.Framework.Logging; +using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Security.Facebook { @@ -27,8 +28,10 @@ namespace Microsoft.AspNet.Security.Facebook RequestDelegate next, IDataProtectionProvider dataProtectionProvider, ILoggerFactory loggerFactory, - FacebookAuthenticationOptions options) - : base(next, dataProtectionProvider, loggerFactory, options) + IOptionsAccessor externalOptions, + IOptionsAccessor options, + IOptionsAction configureOptions = null) + : base(next, dataProtectionProvider, loggerFactory, externalOptions, options, configureOptions) { if (string.IsNullOrWhiteSpace(Options.AppId)) { diff --git a/src/Microsoft.AspNet.Security.Facebook/FacebookAuthenticationOptions.cs b/src/Microsoft.AspNet.Security.Facebook/FacebookAuthenticationOptions.cs index 7f1199a086..1720571843 100644 --- a/src/Microsoft.AspNet.Security.Facebook/FacebookAuthenticationOptions.cs +++ b/src/Microsoft.AspNet.Security.Facebook/FacebookAuthenticationOptions.cs @@ -15,8 +15,9 @@ namespace Microsoft.AspNet.Security.Facebook /// Initializes a new . /// public FacebookAuthenticationOptions() - : base(FacebookAuthenticationDefaults.AuthenticationType) { + AuthenticationType = FacebookAuthenticationDefaults.AuthenticationType; + Caption = AuthenticationType; CallbackPath = new PathString("/signin-facebook"); SendAppSecretProof = true; AuthorizationEndpoint = FacebookAuthenticationDefaults.AuthorizationEndpoint; diff --git a/src/Microsoft.AspNet.Security.Facebook/project.json b/src/Microsoft.AspNet.Security.Facebook/project.json index 6ad815156a..06da113a74 100644 --- a/src/Microsoft.AspNet.Security.Facebook/project.json +++ b/src/Microsoft.AspNet.Security.Facebook/project.json @@ -7,6 +7,7 @@ "Microsoft.AspNet.Security.OAuth": "1.0.0-*", "Microsoft.AspNet.WebUtilities": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", + "Microsoft.Framework.OptionsModel": "1.0.0-*", "Newtonsoft.Json": "6.0.4" }, "frameworks": { diff --git a/src/Microsoft.AspNet.Security.Google/GoogleAuthenticationExtensions.cs b/src/Microsoft.AspNet.Security.Google/GoogleAuthenticationExtensions.cs index 571ff5ffe3..7bb4a24e25 100644 --- a/src/Microsoft.AspNet.Security.Google/GoogleAuthenticationExtensions.cs +++ b/src/Microsoft.AspNet.Security.Google/GoogleAuthenticationExtensions.cs @@ -2,6 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNet.Security.Google; +using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.OptionsModel; +using System; namespace Microsoft.AspNet.Builder { @@ -10,36 +13,25 @@ namespace Microsoft.AspNet.Builder /// public static class GoogleAuthenticationExtensions { - /// - /// Authenticate users using Google OAuth 2.0. - /// - /// The passed to the configure method. - /// The google assigned client id. - /// The google assigned client secret. - /// The updated . - public static IApplicationBuilder UseGoogleAuthentication([NotNull] this IApplicationBuilder app, [NotNull] string clientId, [NotNull] string clientSecret) + public static IServiceCollection ConfigureGoogleAuthentication([NotNull] this IServiceCollection services, [NotNull] Action configure) { - return app.UseGoogleAuthentication( - new GoogleAuthenticationOptions - { - ClientId = clientId, - ClientSecret = clientSecret - }); + return services.ConfigureOptions(configure); } /// /// Authenticate users using Google OAuth 2.0. /// /// The passed to the configure method. - /// Middleware configuration options. + /// Used to configure Middleware options. + /// Name of the options instance to be used /// The updated . - public static IApplicationBuilder UseGoogleAuthentication([NotNull] this IApplicationBuilder app, [NotNull] GoogleAuthenticationOptions options) + public static IApplicationBuilder UseGoogleAuthentication([NotNull] this IApplicationBuilder app, Action configureOptions = null, string optionsName = "") { - if (string.IsNullOrEmpty(options.SignInAsAuthenticationType)) - { - options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(); - } - return app.UseMiddleware(options); + return app.UseMiddleware( + new OptionsAction(configureOptions ?? (o => { })) + { + Name = optionsName + }); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Security.Google/GoogleAuthenticationMiddleware.cs b/src/Microsoft.AspNet.Security.Google/GoogleAuthenticationMiddleware.cs index 08d7610fa0..66cef2e2a0 100644 --- a/src/Microsoft.AspNet.Security.Google/GoogleAuthenticationMiddleware.cs +++ b/src/Microsoft.AspNet.Security.Google/GoogleAuthenticationMiddleware.cs @@ -11,6 +11,7 @@ using Microsoft.AspNet.Security.DataProtection; using Microsoft.AspNet.Security.Infrastructure; using Microsoft.AspNet.Security.OAuth; using Microsoft.Framework.Logging; +using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Security.Google { @@ -31,8 +32,10 @@ namespace Microsoft.AspNet.Security.Google RequestDelegate next, IDataProtectionProvider dataProtectionProvider, ILoggerFactory loggerFactory, - GoogleAuthenticationOptions options) - : base(next, dataProtectionProvider, loggerFactory, options) + IOptionsAccessor externalOptions, + IOptionsAccessor options, + IOptionsAction configureOptions = null) + : base(next, dataProtectionProvider, loggerFactory, externalOptions, options, configureOptions) { if (Options.Notifications == null) { diff --git a/src/Microsoft.AspNet.Security.Google/GoogleAuthenticationOptions.cs b/src/Microsoft.AspNet.Security.Google/GoogleAuthenticationOptions.cs index 0b8e3ab091..4cfb97bbb2 100644 --- a/src/Microsoft.AspNet.Security.Google/GoogleAuthenticationOptions.cs +++ b/src/Microsoft.AspNet.Security.Google/GoogleAuthenticationOptions.cs @@ -19,8 +19,9 @@ namespace Microsoft.AspNet.Security.Google /// Initializes a new . /// public GoogleAuthenticationOptions() - : base(GoogleAuthenticationDefaults.AuthenticationType) { + AuthenticationType = GoogleAuthenticationDefaults.AuthenticationType; + Caption = AuthenticationType; CallbackPath = new PathString("/signin-google"); AuthorizationEndpoint = GoogleAuthenticationDefaults.AuthorizationEndpoint; TokenEndpoint = GoogleAuthenticationDefaults.TokenEndpoint; diff --git a/src/Microsoft.AspNet.Security.Google/project.json b/src/Microsoft.AspNet.Security.Google/project.json index 6ad815156a..0cc8fa1188 100644 --- a/src/Microsoft.AspNet.Security.Google/project.json +++ b/src/Microsoft.AspNet.Security.Google/project.json @@ -7,7 +7,8 @@ "Microsoft.AspNet.Security.OAuth": "1.0.0-*", "Microsoft.AspNet.WebUtilities": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", - "Newtonsoft.Json": "6.0.4" + "Microsoft.Framework.OptionsModel": "1.0.0-*", + "Newtonsoft.Json": "6.0.4", }, "frameworks": { "aspnet50": { diff --git a/src/Microsoft.AspNet.Security.MicrosoftAccount/MicrosoftAccountAuthenticationExtensions.cs b/src/Microsoft.AspNet.Security.MicrosoftAccount/MicrosoftAccountAuthenticationExtensions.cs index 9963abf1d6..64ec369ab5 100644 --- a/src/Microsoft.AspNet.Security.MicrosoftAccount/MicrosoftAccountAuthenticationExtensions.cs +++ b/src/Microsoft.AspNet.Security.MicrosoftAccount/MicrosoftAccountAuthenticationExtensions.cs @@ -2,6 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNet.Security.MicrosoftAccount; +using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.OptionsModel; +using System; namespace Microsoft.AspNet.Builder { @@ -10,36 +13,18 @@ namespace Microsoft.AspNet.Builder /// public static class MicrosoftAccountAuthenticationExtensions { - /// - /// Authenticate users using Microsoft Account. - /// - /// The passed to the configure method. - /// The application client ID assigned by the Microsoft authentication service. - /// The application client secret assigned by the Microsoft authentication service. - /// The updated . - public static IApplicationBuilder UseMicrosoftAccountAuthentication([NotNull] this IApplicationBuilder app, [NotNull] string clientId, [NotNull] string clientSecret) + public static IServiceCollection ConfigureMicrosoftAccountAuthentication([NotNull] this IServiceCollection services, [NotNull] Action configure) { - return app.UseMicrosoftAccountAuthentication( - new MicrosoftAccountAuthenticationOptions - { - ClientId = clientId, - ClientSecret = clientSecret, - }); + return services.ConfigureOptions(configure); } - /// - /// Authenticate users using Microsoft Account. - /// - /// The passed to the configure method. - /// The middleware configuration options. - /// The updated . - public static IApplicationBuilder UseMicrosoftAccountAuthentication([NotNull] this IApplicationBuilder app, [NotNull] MicrosoftAccountAuthenticationOptions options) + public static IApplicationBuilder UseMicrosoftAccountAuthentication([NotNull] this IApplicationBuilder app, Action configureOptions = null, string optionsName = "") { - if (string.IsNullOrEmpty(options.SignInAsAuthenticationType)) - { - options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(); - } - return app.UseMiddleware(options); + return app.UseMiddleware( + new OptionsAction(configureOptions ?? (o => { })) + { + Name = optionsName + }); } } } diff --git a/src/Microsoft.AspNet.Security.MicrosoftAccount/MicrosoftAccountAuthenticationMiddleware.cs b/src/Microsoft.AspNet.Security.MicrosoftAccount/MicrosoftAccountAuthenticationMiddleware.cs index 29ad5c5efb..c36ad16de2 100644 --- a/src/Microsoft.AspNet.Security.MicrosoftAccount/MicrosoftAccountAuthenticationMiddleware.cs +++ b/src/Microsoft.AspNet.Security.MicrosoftAccount/MicrosoftAccountAuthenticationMiddleware.cs @@ -8,6 +8,7 @@ using Microsoft.AspNet.Security.DataProtection; using Microsoft.AspNet.Security.Infrastructure; using Microsoft.AspNet.Security.OAuth; using Microsoft.Framework.Logging; +using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Security.MicrosoftAccount { @@ -27,8 +28,10 @@ namespace Microsoft.AspNet.Security.MicrosoftAccount RequestDelegate next, IDataProtectionProvider dataProtectionProvider, ILoggerFactory loggerFactory, - MicrosoftAccountAuthenticationOptions options) - : base(next, dataProtectionProvider, loggerFactory, options) + IOptionsAccessor externalOptions, + IOptionsAccessor options, + IOptionsAction configureOptions = null) + : base(next, dataProtectionProvider, loggerFactory, externalOptions, options, configureOptions) { if (Options.Notifications == null) { diff --git a/src/Microsoft.AspNet.Security.MicrosoftAccount/MicrosoftAccountAuthenticationOptions.cs b/src/Microsoft.AspNet.Security.MicrosoftAccount/MicrosoftAccountAuthenticationOptions.cs index 24d2599cb2..8755de63ba 100644 --- a/src/Microsoft.AspNet.Security.MicrosoftAccount/MicrosoftAccountAuthenticationOptions.cs +++ b/src/Microsoft.AspNet.Security.MicrosoftAccount/MicrosoftAccountAuthenticationOptions.cs @@ -15,8 +15,9 @@ namespace Microsoft.AspNet.Security.MicrosoftAccount /// Initializes a new . /// public MicrosoftAccountAuthenticationOptions() - : base(MicrosoftAccountAuthenticationDefaults.AuthenticationType) { + AuthenticationType = MicrosoftAccountAuthenticationDefaults.AuthenticationType; + Caption = AuthenticationType; CallbackPath = new PathString("/signin-microsoft"); AuthorizationEndpoint = MicrosoftAccountAuthenticationDefaults.AuthorizationEndpoint; TokenEndpoint = MicrosoftAccountAuthenticationDefaults.TokenEndpoint; diff --git a/src/Microsoft.AspNet.Security.MicrosoftAccount/project.json b/src/Microsoft.AspNet.Security.MicrosoftAccount/project.json index c0c9fa2067..08fee1520f 100644 --- a/src/Microsoft.AspNet.Security.MicrosoftAccount/project.json +++ b/src/Microsoft.AspNet.Security.MicrosoftAccount/project.json @@ -7,6 +7,7 @@ "Microsoft.AspNet.Security.OAuth": "1.0.0-*", "Microsoft.AspNet.WebUtilities": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", + "Microsoft.Framework.OptionsModel": "1.0.0-*", "Newtonsoft.Json": "6.0.4" }, "frameworks": { diff --git a/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationExtensions.cs b/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationExtensions.cs index 0b6f0ddec6..bdbc3c9ee5 100644 --- a/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationExtensions.cs +++ b/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationExtensions.cs @@ -4,6 +4,8 @@ using System; using System.Globalization; using Microsoft.AspNet.Security.OAuth; +using Microsoft.AspNet.Security.Infrastructure; +using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Builder { @@ -18,17 +20,21 @@ namespace Microsoft.AspNet.Builder /// The passed to the configure method. /// The middleware configuration options. /// The updated . - public static IApplicationBuilder UseOAuthAuthentication([NotNull] this IApplicationBuilder app, [NotNull] OAuthAuthenticationOptions options) + public static IApplicationBuilder UseOAuthAuthentication([NotNull] this IApplicationBuilder app, [NotNull] string authenticationType, Action> configureOptions = null) { - if (string.IsNullOrEmpty(options.SignInAsAuthenticationType)) - { - options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(); - } - if (options.Notifications == null) - { - options.Notifications = new OAuthAuthenticationNotifications(); - } - return app.UseMiddleware, IOAuthAuthenticationNotifications>>(options); + return app.UseMiddleware, IOAuthAuthenticationNotifications>>( + new OptionsAction>(options => + { + options.AuthenticationType = authenticationType; + options.Caption = authenticationType; + if (configureOptions != null) + { + configureOptions(options); + } + }) + { + Name = authenticationType, + }); } } } diff --git a/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationMiddleware.cs b/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationMiddleware.cs index 009b025488..e3d65c55bd 100644 --- a/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationMiddleware.cs +++ b/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationMiddleware.cs @@ -10,6 +10,7 @@ using Microsoft.AspNet.Security.DataHandler; using Microsoft.AspNet.Security.DataProtection; using Microsoft.AspNet.Security.Infrastructure; using Microsoft.Framework.Logging; +using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Security.OAuth { @@ -18,7 +19,7 @@ namespace Microsoft.AspNet.Security.OAuth /// [SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", Justification = "Middleware are not disposable.")] public class OAuthAuthenticationMiddleware : AuthenticationMiddleware - where TOptions : OAuthAuthenticationOptions + where TOptions : OAuthAuthenticationOptions, new() where TNotifications : IOAuthAuthenticationNotifications { /// @@ -32,9 +33,16 @@ namespace Microsoft.AspNet.Security.OAuth RequestDelegate next, IDataProtectionProvider dataProtectionProvider, ILoggerFactory loggerFactory, - TOptions options) - : base(next, options) + IOptionsAccessor externalOptions, + IOptionsAccessor options, + IOptionsAction configureOptions = null) + : base(next, options, configureOptions) { + // todo: review error handling + if (string.IsNullOrWhiteSpace(Options.AuthenticationType)) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, "AuthenticationType")); + } if (string.IsNullOrWhiteSpace(Options.ClientId)) { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, "ClientId")); @@ -57,7 +65,7 @@ namespace Microsoft.AspNet.Security.OAuth if (Options.StateDataFormat == null) { IDataProtector dataProtector = DataProtectionHelpers.CreateDataProtector(dataProtectionProvider, - this.GetType().FullName, options.AuthenticationType, "v1"); + this.GetType().FullName, Options.AuthenticationType, "v1"); Options.StateDataFormat = new PropertiesDataFormat(dataProtector); } @@ -65,6 +73,15 @@ namespace Microsoft.AspNet.Security.OAuth Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft ASP.NET OAuth middleware"); Backchannel.Timeout = Options.BackchannelTimeout; Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB + + if (string.IsNullOrEmpty(Options.SignInAsAuthenticationType)) + { + Options.SignInAsAuthenticationType = externalOptions.Options.SignInAsAuthenticationType; + } + if (string.IsNullOrEmpty(Options.SignInAsAuthenticationType)) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, "SignInAsAuthenticationType")); + } } protected HttpClient Backchannel { get; private set; } diff --git a/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationOptions.cs b/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationOptions.cs index 69e8897448..cee784185d 100644 --- a/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationOptions.cs +++ b/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationOptions.cs @@ -18,10 +18,8 @@ namespace Microsoft.AspNet.Security.OAuth /// /// Initializes a new . /// - public OAuthAuthenticationOptions([NotNull] string authenticationType) - : base(authenticationType) + public OAuthAuthenticationOptions() { - Caption = authenticationType; AuthenticationMode = AuthenticationMode.Passive; Scope = new List(); BackchannelTimeout = TimeSpan.FromSeconds(60); @@ -69,9 +67,6 @@ namespace Microsoft.AspNet.Security.OAuth /// /// Get or sets the text that the user can display on a sign in user interface. /// - /// - /// The default value is the authentication type. - /// public string Caption { get { return Description.Caption; } diff --git a/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationOptions`1.cs b/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationOptions`1.cs index 65f01b5b82..2eb1bfb89a 100644 --- a/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationOptions`1.cs +++ b/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationOptions`1.cs @@ -8,14 +8,6 @@ namespace Microsoft.AspNet.Security.OAuth /// public class OAuthAuthenticationOptions : OAuthAuthenticationOptions where TNotifications : IOAuthAuthenticationNotifications { - /// - /// Initializes a new . - /// - public OAuthAuthenticationOptions([NotNull] string authenticationType) - : base(authenticationType) - { - } - /// /// Gets or sets the used to handle authentication events. /// diff --git a/src/Microsoft.AspNet.Security.Twitter/TwitterAuthenticationExtensions.cs b/src/Microsoft.AspNet.Security.Twitter/TwitterAuthenticationExtensions.cs index aa56249cca..9f2c54ce1f 100644 --- a/src/Microsoft.AspNet.Security.Twitter/TwitterAuthenticationExtensions.cs +++ b/src/Microsoft.AspNet.Security.Twitter/TwitterAuthenticationExtensions.cs @@ -1,7 +1,11 @@ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using Microsoft.AspNet.Security.Infrastructure; using Microsoft.AspNet.Security.Twitter; +using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.OptionsModel; +using System; namespace Microsoft.AspNet.Builder { @@ -10,36 +14,18 @@ namespace Microsoft.AspNet.Builder /// public static class TwitterAuthenticationExtensions { - /// - /// Authenticate users using Twitter - /// - /// The passed to the configure method - /// The Twitter-issued consumer key - /// The Twitter-issued consumer secret - /// The updated - public static IApplicationBuilder UseTwitterAuthentication([NotNull] this IApplicationBuilder app, [NotNull] string consumerKey, [NotNull] string consumerSecret) + public static IServiceCollection ConfigureTwitterAuthentication([NotNull] this IServiceCollection services, [NotNull] Action configure) { - return app.UseTwitterAuthentication( - new TwitterAuthenticationOptions - { - ConsumerKey = consumerKey, - ConsumerSecret = consumerSecret, - }); + return services.ConfigureOptions(configure); } - /// - /// Authenticate users using Twitter - /// - /// The passed to the configure method - /// Middleware configuration options - /// The updated - public static IApplicationBuilder UseTwitterAuthentication([NotNull] this IApplicationBuilder app, [NotNull] TwitterAuthenticationOptions options) + public static IApplicationBuilder UseTwitterAuthentication([NotNull] this IApplicationBuilder app, Action configureOptions = null, string optionsName = "") { - if (string.IsNullOrEmpty(options.SignInAsAuthenticationType)) - { - options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(); - } - return app.UseMiddleware(options); + return app.UseMiddleware( + new OptionsAction(configureOptions ?? (o => { })) + { + Name = optionsName + }); } } } diff --git a/src/Microsoft.AspNet.Security.Twitter/TwitterAuthenticationMiddleware.cs b/src/Microsoft.AspNet.Security.Twitter/TwitterAuthenticationMiddleware.cs index 5961762191..ffa9b9bb69 100644 --- a/src/Microsoft.AspNet.Security.Twitter/TwitterAuthenticationMiddleware.cs +++ b/src/Microsoft.AspNet.Security.Twitter/TwitterAuthenticationMiddleware.cs @@ -12,6 +12,7 @@ using Microsoft.AspNet.Security.DataProtection; using Microsoft.AspNet.Security.Infrastructure; using Microsoft.AspNet.Security.Twitter.Messages; using Microsoft.Framework.Logging; +using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Security.Twitter { @@ -35,8 +36,10 @@ namespace Microsoft.AspNet.Security.Twitter RequestDelegate next, IDataProtectionProvider dataProtectionProvider, ILoggerFactory loggerFactory, - TwitterAuthenticationOptions options) - : base(next, options) + IOptionsAccessor externalOptions, + IOptionsAccessor options, + IOptionsAction configureOptions = null) + : base(next, options, configureOptions) { if (string.IsNullOrWhiteSpace(Options.ConsumerSecret)) { @@ -56,13 +59,22 @@ namespace Microsoft.AspNet.Security.Twitter if (Options.StateDataFormat == null) { IDataProtector dataProtector = DataProtectionHelpers.CreateDataProtector(dataProtectionProvider, - typeof(TwitterAuthenticationMiddleware).FullName, options.AuthenticationType, "v1"); + typeof(TwitterAuthenticationMiddleware).FullName, Options.AuthenticationType, "v1"); Options.StateDataFormat = new SecureDataFormat( Serializers.RequestToken, dataProtector, TextEncodings.Base64Url); } + if (string.IsNullOrEmpty(Options.SignInAsAuthenticationType)) + { + Options.SignInAsAuthenticationType = externalOptions.Options.SignInAsAuthenticationType; + } + if (string.IsNullOrEmpty(Options.SignInAsAuthenticationType)) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, "SignInAsAuthenticationType")); + } + _httpClient = new HttpClient(ResolveHttpMessageHandler(Options)); _httpClient.Timeout = Options.BackchannelTimeout; _httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB diff --git a/src/Microsoft.AspNet.Security.Twitter/TwitterAuthenticationOptions.cs b/src/Microsoft.AspNet.Security.Twitter/TwitterAuthenticationOptions.cs index 043911e759..91207863d5 100644 --- a/src/Microsoft.AspNet.Security.Twitter/TwitterAuthenticationOptions.cs +++ b/src/Microsoft.AspNet.Security.Twitter/TwitterAuthenticationOptions.cs @@ -17,9 +17,9 @@ namespace Microsoft.AspNet.Security.Twitter /// Initializes a new instance of the class. /// public TwitterAuthenticationOptions() - : base(TwitterAuthenticationDefaults.AuthenticationType) { - Caption = TwitterAuthenticationDefaults.AuthenticationType; + AuthenticationType = TwitterAuthenticationDefaults.AuthenticationType; + Caption = AuthenticationType; CallbackPath = new PathString("/signin-twitter"); AuthenticationMode = AuthenticationMode.Passive; BackchannelTimeout = TimeSpan.FromSeconds(60); diff --git a/src/Microsoft.AspNet.Security.Twitter/project.json b/src/Microsoft.AspNet.Security.Twitter/project.json index 5f1c34c942..f5e8ef324d 100644 --- a/src/Microsoft.AspNet.Security.Twitter/project.json +++ b/src/Microsoft.AspNet.Security.Twitter/project.json @@ -6,6 +6,7 @@ "Microsoft.AspNet.Security.DataProtection": "1.0.0-*", "Microsoft.AspNet.WebUtilities": "1.0.0-*", "Microsoft.Framework.Logging": "1.0.0-*", + "Microsoft.Framework.OptionsModel": "1.0.0-*", "Newtonsoft.Json": "6.0.4" }, "frameworks": { diff --git a/src/Microsoft.AspNet.Security/AuthenticationOptions.cs b/src/Microsoft.AspNet.Security/AuthenticationOptions.cs index 77e8fa03a4..e25383cfe3 100644 --- a/src/Microsoft.AspNet.Security/AuthenticationOptions.cs +++ b/src/Microsoft.AspNet.Security/AuthenticationOptions.cs @@ -17,17 +17,6 @@ namespace Microsoft.AspNet.Security { private string _authenticationType; - /// - /// Initialize properties of AuthenticationOptions base class - /// - /// Assigned to the AuthenticationType property - protected AuthenticationOptions(string authenticationType) - { - Description = new AuthenticationDescription(); - AuthenticationType = authenticationType; - AuthenticationMode = AuthenticationMode.Active; - } - /// /// The AuthenticationType in the options corresponds to the IIdentity AuthenticationType property. A different /// value may be assigned in order to use the same authentication middleware type more than once in a pipeline. @@ -47,11 +36,11 @@ namespace Microsoft.AspNet.Security /// alter 401 Unauthorized responses going out. If Passive the authentication middleware will only provide /// identity and alter responses when explicitly indicated by the AuthenticationType. /// - public AuthenticationMode AuthenticationMode { get; set; } + public AuthenticationMode AuthenticationMode { get; set; } = AuthenticationMode.Active; /// /// Additional information about the authentication type which is made available to the application. /// - public AuthenticationDescription Description { get; set; } + public AuthenticationDescription Description { get; set; } = new AuthenticationDescription(); } } diff --git a/src/Microsoft.AspNet.Security/BuilderSecurityExtensions.cs b/src/Microsoft.AspNet.Security/BuilderSecurityExtensions.cs deleted file mode 100644 index 5a9aec367f..0000000000 --- a/src/Microsoft.AspNet.Security/BuilderSecurityExtensions.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. 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.AspNet.Security; - -namespace Microsoft.AspNet.Builder -{ - /// - /// Provides extensions methods for app.Property values that are only needed by implementations of authentication middleware. - /// - public static class BuilderSecurityExtensions - { - /// - /// Returns the previously set AuthenticationType that external sign in middleware should use when the - /// browser navigates back to their return url. - /// - /// App builder passed to the application startup code - /// - public static string GetDefaultSignInAsAuthenticationType([NotNull] this IApplicationBuilder app) - { - object value; - if (app.Properties.TryGetValue(Constants.DefaultSignInAsAuthenticationType, out value)) - { - var authenticationType = value as string; - if (!string.IsNullOrEmpty(authenticationType)) - { - return authenticationType; - } - } - throw new InvalidOperationException(Resources.Exception_MissingDefaultSignInAsAuthenticationType); - } - - /// - /// Called by middleware to change the name of the AuthenticationType that external middleware should use - /// when the browser navigates back to their return url. - /// - /// App builder passed to the application startup code - /// AuthenticationType that external middleware should sign in as. - public static void SetDefaultSignInAsAuthenticationType([NotNull] this IApplicationBuilder app, [NotNull] string authenticationType) - { - app.Properties[Constants.DefaultSignInAsAuthenticationType] = authenticationType; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Security/Constants.cs b/src/Microsoft.AspNet.Security/Constants.cs deleted file mode 100644 index d1bc8f01e1..0000000000 --- a/src/Microsoft.AspNet.Security/Constants.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - - -namespace Microsoft.AspNet.Security -{ - /// - /// String constants used only by the Security assembly - /// - internal static class Constants - { - /// - /// Used by middleware extension methods to coordinate the default value Options property SignInAsAuthenticationType - /// - internal const string DefaultSignInAsAuthenticationType = "Microsoft.AspNet.Security.DefaultSignInAsAuthenticationType"; - } -} diff --git a/src/Microsoft.AspNet.Security/ExternalAuthenticationOptions.cs b/src/Microsoft.AspNet.Security/ExternalAuthenticationOptions.cs new file mode 100644 index 0000000000..671020b2b6 --- /dev/null +++ b/src/Microsoft.AspNet.Security/ExternalAuthenticationOptions.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + + +using System; + +namespace Microsoft.AspNet.Security +{ + public class ExternalAuthenticationOptions + { + public string SignInAsAuthenticationType { get; set; } + } +} diff --git a/src/Microsoft.AspNet.Security/Infrastructure/AuthenticationMiddleware.cs b/src/Microsoft.AspNet.Security/Infrastructure/AuthenticationMiddleware.cs index 8077b22d63..1ea787fce8 100644 --- a/src/Microsoft.AspNet.Security/Infrastructure/AuthenticationMiddleware.cs +++ b/src/Microsoft.AspNet.Security/Infrastructure/AuthenticationMiddleware.cs @@ -6,19 +6,30 @@ using System; using System.Threading.Tasks; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; +using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Security.Infrastructure { - public abstract class AuthenticationMiddleware where TOptions : AuthenticationOptions + public abstract class AuthenticationMiddleware where TOptions : AuthenticationOptions, new() { private readonly RequestDelegate _next; - protected AuthenticationMiddleware([NotNull] RequestDelegate next, [NotNull] TOptions options) + protected AuthenticationMiddleware([NotNull] RequestDelegate next, [NotNull] IOptionsAccessor options, IOptionsAction configureOptions) { - Options = options; + if (configureOptions != null) + { + Options = options.GetNamedOptions(configureOptions.Name); + configureOptions.Invoke(Options); + } + else + { + Options = options.Options; + } _next = next; } + public string AuthenticationType { get; set; } + public TOptions Options { get; set; } public async Task Invoke(HttpContext context) diff --git a/src/Microsoft.AspNet.Security/Resources.resx b/src/Microsoft.AspNet.Security/Resources.resx index f0765cc325..77060045e0 100644 --- a/src/Microsoft.AspNet.Security/Resources.resx +++ b/src/Microsoft.AspNet.Security/Resources.resx @@ -123,9 +123,6 @@ The state passed to UnhookAuthentication may only be the return value from HookAuthentication. - - A default value for SignInAsAuthenticationType was not found in IApplicationBuilder Properties. This can happen if your authentication middleware are added in the wrong order, or if one is missing. - The AuthenticationTokenProvider's required synchronous events have not been registered. diff --git a/src/Microsoft.AspNet.Security/project.json b/src/Microsoft.AspNet.Security/project.json index 11854a0e14..502d45043f 100644 --- a/src/Microsoft.AspNet.Security/project.json +++ b/src/Microsoft.AspNet.Security/project.json @@ -5,7 +5,8 @@ "Microsoft.AspNet.PipelineCore": "1.0.0-*", "Microsoft.AspNet.Security.DataProtection": "1.0.0-*", "Microsoft.Framework.DependencyInjection": "1.0.0-*", - "Microsoft.Framework.Logging": "1.0.0-*" + "Microsoft.Framework.Logging": "1.0.0-*", + "Microsoft.Framework.OptionsModel": "1.0.0-*" }, "frameworks": { "aspnet50": { }, diff --git a/test/Microsoft.AspNet.Security.Test/Cookies/CookieMiddlewareTests.cs b/test/Microsoft.AspNet.Security.Test/Cookies/CookieMiddlewareTests.cs index 6578ba6004..a02dc14752 100644 --- a/test/Microsoft.AspNet.Security.Test/Cookies/CookieMiddlewareTests.cs +++ b/test/Microsoft.AspNet.Security.Test/Cookies/CookieMiddlewareTests.cs @@ -18,6 +18,8 @@ using Microsoft.AspNet.Http.Security; using Microsoft.AspNet.TestHost; using Shouldly; using Xunit; +using Microsoft.Framework.OptionsModel; +using Microsoft.Framework.DependencyInjection; namespace Microsoft.AspNet.Security.Cookies { @@ -26,7 +28,7 @@ namespace Microsoft.AspNet.Security.Cookies [Fact] public async Task NormalRequestPassesThrough() { - TestServer server = CreateServer(new CookieAuthenticationOptions + TestServer server = CreateServer(options => { }); HttpResponseMessage response = await server.CreateClient().GetAsync("http://example.com/normal"); @@ -36,9 +38,9 @@ namespace Microsoft.AspNet.Security.Cookies [Fact] public async Task ProtectedRequestShouldRedirectToLogin() { - TestServer server = CreateServer(new CookieAuthenticationOptions + TestServer server = CreateServer(options => { - LoginPath = new PathString("/login") + options.LoginPath = new PathString("/login"); }); Transaction transaction = await SendAsync(server, "http://example.com/protected"); @@ -53,9 +55,9 @@ namespace Microsoft.AspNet.Security.Cookies [Fact] public async Task ProtectedCustomRequestShouldRedirectToCustomLogin() { - TestServer server = CreateServer(new CookieAuthenticationOptions + TestServer server = CreateServer(options => { - LoginPath = new PathString("/login") + options.LoginPath = new PathString("/login"); }); Transaction transaction = await SendAsync(server, "http://example.com/protected/CustomRedirect"); @@ -77,10 +79,10 @@ namespace Microsoft.AspNet.Security.Cookies [Fact] public async Task SignInCausesDefaultCookieToBeCreated() { - TestServer server = CreateServer(new CookieAuthenticationOptions + TestServer server = CreateServer(options => { - LoginPath = new PathString("/login"), - CookieName = "TestCookie", + options.LoginPath = new PathString("/login"); + options.CookieName = "TestCookie"; }, SignInAsAlice); Transaction transaction = await SendAsync(server, "http://example.com/testpath"); @@ -106,11 +108,11 @@ namespace Microsoft.AspNet.Security.Cookies string requestUri, bool shouldBeSecureOnly) { - TestServer server = CreateServer(new CookieAuthenticationOptions + TestServer server = CreateServer(options => { - LoginPath = new PathString("/login"), - CookieName = "TestCookie", - CookieSecure = cookieSecureOption + options.LoginPath = new PathString("/login"); + options.CookieName = "TestCookie"; + options.CookieSecure = cookieSecureOption; }, SignInAsAlice); Transaction transaction = await SendAsync(server, requestUri); @@ -129,22 +131,22 @@ namespace Microsoft.AspNet.Security.Cookies [Fact] public async Task CookieOptionsAlterSetCookieHeader() { - TestServer server1 = CreateServer(new CookieAuthenticationOptions + TestServer server1 = CreateServer(options => { - CookieName = "TestCookie", - CookiePath = "/foo", - CookieDomain = "another.com", - CookieSecure = CookieSecureOption.Always, - CookieHttpOnly = true, + options.CookieName = "TestCookie"; + options.CookiePath = "/foo"; + options.CookieDomain = "another.com"; + options.CookieSecure = CookieSecureOption.Always; + options.CookieHttpOnly = true; }, SignInAsAlice); Transaction transaction1 = await SendAsync(server1, "http://example.com/testpath"); - TestServer server2 = CreateServer(new CookieAuthenticationOptions + TestServer server2 = CreateServer(options => { - CookieName = "SecondCookie", - CookieSecure = CookieSecureOption.Never, - CookieHttpOnly = false, + options.CookieName = "SecondCookie"; + options.CookieSecure = CookieSecureOption.Never; + options.CookieHttpOnly = false; }, SignInAsAlice); Transaction transaction2 = await SendAsync(server2, "http://example.com/testpath"); @@ -168,9 +170,9 @@ namespace Microsoft.AspNet.Security.Cookies public async Task CookieContainsIdentity() { var clock = new TestClock(); - TestServer server = CreateServer(new CookieAuthenticationOptions + TestServer server = CreateServer(options => { - SystemClock = clock + options.SystemClock = clock; }, SignInAsAlice); Transaction transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -184,11 +186,11 @@ namespace Microsoft.AspNet.Security.Cookies public async Task CookieStopsWorkingAfterExpiration() { var clock = new TestClock(); - TestServer server = CreateServer(new CookieAuthenticationOptions + TestServer server = CreateServer(options => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - SlidingExpiration = false, + options.SystemClock = clock; + options.ExpireTimeSpan = TimeSpan.FromMinutes(10); + options.SlidingExpiration = false; }, SignInAsAlice); Transaction transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -215,11 +217,11 @@ namespace Microsoft.AspNet.Security.Cookies public async Task CookieExpirationCanBeOverridenInSignin() { var clock = new TestClock(); - TestServer server = CreateServer(new CookieAuthenticationOptions + TestServer server = CreateServer(options => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - SlidingExpiration = false, + options.SystemClock = clock; + options.ExpireTimeSpan = TimeSpan.FromMinutes(10); + options.SlidingExpiration = false; }, context => { @@ -253,18 +255,18 @@ namespace Microsoft.AspNet.Security.Cookies public async Task CookieExpirationCanBeOverridenInEvent() { var clock = new TestClock(); - TestServer server = CreateServer(new CookieAuthenticationOptions + TestServer server = CreateServer(options => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - SlidingExpiration = false, - Notifications = new CookieAuthenticationNotifications() + options.SystemClock = clock; + options.ExpireTimeSpan = TimeSpan.FromMinutes(10); + options.SlidingExpiration = false; + options.Notifications = new CookieAuthenticationNotifications() { OnResponseSignIn = context => { context.Properties.ExpiresUtc = clock.UtcNow.Add(TimeSpan.FromMinutes(5)); } - } + }; }, SignInAsAlice); Transaction transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -291,11 +293,11 @@ namespace Microsoft.AspNet.Security.Cookies public async Task CookieIsRenewedWithSlidingExpiration() { var clock = new TestClock(); - TestServer server = CreateServer(new CookieAuthenticationOptions + TestServer server = CreateServer(options => { - SystemClock = clock, - ExpireTimeSpan = TimeSpan.FromMinutes(10), - SlidingExpiration = true, + options.SystemClock = clock; + options.ExpireTimeSpan = TimeSpan.FromMinutes(10); + options.SlidingExpiration = true; }, SignInAsAlice); Transaction transaction1 = await SendAsync(server, "http://example.com/testpath"); @@ -328,9 +330,9 @@ namespace Microsoft.AspNet.Security.Cookies [Fact] public async Task AjaxRedirectsAsExtraHeaderOnTwoHundred() { - TestServer server = CreateServer(new CookieAuthenticationOptions + TestServer server = CreateServer(options => { - LoginPath = new PathString("/login") + options.LoginPath = new PathString("/login"); }); Transaction transaction = await SendAsync(server, "http://example.com/protected", ajaxRequest: true); @@ -363,11 +365,12 @@ namespace Microsoft.AspNet.Security.Cookies return me; } - private static TestServer CreateServer(CookieAuthenticationOptions options, Func testpath = null) + private static TestServer CreateServer(Action configureOptions, Func testpath = null) { return TestServer.Create(app => { - app.UseCookieAuthentication(options); + app.UseServices(services => { }); + app.UseCookieAuthentication(configureOptions); app.Use(async (context, next) => { var req = context.Request; diff --git a/test/Microsoft.AspNet.Security.Test/Facebook/FacebookMiddlewareTests.cs b/test/Microsoft.AspNet.Security.Test/Facebook/FacebookMiddlewareTests.cs index 672dc04ac9..2f800c4933 100644 --- a/test/Microsoft.AspNet.Security.Test/Facebook/FacebookMiddlewareTests.cs +++ b/test/Microsoft.AspNet.Security.Test/Facebook/FacebookMiddlewareTests.cs @@ -13,6 +13,7 @@ using Microsoft.AspNet.Http.Security; using Microsoft.AspNet.Security.Cookies; using Microsoft.AspNet.TestHost; using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.OptionsModel; using Shouldly; using Xunit; @@ -23,20 +24,35 @@ namespace Microsoft.AspNet.Security.Facebook [Fact] public async Task ChallengeWillTriggerApplyRedirectEvent() { - var options = new FacebookAuthenticationOptions() - { - AppId = "Test App Id", - AppSecret = "Test App Secret", - Notifications = new FacebookAuthenticationNotifications - { - OnApplyRedirect = context => - { - context.Response.Redirect(context.RedirectUri + "&custom=test"); - } - } - }; var server = CreateServer( - app => app.UseFacebookAuthentication(options), + app => + { + app.UseServices(services => + { + services.ConfigureFacebookAuthentication(options => + { + options.AppId = "Test App Id"; + options.AppSecret = "Test App Secret"; + options.Notifications = new FacebookAuthenticationNotifications + { + OnApplyRedirect = context => + { + context.Response.Redirect(context.RedirectUri + "&custom=test"); + } + }; + }); + services.ConfigureCookieAuthentication(options => + { + options.AuthenticationType = "External"; + }); + services.ConfigureOptions(options => + { + options.SignInAsAuthenticationType = "External"; + }); + }); + app.UseFacebookAuthentication(); + app.UseCookieAuthentication(); + }, context => { context.Response.Challenge("Facebook"); @@ -52,7 +68,27 @@ namespace Microsoft.AspNet.Security.Facebook public async Task ChallengeWillTriggerRedirection() { var server = CreateServer( - app => app.UseFacebookAuthentication("Test App Id", "Test App Secret"), + app => + { + app.UseServices(services => + { + services.ConfigureFacebookAuthentication(options => + { + options.AppId = "Test App Id"; + options.AppSecret = "Test App Secret"; + }); + services.ConfigureCookieAuthentication(options => + { + options.AuthenticationType = "External"; + }); + services.ConfigureOptions(options => + { + options.SignInAsAuthenticationType = "External"; + }); + }); + app.UseFacebookAuthentication(); + app.UseCookieAuthentication(); + }, context => { context.Response.Challenge("Facebook"); @@ -73,11 +109,6 @@ namespace Microsoft.AspNet.Security.Facebook { return TestServer.Create(app => { - app.SetDefaultSignInAsAuthenticationType("External"); - app.UseCookieAuthentication(new CookieAuthenticationOptions() - { - AuthenticationType = "External" - }); if (configure != null) { configure(app); diff --git a/test/Microsoft.AspNet.Security.Test/Google/GoogleMiddlewareTests.cs b/test/Microsoft.AspNet.Security.Test/Google/GoogleMiddlewareTests.cs index e12def60fa..2a58baf167 100644 --- a/test/Microsoft.AspNet.Security.Test/Google/GoogleMiddlewareTests.cs +++ b/test/Microsoft.AspNet.Security.Test/Google/GoogleMiddlewareTests.cs @@ -19,6 +19,10 @@ using Microsoft.AspNet.TestHost; using Newtonsoft.Json; using Shouldly; using Xunit; +using Microsoft.Framework.OptionsModel; +using Microsoft.Framework.DependencyInjection; +using Microsoft.AspNet.Security.DataProtection; +using Microsoft.AspNet.Security.DataHandler; namespace Microsoft.AspNet.Security.Google { @@ -29,10 +33,10 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task ChallengeWillTriggerRedirection() { - var server = CreateServer(new GoogleAuthenticationOptions() + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret" + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; }); var transaction = await SendAsync(server, "https://example.com/challenge"); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); @@ -51,11 +55,11 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task Challenge401WillTriggerRedirection() { - var server = CreateServer(new GoogleAuthenticationOptions() + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - AuthenticationMode = AuthenticationMode.Active, + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; + options.AuthenticationMode = AuthenticationMode.Active; }); var transaction = await SendAsync(server, "https://example.com/401"); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); @@ -70,10 +74,10 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task ChallengeWillSetCorrelationCookie() { - var server = CreateServer(new GoogleAuthenticationOptions() + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret" + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; }); var transaction = await SendAsync(server, "https://example.com/challenge"); Console.WriteLine(transaction.SetCookie); @@ -83,11 +87,11 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task Challenge401WillSetCorrelationCookie() { - var server = CreateServer(new GoogleAuthenticationOptions() + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - AuthenticationMode = AuthenticationMode.Active, + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; + options.AuthenticationMode = AuthenticationMode.Active; }); var transaction = await SendAsync(server, "https://example.com/401"); Console.WriteLine(transaction.SetCookie); @@ -97,10 +101,11 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task ChallengeWillSetDefaultScope() { - var server = CreateServer(new GoogleAuthenticationOptions() + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret" + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; + options.AuthenticationMode = AuthenticationMode.Active; }); var transaction = await SendAsync(server, "https://example.com/challenge"); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); @@ -111,11 +116,11 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task Challenge401WillSetDefaultScope() { - var server = CreateServer(new GoogleAuthenticationOptions() + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - AuthenticationMode = AuthenticationMode.Active, + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; + options.AuthenticationMode = AuthenticationMode.Active; }); var transaction = await SendAsync(server, "https://example.com/401"); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); @@ -126,13 +131,12 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task ChallengeWillUseOptionsScope() { - var options = new GoogleAuthenticationOptions() + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - }; - options.Scope.Add("https://www.googleapis.com/auth/plus.login"); - var server = CreateServer(options); + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; + options.Scope.Add("https://www.googleapis.com/auth/plus.login"); + }); var transaction = await SendAsync(server, "https://example.com/challenge"); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); var query = transaction.Response.Headers.Location.Query; @@ -142,13 +146,12 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task ChallengeWillUseAuthenticationPropertiesAsParameters() { - var options = new GoogleAuthenticationOptions() + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret" - }; - var server = CreateServer(options, - context => + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; + }, + context => { var req = context.Request; var res = context.Response; @@ -179,19 +182,18 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task ChallengeWillTriggerApplyRedirectEvent() { - var options = new GoogleAuthenticationOptions() + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - Notifications = new GoogleAuthenticationNotifications + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; + options.Notifications = new GoogleAuthenticationNotifications { OnApplyRedirect = context => { context.Response.Redirect(context.RedirectUri + "&custom=test"); } - } - }; - var server = CreateServer(options); + }; + }); var transaction = await SendAsync(server, "https://example.com/challenge"); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); var query = transaction.Response.Headers.Location.Query; @@ -201,12 +203,11 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task ReplyPathWithoutStateQueryStringWillBeRejected() { - var options = new GoogleAuthenticationOptions() + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret" - }; - var server = CreateServer(options); + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; + }); var transaction = await SendAsync(server, "https://example.com/signin-google?code=TestCode"); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.InternalServerError); } @@ -214,57 +215,58 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task ReplyPathWillAuthenticateValidAuthorizeCodeAndState() { - var options = new GoogleAuthenticationOptions() + ISecureDataFormat stateFormat = new PropertiesDataFormat(DataProtectionProvider.CreateNew().CreateProtector("GoogleTest")); + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - BackchannelHttpHandler = new TestHttpMessageHandler + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; + options.StateDataFormat = stateFormat; + options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = async req => + { + if (req.RequestUri.AbsoluteUri == "https://accounts.google.com/o/oauth2/token") { - if (req.RequestUri.AbsoluteUri == "https://accounts.google.com/o/oauth2/token") + return await ReturnJsonResponse(new { - return await ReturnJsonResponse(new - { - access_token = "Test Access Token", - expire_in = 3600, - token_type = "Bearer" - }); - } - else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://www.googleapis.com/plus/v1/people/me") - { - return await ReturnJsonResponse(new - { - id = "Test User ID", - displayName = "Test Name", - name = new - { - familyName = "Test Family Name", - givenName = "Test Given Name" - }, - url = "Profile link", - emails = new[] - { - new - { - value = "Test email", - type = "account" - } - } - }); - } - - return null; + access_token = "Test Access Token", + expire_in = 3600, + token_type = "Bearer" + }); } - } - }; - var server = CreateServer(options); + else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://www.googleapis.com/plus/v1/people/me") + { + return await ReturnJsonResponse(new + { + id = "Test User ID", + displayName = "Test Name", + name = new + { + familyName = "Test Family Name", + givenName = "Test Given Name" + }, + url = "Profile link", + emails = new[] + { + new + { + value = "Test email", + type = "account" + } + } + }); + } + + return null; + } + }; + }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Dictionary.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; - var state = options.StateDataFormat.Protect(properties); + var state = stateFormat.Protect(properties); var transaction = await SendAsync(server, "https://example.com/signin-google?code=TestCode&state=" + Uri.EscapeDataString(state), correlationKey + "=" + correlationValue); @@ -287,25 +289,26 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task ReplyPathWillRejectIfCodeIsInvalid() { - var options = new GoogleAuthenticationOptions() + ISecureDataFormat stateFormat = new PropertiesDataFormat(DataProtectionProvider.CreateNew().CreateProtector("GoogleTest")); + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - BackchannelHttpHandler = new TestHttpMessageHandler + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; + options.StateDataFormat = stateFormat; + options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = req => { return Task.FromResult(new HttpResponseMessage(HttpStatusCode.BadRequest)); } - } - }; - var server = CreateServer(options); + }; + }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Dictionary.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; - var state = options.StateDataFormat.Protect(properties); + var state = stateFormat.Protect(properties); var transaction = await SendAsync(server, "https://example.com/signin-google?code=TestCode&state=" + Uri.EscapeDataString(state), correlationKey + "=" + correlationValue); @@ -316,25 +319,26 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task ReplyPathWillRejectIfAccessTokenIsMissing() { - var options = new GoogleAuthenticationOptions() + ISecureDataFormat stateFormat = new PropertiesDataFormat(DataProtectionProvider.CreateNew().CreateProtector("GoogleTest")); + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - BackchannelHttpHandler = new TestHttpMessageHandler + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; + options.StateDataFormat = stateFormat; + options.BackchannelHttpHandler = new TestHttpMessageHandler { - Sender = async req => + Sender = req => { - return await ReturnJsonResponse(new object()); + return ReturnJsonResponse(new object()); } - } - }; - var server = CreateServer(options); + }; + }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Dictionary.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; - var state = options.StateDataFormat.Protect(properties); + var state = stateFormat.Protect(properties); var transaction = await SendAsync(server, "https://example.com/signin-google?code=TestCode&state=" + Uri.EscapeDataString(state), correlationKey + "=" + correlationValue); @@ -345,11 +349,13 @@ namespace Microsoft.AspNet.Security.Google [Fact] public async Task AuthenticatedEventCanGetRefreshToken() { - var options = new GoogleAuthenticationOptions() + ISecureDataFormat stateFormat = new PropertiesDataFormat(DataProtectionProvider.CreateNew().CreateProtector("GoogleTest")); + var server = CreateServer(options => { - ClientId = "Test Id", - ClientSecret = "Test Secret", - BackchannelHttpHandler = new TestHttpMessageHandler + options.ClientId = "Test Id"; + options.ClientSecret = "Test Secret"; + options.StateDataFormat = stateFormat; + options.BackchannelHttpHandler = new TestHttpMessageHandler { Sender = async req => { @@ -388,8 +394,8 @@ namespace Microsoft.AspNet.Security.Google return null; } - }, - Notifications = new GoogleAuthenticationNotifications() + }; + options.Notifications = new GoogleAuthenticationNotifications() { OnAuthenticated = context => { @@ -397,15 +403,14 @@ namespace Microsoft.AspNet.Security.Google context.Identity.AddClaim(new Claim("RefreshToken", refreshToken)); return Task.FromResult(null); } - } - }; - var server = CreateServer(options); + }; + }); var properties = new AuthenticationProperties(); var correlationKey = ".AspNet.Correlation.Google"; var correlationValue = "TestCorrelationId"; properties.Dictionary.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; - var state = options.StateDataFormat.Protect(properties); + var state = stateFormat.Protect(properties); var transaction = await SendAsync(server, "https://example.com/signin-google?code=TestCode&state=" + Uri.EscapeDataString(state), correlationKey + "=" + correlationValue); @@ -456,16 +461,19 @@ namespace Microsoft.AspNet.Security.Google return transaction; } - private static TestServer CreateServer(GoogleAuthenticationOptions options, Func testpath = null) + private static TestServer CreateServer(Action configureOptions, Func testpath = null) { return TestServer.Create(app => { - app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationType); - app.UseCookieAuthentication(new CookieAuthenticationOptions() + app.UseServices(services => + { + services.ConfigureOptions(options => { - AuthenticationType = CookieAuthenticationType + options.SignInAsAuthenticationType = CookieAuthenticationType; }); - app.UseGoogleAuthentication(options); + }); + app.UseCookieAuthentication(options => options.AuthenticationType = CookieAuthenticationType); + app.UseGoogleAuthentication(configureOptions); app.Use(async (context, next) => { var req = context.Request; diff --git a/test/Microsoft.AspNet.Security.Test/MicrosoftAccount/MicrosoftAccountMiddlewareTests.cs b/test/Microsoft.AspNet.Security.Test/MicrosoftAccount/MicrosoftAccountMiddlewareTests.cs index a19aeae05c..3a90d5fc51 100644 --- a/test/Microsoft.AspNet.Security.Test/MicrosoftAccount/MicrosoftAccountMiddlewareTests.cs +++ b/test/Microsoft.AspNet.Security.Test/MicrosoftAccount/MicrosoftAccountMiddlewareTests.cs @@ -20,6 +20,10 @@ using Microsoft.AspNet.TestHost; using Newtonsoft.Json; using Shouldly; using Xunit; +using Microsoft.Framework.OptionsModel; +using Microsoft.Framework.DependencyInjection; +using Microsoft.AspNet.Security.DataHandler; +using Microsoft.AspNet.Security.DataProtection; namespace Microsoft.AspNet.Security.Tests.MicrosoftAccount { @@ -28,20 +32,19 @@ namespace Microsoft.AspNet.Security.Tests.MicrosoftAccount [Fact] public async Task ChallengeWillTriggerApplyRedirectEvent() { - var options = new MicrosoftAccountAuthenticationOptions() - { - ClientId = "Test Client Id", - ClientSecret = "Test Client Secret", - Notifications = new MicrosoftAccountAuthenticationNotifications - { - OnApplyRedirect = context => - { - context.Response.Redirect(context.RedirectUri + "&custom=test"); - } - } - }; var server = CreateServer( - app => app.UseMicrosoftAccountAuthentication(options), + options => + { + options.ClientId = "Test Client Id"; + options.ClientSecret = "Test Client Secret"; + options.Notifications = new MicrosoftAccountAuthenticationNotifications + { + OnApplyRedirect = context => + { + context.Response.Redirect(context.RedirectUri + "&custom=test"); + } + }; + }, context => { context.Response.Challenge("Microsoft"); @@ -57,7 +60,11 @@ namespace Microsoft.AspNet.Security.Tests.MicrosoftAccount public async Task ChallengeWillTriggerRedirection() { var server = CreateServer( - app => app.UseMicrosoftAccountAuthentication("Test Client Id", "Test Client Secret"), + options => + { + options.ClientId = "Test Client Id"; + options.ClientSecret = "Test Client Secret"; + }, context => { context.Response.Challenge("Microsoft"); @@ -77,54 +84,55 @@ namespace Microsoft.AspNet.Security.Tests.MicrosoftAccount [Fact] public async Task AuthenticatedEventCanGetRefreshToken() { - var options = new MicrosoftAccountAuthenticationOptions() - { - ClientId = "Test Client Id", - ClientSecret = "Test Client Secret", - BackchannelHttpHandler = new TestHttpMessageHandler - { - Sender = async req => - { - if (req.RequestUri.AbsoluteUri == "https://login.live.com/oauth20_token.srf") - { - return await ReturnJsonResponse(new - { - access_token = "Test Access Token", - expire_in = 3600, - token_type = "Bearer", - refresh_token = "Test Refresh Token" - }); - } - else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://apis.live.net/v5.0/me") - { - return await ReturnJsonResponse(new - { - id = "Test User ID", - name = "Test Name", - first_name = "Test Given Name", - last_name = "Test Family Name", - emails = new - { - preferred = "Test email" - } - }); - } - - return null; - } - }, - Notifications = new MicrosoftAccountAuthenticationNotifications - { - OnAuthenticated = context => - { - var refreshToken = context.RefreshToken; - context.Identity.AddClaim(new Claim("RefreshToken", refreshToken)); - return Task.FromResult(null); - } - } - }; + ISecureDataFormat stateFormat = new PropertiesDataFormat(DataProtectionProvider.CreateNew().CreateProtector("MsftTest")); var server = CreateServer( - app => app.UseMicrosoftAccountAuthentication(options), + options => + { + options.ClientId = "Test Client Id"; + options.ClientSecret = "Test Client Secret"; + options.StateDataFormat = stateFormat; + options.BackchannelHttpHandler = new TestHttpMessageHandler + { + Sender = async req => + { + if (req.RequestUri.AbsoluteUri == "https://login.live.com/oauth20_token.srf") + { + return await ReturnJsonResponse(new + { + access_token = "Test Access Token", + expire_in = 3600, + token_type = "Bearer", + refresh_token = "Test Refresh Token" + }); + } + else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://apis.live.net/v5.0/me") + { + return await ReturnJsonResponse(new + { + id = "Test User ID", + name = "Test Name", + first_name = "Test Given Name", + last_name = "Test Family Name", + emails = new + { + preferred = "Test email" + } + }); + } + + return null; + } + }; + options.Notifications = new MicrosoftAccountAuthenticationNotifications + { + OnAuthenticated = context => + { + var refreshToken = context.RefreshToken; + context.Identity.AddClaim(new Claim("RefreshToken", refreshToken)); + return Task.FromResult(null); + } + }; + }, context => { Describe(context.Response, (ClaimsIdentity)context.User.Identity); @@ -135,7 +143,7 @@ namespace Microsoft.AspNet.Security.Tests.MicrosoftAccount var correlationValue = "TestCorrelationId"; properties.Dictionary.Add(correlationKey, correlationValue); properties.RedirectUri = "/me"; - var state = options.StateDataFormat.Protect(properties); + var state = stateFormat.Protect(properties); var transaction = await SendAsync(server, "https://example.com/signin-microsoft?code=TestCode&state=" + Uri.EscapeDataString(state), correlationKey + "=" + correlationValue); @@ -151,19 +159,19 @@ namespace Microsoft.AspNet.Security.Tests.MicrosoftAccount transaction.FindClaimValue("RefreshToken").ShouldBe("Test Refresh Token"); } - private static TestServer CreateServer(Action configure, Func handler) + private static TestServer CreateServer(Action configureOptions, Func handler) { return TestServer.Create(app => { - app.UseCookieAuthentication(new CookieAuthenticationOptions + app.UseServices(services => { - AuthenticationType = "External" + services.ConfigureOptions(options => + { + options.SignInAsAuthenticationType = "External"; + }); }); - app.SetDefaultSignInAsAuthenticationType("External"); - if (configure != null) - { - configure(app); - } + app.UseCookieAuthentication(options => options.AuthenticationType = "External"); + app.UseMicrosoftAccountAuthentication(configureOptions); app.Use(async (context, next) => { if (handler == null || !handler(context)) diff --git a/test/Microsoft.AspNet.Security.Test/Twitter/TwitterMiddlewareTests.cs b/test/Microsoft.AspNet.Security.Test/Twitter/TwitterMiddlewareTests.cs index 461e541845..31afcfa7a9 100644 --- a/test/Microsoft.AspNet.Security.Test/Twitter/TwitterMiddlewareTests.cs +++ b/test/Microsoft.AspNet.Security.Test/Twitter/TwitterMiddlewareTests.cs @@ -15,6 +15,8 @@ using Microsoft.AspNet.TestHost; using Newtonsoft.Json; using Shouldly; using Xunit; +using Microsoft.Framework.OptionsModel; +using Microsoft.Framework.DependencyInjection; namespace Microsoft.AspNet.Security.Twitter { @@ -23,20 +25,21 @@ namespace Microsoft.AspNet.Security.Twitter [Fact] public async Task ChallengeWillTriggerApplyRedirectEvent() { - var options = new TwitterAuthenticationOptions() - { - ConsumerKey = "Test Consumer Key", - ConsumerSecret = "Test Consumer Secret", - Notifications = new TwitterAuthenticationNotifications + var server = CreateServer( + app => app.UseTwitterAuthentication(options => { - OnApplyRedirect = context => + options.ConsumerKey = "Test Consumer Key"; + options.ConsumerSecret = "Test Consumer Secret"; + options.Notifications = new TwitterAuthenticationNotifications { - context.Response.Redirect(context.RedirectUri + "&custom=test"); - } - }, - BackchannelHttpHandler = new TestHttpMessageHandler - { - Sender = req => + OnApplyRedirect = context => + { + context.Response.Redirect(context.RedirectUri + "&custom=test"); + } + }; + options.BackchannelHttpHandler = new TestHttpMessageHandler + { + Sender = req => { if (req.RequestUri.AbsoluteUri == "https://api.twitter.com/oauth/request_token") { @@ -50,11 +53,9 @@ namespace Microsoft.AspNet.Security.Twitter } return Task.FromResult(null); } - }, - BackchannelCertificateValidator = null - }; - var server = CreateServer( - app => app.UseTwitterAuthentication(options), + }; + options.BackchannelCertificateValidator = null; + }), context => { context.Response.Challenge("Twitter"); @@ -69,31 +70,30 @@ namespace Microsoft.AspNet.Security.Twitter [Fact] public async Task ChallengeWillTriggerRedirection() { - var options = new TwitterAuthenticationOptions() - { - ConsumerKey = "Test Consumer Key", - ConsumerSecret = "Test Consumer Secret", - BackchannelHttpHandler = new TestHttpMessageHandler - { - Sender = req => - { - if (req.RequestUri.AbsoluteUri == "https://api.twitter.com/oauth/request_token") - { - return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) - { - Content = - new StringContent("oauth_callback_confirmed=true&oauth_token=test_oauth_token&oauth_token_secret=test_oauth_token_secret", - Encoding.UTF8, - "application/x-www-form-urlencoded") - }); - } - return Task.FromResult(null); - } - }, - BackchannelCertificateValidator = null - }; var server = CreateServer( - app => app.UseTwitterAuthentication(options), + app => app.UseTwitterAuthentication(options => + { + options.ConsumerKey = "Test Consumer Key"; + options.ConsumerSecret = "Test Consumer Secret"; + options.BackchannelHttpHandler = new TestHttpMessageHandler + { + Sender = req => + { + if (req.RequestUri.AbsoluteUri == "https://api.twitter.com/oauth/request_token") + { + return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) + { + Content = + new StringContent("oauth_callback_confirmed=true&oauth_token=test_oauth_token&oauth_token_secret=test_oauth_token_secret", + Encoding.UTF8, + "application/x-www-form-urlencoded") + }); + } + return Task.FromResult(null); + } + }; + options.BackchannelCertificateValidator = null; + }), context => { context.Response.Challenge("Twitter"); @@ -109,10 +109,16 @@ namespace Microsoft.AspNet.Security.Twitter { return TestServer.Create(app => { - app.SetDefaultSignInAsAuthenticationType("External"); - app.UseCookieAuthentication(new CookieAuthenticationOptions + app.UseServices(services => { - AuthenticationType = "External" + services.ConfigureOptions(options => + { + options.SignInAsAuthenticationType = "External"; + }); + }); + app.UseCookieAuthentication(options => + { + options.AuthenticationType = "External"; }); if (configure != null) { diff --git a/test/Microsoft.AspNet.Security.Test/project.json b/test/Microsoft.AspNet.Security.Test/project.json index c3b4a4b2c9..7fa89c00ce 100644 --- a/test/Microsoft.AspNet.Security.Test/project.json +++ b/test/Microsoft.AspNet.Security.Test/project.json @@ -12,6 +12,7 @@ "Microsoft.AspNet.Security.Twitter": "1.0.0-*", "Microsoft.AspNet.TestHost": "1.0.0-*", "Microsoft.Framework.DependencyInjection": "1.0.0-*", + "Microsoft.Framework.OptionsModel": "1.0.0-*", "Moq": "4.2.1312.1622", "Xunit.KRunner": "1.0.0-*" },