From 2f9fb9f1068aca3cc61d1e887c2422892c67b8d9 Mon Sep 17 00:00:00 2001 From: Albireo Date: Tue, 7 Jul 2015 10:20:15 +0200 Subject: [PATCH 01/18] Add imgur provider classes stubs --- .../Imgur/ImgurAuthenticationDefaults.cs | 7 +++++++ .../Imgur/ImgurAuthenticationExtensions.cs | 10 ++++++++++ .../Imgur/ImgurAuthenticationHandler.cs | 16 ++++++++++++++++ .../Imgur/ImgurAuthenticationMiddleware.cs | 17 +++++++++++++++++ .../Imgur/ImgurAuthenticationOptions.cs | 11 +++++++++++ .../Provider/IImgurAuthenticationProvider.cs | 11 +++++++++++ .../Provider/ImgurAuthenticatedContext.cs | 12 ++++++++++++ .../Provider/ImgurAuthenticationProvider.cs | 18 ++++++++++++++++++ .../Provider/ImgurReturnEndpointContext.cs | 13 +++++++++++++ .../Owin.Security.Providers.csproj | 9 +++++++++ 10 files changed, 124 insertions(+) create mode 100644 Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs create mode 100644 Owin.Security.Providers/Imgur/ImgurAuthenticationExtensions.cs create mode 100644 Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs create mode 100644 Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs create mode 100644 Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs create mode 100644 Owin.Security.Providers/Imgur/Provider/IImgurAuthenticationProvider.cs create mode 100644 Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs create mode 100644 Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs create mode 100644 Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs new file mode 100644 index 00000000..7e983793 --- /dev/null +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs @@ -0,0 +1,7 @@ +namespace Owin.Security.Providers.Imgur +{ + public class ImgurAuthenticationDefaults + { + public const string AuthenticationType = "Imgur"; + } +} diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationExtensions.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationExtensions.cs new file mode 100644 index 00000000..b9059ab9 --- /dev/null +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationExtensions.cs @@ -0,0 +1,10 @@ +namespace Owin.Security.Providers.Imgur +{ + public static class ImgurAuthenticationExtensions + { + public static IAppBuilder UseImgurAuthentication(this IAppBuilder appBuilder, ImgurAuthenticationOptions options) + { + return appBuilder.Use(appBuilder, options); + } + } +} diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs new file mode 100644 index 00000000..b32f9f23 --- /dev/null +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs @@ -0,0 +1,16 @@ +namespace Owin.Security.Providers.Imgur +{ + using System; + using System.Threading.Tasks; + + using Microsoft.Owin.Security; + using Microsoft.Owin.Security.Infrastructure; + + public class ImgurAuthenticationHandler : AuthenticationHandler + { + protected override Task AuthenticateCoreAsync() + { + throw new NotImplementedException(); + } + } +} diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs new file mode 100644 index 00000000..c8e29b40 --- /dev/null +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs @@ -0,0 +1,17 @@ +namespace Owin.Security.Providers.Imgur +{ + using Microsoft.Owin; + using Microsoft.Owin.Security.Infrastructure; + + public class ImgurAuthenticationMiddleware : AuthenticationMiddleware + { + public ImgurAuthenticationMiddleware(OwinMiddleware next, ImgurAuthenticationOptions options) : base(next, options) + { + } + + protected override AuthenticationHandler CreateHandler() + { + return new ImgurAuthenticationHandler(); + } + } +} diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs new file mode 100644 index 00000000..88400723 --- /dev/null +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs @@ -0,0 +1,11 @@ +namespace Owin.Security.Providers.Imgur +{ + using Microsoft.Owin.Security; + + public class ImgurAuthenticationOptions : AuthenticationOptions + { + public ImgurAuthenticationOptions() : base(ImgurAuthenticationDefaults.AuthenticationType) + { + } + } +} diff --git a/Owin.Security.Providers/Imgur/Provider/IImgurAuthenticationProvider.cs b/Owin.Security.Providers/Imgur/Provider/IImgurAuthenticationProvider.cs new file mode 100644 index 00000000..71cf4cb8 --- /dev/null +++ b/Owin.Security.Providers/Imgur/Provider/IImgurAuthenticationProvider.cs @@ -0,0 +1,11 @@ +namespace Owin.Security.Providers.Imgur.Provider +{ + using System.Threading.Tasks; + + public interface IImgurAuthenticationProvider + { + Task Authenticated(ImgurAuthenticatedContext context); + + Task ReturnEndpoint(ImgurReturnEndpointContext context); + } +} diff --git a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs new file mode 100644 index 00000000..ac2c8572 --- /dev/null +++ b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs @@ -0,0 +1,12 @@ +namespace Owin.Security.Providers.Imgur.Provider +{ + using Microsoft.Owin; + using Microsoft.Owin.Security.Provider; + + public class ImgurAuthenticatedContext : BaseContext + { + public ImgurAuthenticatedContext(IOwinContext context, ImgurAuthenticationOptions options) : base(context, options) + { + } + } +} diff --git a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs new file mode 100644 index 00000000..412826f5 --- /dev/null +++ b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs @@ -0,0 +1,18 @@ +namespace Owin.Security.Providers.Imgur.Provider +{ + using System; + using System.Threading.Tasks; + + public class ImgurAuthenticationProvider : IImgurAuthenticationProvider + { + public Task Authenticated(ImgurAuthenticatedContext context) + { + throw new NotImplementedException(); + } + + public Task ReturnEndpoint(ImgurReturnEndpointContext context) + { + throw new NotImplementedException(); + } + } +} diff --git a/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs b/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs new file mode 100644 index 00000000..6db56e97 --- /dev/null +++ b/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs @@ -0,0 +1,13 @@ +namespace Owin.Security.Providers.Imgur.Provider +{ + using Microsoft.Owin; + using Microsoft.Owin.Security; + using Microsoft.Owin.Security.Provider; + + public class ImgurReturnEndpointContext : ReturnEndpointContext + { + public ImgurReturnEndpointContext(IOwinContext context, AuthenticationTicket ticket) : base(context, ticket) + { + } + } +} diff --git a/Owin.Security.Providers/Owin.Security.Providers.csproj b/Owin.Security.Providers/Owin.Security.Providers.csproj index 1e6063da..5dacbd8a 100644 --- a/Owin.Security.Providers/Owin.Security.Providers.csproj +++ b/Owin.Security.Providers/Owin.Security.Providers.csproj @@ -178,6 +178,15 @@ + + + + + + + + + From 95d20648e416295758325dea372c9978816d6efc Mon Sep 17 00:00:00 2001 From: Albireo Date: Wed, 8 Jul 2015 22:17:06 +0200 Subject: [PATCH 02/18] Fix imgur middleware constructor --- Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs index c8e29b40..9e3ec028 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs @@ -5,7 +5,7 @@ public class ImgurAuthenticationMiddleware : AuthenticationMiddleware { - public ImgurAuthenticationMiddleware(OwinMiddleware next, ImgurAuthenticationOptions options) : base(next, options) + public ImgurAuthenticationMiddleware(OwinMiddleware next, IAppBuilder appBuilder, ImgurAuthenticationOptions options) : base(next, options) { } From 0944fd9fae8bf5570ccbc5ac9a75c94f0d9f24ef Mon Sep 17 00:00:00 2001 From: Albireo Date: Wed, 8 Jul 2015 22:24:09 +0200 Subject: [PATCH 03/18] Add imgur authentication options --- .../Imgur/ImgurAuthenticationDefaults.cs | 2 +- .../Imgur/ImgurAuthenticationOptions.cs | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs index 7e983793..7c16387f 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs @@ -1,6 +1,6 @@ namespace Owin.Security.Providers.Imgur { - public class ImgurAuthenticationDefaults + internal static class ImgurAuthenticationDefaults { public const string AuthenticationType = "Imgur"; } diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs index 88400723..6c01009e 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs @@ -1,11 +1,41 @@ namespace Owin.Security.Providers.Imgur { + using System; + using System.Net.Http; + + using Microsoft.Owin; using Microsoft.Owin.Security; + using Owin.Security.Providers.Imgur.Provider; + public class ImgurAuthenticationOptions : AuthenticationOptions { public ImgurAuthenticationOptions() : base(ImgurAuthenticationDefaults.AuthenticationType) { + this.AuthenticationMode = AuthenticationMode.Passive; + this.BackchannelTimeout = TimeSpan.FromSeconds(60); + this.CallbackPath = new PathString("/signin-imgur"); + this.Caption = ImgurAuthenticationDefaults.AuthenticationType; } + + public ICertificateValidator BackchannelCertificateValidator { get; set; } + + public HttpMessageHandler BackchannelHttpHandler { get; set; } + + public TimeSpan BackchannelTimeout { get; set; } + + public PathString CallbackPath { get; set; } + + public string Caption { get; set; } + + public string ClientId { get; set; } + + public string ClientSecret { get; set; } + + public IImgurAuthenticationProvider Provider { get; set; } + + public string SignInAsAuthenticationType { get; set; } + + public ISecureDataFormat StateDataFormat { get; set; } } } From d3365fcb5cd040c47bf938db6d3f0a5f76ed2ce4 Mon Sep 17 00:00:00 2001 From: Albireo Date: Wed, 8 Jul 2015 22:24:35 +0200 Subject: [PATCH 04/18] Add imgur authentication registration --- OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs index dc533c49..97815354 100755 --- a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs +++ b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs @@ -18,6 +18,7 @@ using Owin.Security.Providers.GooglePlus; using Owin.Security.Providers.GooglePlus.Provider; using Owin.Security.Providers.HealthGraph; +using Owin.Security.Providers.Imgur; using Owin.Security.Providers.Instagram; using Owin.Security.Providers.LinkedIn; using Owin.Security.Providers.OpenID; @@ -248,6 +249,13 @@ public void ConfigureAuth(IAppBuilder app) // clientId: "", // clientSecret: "" //); + + //app.UseImgurAuthentication( + // new ImgurAuthenticationOptions + // { + // ClientId = "", + // ClientSecret = "" + // }); } } } From 65aefd97ec3822df2323082c9c0fbb0ed2482e3a Mon Sep 17 00:00:00 2001 From: Albireo Date: Wed, 8 Jul 2015 22:40:57 +0200 Subject: [PATCH 05/18] Implement imgur middleware --- .../Imgur/ImgurAuthenticationHandler.cs | 21 +++++ .../Imgur/ImgurAuthenticationMiddleware.cs | 80 ++++++++++++++++++- 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs index b32f9f23..bf7dc6ae 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs @@ -1,13 +1,34 @@ namespace Owin.Security.Providers.Imgur { using System; + using System.Net.Http; using System.Threading.Tasks; + using Microsoft.Owin.Logging; using Microsoft.Owin.Security; using Microsoft.Owin.Security.Infrastructure; public class ImgurAuthenticationHandler : AuthenticationHandler { + private readonly HttpClient httpClient; + private readonly ILogger logger; + + public ImgurAuthenticationHandler(HttpClient httpClient, ILogger logger) + { + if (httpClient == null) + { + throw new ArgumentNullException("httpClient"); + } + + if (logger == null) + { + throw new ArgumentNullException("logger"); + } + + this.httpClient = httpClient; + this.logger = logger; + } + protected override Task AuthenticateCoreAsync() { throw new NotImplementedException(); diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs index 9e3ec028..cb32897b 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs @@ -1,17 +1,95 @@ namespace Owin.Security.Providers.Imgur { + using System; + using System.Globalization; + using System.Net.Http; + using Microsoft.Owin; + using Microsoft.Owin.Logging; + using Microsoft.Owin.Security; + using Microsoft.Owin.Security.DataHandler; + using Microsoft.Owin.Security.DataProtection; using Microsoft.Owin.Security.Infrastructure; + using Owin.Security.Providers.Imgur.Provider; + using Owin.Security.Providers.Properties; + public class ImgurAuthenticationMiddleware : AuthenticationMiddleware { + private readonly HttpClient httpClient; + private readonly ILogger logger; + + private readonly static string TypeFullName = typeof(ImgurAuthenticationMiddleware).FullName; + public ImgurAuthenticationMiddleware(OwinMiddleware next, IAppBuilder appBuilder, ImgurAuthenticationOptions options) : base(next, options) { + if (appBuilder == null) + { + throw new ArgumentNullException("appBuilder"); + } + + if (options == null) + { + throw new ArgumentNullException("options"); + } + + if (string.IsNullOrWhiteSpace(this.Options.ClientId)) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.Exception_OptionMustBeProvided, "ClientId"), "options"); + } + + if (string.IsNullOrWhiteSpace(this.Options.ClientSecret)) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.Exception_OptionMustBeProvided, "ClientSecret"), "options"); + } + + if (this.Options.Provider == null) + { + this.Options.Provider = new ImgurAuthenticationProvider(); + } + + if (string.IsNullOrWhiteSpace(this.Options.SignInAsAuthenticationType)) + { + this.Options.SignInAsAuthenticationType = appBuilder.GetDefaultSignInAsAuthenticationType(); + } + + if (this.Options.StateDataFormat == null) + { + var dataProtector = appBuilder.CreateDataProtector(TypeFullName, this.Options.AuthenticationType, "v1"); + + this.Options.StateDataFormat = new PropertiesDataFormat(dataProtector); + } + + var httpMessageHandler = ResolveHttpMessageHandler(this.Options); + + this.httpClient = new HttpClient(httpMessageHandler); + this.logger = appBuilder.CreateLogger(); } protected override AuthenticationHandler CreateHandler() { - return new ImgurAuthenticationHandler(); + return new ImgurAuthenticationHandler(this.httpClient, this.logger); + } + + private static HttpMessageHandler ResolveHttpMessageHandler(ImgurAuthenticationOptions options) + { + var httpMessageHandler = options.BackchannelHttpHandler ?? new WebRequestHandler(); + + if (options.BackchannelCertificateValidator == null) + { + return httpMessageHandler; + } + + var webRequestHandler = httpMessageHandler as WebRequestHandler; + + if (webRequestHandler == null) + { + throw new InvalidOperationException(Resources.Exception_ValidatorHandlerMismatch); + } + + webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate; + + return webRequestHandler; } } } From 702afe3288841cf273824fe041e906481b77b137 Mon Sep 17 00:00:00 2001 From: Albireo Date: Wed, 8 Jul 2015 23:38:36 +0200 Subject: [PATCH 06/18] Implement imgur authentication provider --- .../Imgur/Provider/ImgurAuthenticationProvider.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs index 412826f5..80445df9 100644 --- a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs +++ b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs @@ -5,14 +5,24 @@ public class ImgurAuthenticationProvider : IImgurAuthenticationProvider { + public ImgurAuthenticationProvider() + { + this.OnAuthenticated = context => Task.FromResult(null); + this.OnReturnEndpoint = context => Task.FromResult(null); + } + + public Func OnAuthenticated { get; set; } + + public Func OnReturnEndpoint { get; set; } + public Task Authenticated(ImgurAuthenticatedContext context) { - throw new NotImplementedException(); + return this.OnAuthenticated(context); } public Task ReturnEndpoint(ImgurReturnEndpointContext context) { - throw new NotImplementedException(); + return this.OnReturnEndpoint(context); } } } From f5f6cda67e41b3f2c155c38767ddb526f189f6fb Mon Sep 17 00:00:00 2001 From: Albireo Date: Wed, 8 Jul 2015 23:38:57 +0200 Subject: [PATCH 07/18] Fix imgur authentication options caption --- .../Imgur/ImgurAuthenticationOptions.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs index 6c01009e..e03a924f 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs @@ -26,7 +26,18 @@ public ImgurAuthenticationOptions() : base(ImgurAuthenticationDefaults.Authentic public PathString CallbackPath { get; set; } - public string Caption { get; set; } + public string Caption + { + get + { + return this.Description.Caption; + } + + set + { + this.Description.Caption = value; + } + } public string ClientId { get; set; } From dd9c4be1c3944ce0b4b7d6ef2d4b407a67531328 Mon Sep 17 00:00:00 2001 From: Albireo Date: Wed, 8 Jul 2015 23:39:16 +0200 Subject: [PATCH 08/18] Implement imgur authenticated context --- .../Provider/ImgurAuthenticatedContext.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs index ac2c8572..838fcc0c 100644 --- a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs +++ b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs @@ -1,6 +1,9 @@ namespace Owin.Security.Providers.Imgur.Provider { + using System.Security.Claims; + using Microsoft.Owin; + using Microsoft.Owin.Security; using Microsoft.Owin.Security.Provider; public class ImgurAuthenticatedContext : BaseContext @@ -8,5 +11,23 @@ public class ImgurAuthenticatedContext : BaseContext public ImgurAuthenticatedContext(IOwinContext context, ImgurAuthenticationOptions options) : base(context, options) { } + + public string AccessToken { get; set; } + + public int AccountId { get; set; } + + public string AccountUsername { get; set; } + + public int ExpiresIn { get; set; } + + public ClaimsIdentity Identity { get; set; } + + public AuthenticationProperties Properties { get; set; } + + public string RefreshToken { get; set; } + + public string Scope { get; set; } + + public string TokenType { get; set; } } } From a368381877c33b025e0cb9a812b0bbeaee885e39 Mon Sep 17 00:00:00 2001 From: Albireo Date: Wed, 8 Jul 2015 23:39:35 +0200 Subject: [PATCH 09/18] Implement imgur authentication handler --- .../Imgur/ImgurAuthenticationHandler.cs | 206 +++++++++++++++++- 1 file changed, 204 insertions(+), 2 deletions(-) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs index bf7dc6ae..839903cb 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs @@ -1,15 +1,26 @@ namespace Owin.Security.Providers.Imgur { using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; using System.Net.Http; + using System.Security.Claims; using System.Threading.Tasks; + using Microsoft.Owin.Infrastructure; using Microsoft.Owin.Logging; using Microsoft.Owin.Security; using Microsoft.Owin.Security.Infrastructure; + using Newtonsoft.Json; + + using Owin.Security.Providers.Imgur.Provider; + public class ImgurAuthenticationHandler : AuthenticationHandler { + private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; + private readonly HttpClient httpClient; private readonly ILogger logger; @@ -29,9 +40,200 @@ public ImgurAuthenticationHandler(HttpClient httpClient, ILogger logger) this.logger = logger; } - protected override Task AuthenticateCoreAsync() + protected override Task ApplyResponseChallengeAsync() + { + if (this.Response.StatusCode != 401) + { + return Task.FromResult(null); + } + + var challenge = this.Helper.LookupChallenge(this.Options.AuthenticationType, this.Options.AuthenticationMode); + + if (challenge == null) + { + return Task.FromResult(null); + } + + var currentUri = this.Request.Uri.AbsoluteUri; + + if (string.IsNullOrWhiteSpace(challenge.Properties.RedirectUri)) + { + challenge.Properties.RedirectUri = currentUri; + } + + this.GenerateCorrelationId(challenge.Properties); + + var state = this.Options.StateDataFormat.Protect(challenge.Properties); + + var authorizationUri = "https://api.imgur.com/oauth2/authorize"; + authorizationUri = WebUtilities.AddQueryString(authorizationUri, "client_id", Uri.EscapeDataString(this.Options.ClientId)); + authorizationUri = WebUtilities.AddQueryString(authorizationUri, "response_type", "code"); + authorizationUri = WebUtilities.AddQueryString(authorizationUri, "state", Uri.EscapeDataString(state)); + + this.Response.Redirect(authorizationUri); + + return Task.FromResult(null); + } + + protected override async Task AuthenticateCoreAsync() { - throw new NotImplementedException(); + var error = this.Request.Query.Get("error"); + + if (error != null) + { + if (error.Equals("access_denied", StringComparison.OrdinalIgnoreCase)) + { + this.logger.WriteInformation("User denied access."); + + return new AuthenticationTicket(null, null); + } + + this.logger.WriteInformation(string.Concat("Unknown authentication error: ", error)); + + return new AuthenticationTicket(null, null); + } + + var code = this.Request.Query.Get("code"); + var state = this.Request.Query.Get("state"); + var properties = this.Options.StateDataFormat.Unprotect(state); + + if (properties == null) + { + return new AuthenticationTicket(null, null); + } + + if (!this.ValidateCorrelationId(properties, this.logger)) + { + return new AuthenticationTicket(null, properties); + } + + AuthenticationResponse authenticationResponse; + + using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "https://api.imgur.com/oauth2/token")) + { + httpRequestMessage.Content = new FormUrlEncodedContent(new[] { new KeyValuePair("client_id", this.Options.ClientId), new KeyValuePair("client_secret", this.Options.ClientSecret), new KeyValuePair("grant_type", "authorization_code"), new KeyValuePair("code", code) }); + + using (var httpResponseMessage = await this.httpClient.SendAsync(httpRequestMessage, this.Request.CallCancelled)) + { + if (!httpResponseMessage.IsSuccessStatusCode) + { + throw new Exception(); // TODO + } + + using (var stream = await httpResponseMessage.Content.ReadAsStreamAsync()) + { + var jsonSerializer = new JsonSerializer(); + + using (var streamReader = new StreamReader(stream)) + { + using (var jsonTextReader = new JsonTextReader(streamReader)) + { + authenticationResponse = jsonSerializer.Deserialize(jsonTextReader); + } + } + } + } + } + + if (authenticationResponse == null) + { + throw new Exception(); // TODO + } + + var identity = new ClaimsIdentity(this.Options.AuthenticationType, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType); + identity.AddClaim(new Claim(ClaimTypes.Name, authenticationResponse.account_username, XmlSchemaString, this.Options.AuthenticationType)); + identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, authenticationResponse.account_id.ToString("D", CultureInfo.InvariantCulture), XmlSchemaString, this.Options.AuthenticationType)); + identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, authenticationResponse.account_username, XmlSchemaString, this.Options.AuthenticationType)); + + var context = new ImgurAuthenticatedContext(this.Context, this.Options); + context.AccessToken = authenticationResponse.access_token; + context.AccountId = authenticationResponse.account_id; + context.AccountUsername = authenticationResponse.account_username; + context.ExpiresIn = authenticationResponse.expires_in; + context.Identity = identity; + context.Properties = properties; + context.RefreshToken = authenticationResponse.refresh_token; + context.Scope = authenticationResponse.scope; + context.TokenType = authenticationResponse.token_type; + + await this.Options.Provider.Authenticated(context); + + return new AuthenticationTicket(context.Identity, context.Properties); + } + + public override async Task InvokeAsync() + { + if (!this.Options.CallbackPath.HasValue) + { + return false; + } + + if (!this.Options.CallbackPath.Value.Equals(this.Request.Path.Value, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + var ticket = await this.AuthenticateAsync(); + + if (ticket == null) + { + this.logger.WriteError("Invalid return state, unable to redirect."); + + throw new Exception("Invalid return state, unable to redirect."); + } + + var context = new ImgurReturnEndpointContext(this.Context, ticket); + context.SignInAsAuthenticationType = this.Options.SignInAsAuthenticationType; + context.RedirectUri = ticket.Properties.RedirectUri; + + await this.Options.Provider.ReturnEndpoint(context); + + if (context.SignInAsAuthenticationType != null && context.Identity != null) + { + var identity = context.Identity; + + if (!identity.AuthenticationType.Equals(context.SignInAsAuthenticationType, StringComparison.OrdinalIgnoreCase)) + { + identity = new ClaimsIdentity(identity.Claims, context.SignInAsAuthenticationType, identity.NameClaimType, identity.RoleClaimType); + } + + this.Context.Authentication.SignIn(context.Properties, identity); + } + + if (context.IsRequestCompleted || context.RedirectUri == null) + { + return context.IsRequestCompleted; + } + + var location = context.RedirectUri; + + if (context.Identity == null) + { + location = WebUtilities.AddQueryString(location, "error", "access_denied"); + } + + this.Response.Redirect(location); + + context.RequestCompleted(); + + return context.IsRequestCompleted; + } + + private class AuthenticationResponse + { + public string access_token { get; set; } + + public int expires_in { get; set; } + + public string token_type { get; set; } + + public string scope { get; set; } + + public string refresh_token { get; set; } + + public int account_id { get; set; } + + public string account_username { get; set; } } } } From f3c6458ec8fe9672e9cba923198d9fb631fd0a88 Mon Sep 17 00:00:00 2001 From: Albireo Date: Thu, 9 Jul 2015 00:01:07 +0200 Subject: [PATCH 10/18] Clean up code --- .../Imgur/ImgurAuthenticationHandler.cs | 66 ++++++++++--------- .../Imgur/ImgurAuthenticationMiddleware.cs | 3 +- .../Imgur/ImgurAuthenticationOptions.cs | 3 +- .../Provider/ImgurAuthenticatedContext.cs | 3 +- .../Provider/ImgurReturnEndpointContext.cs | 3 +- 5 files changed, 42 insertions(+), 36 deletions(-) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs index 839903cb..d16471a2 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs @@ -19,8 +19,6 @@ public class ImgurAuthenticationHandler : AuthenticationHandler { - private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; - private readonly HttpClient httpClient; private readonly ILogger logger; @@ -77,19 +75,8 @@ protected override Task ApplyResponseChallengeAsync() protected override async Task AuthenticateCoreAsync() { - var error = this.Request.Query.Get("error"); - - if (error != null) + if (this.Request.Query.Get("error") != null) { - if (error.Equals("access_denied", StringComparison.OrdinalIgnoreCase)) - { - this.logger.WriteInformation("User denied access."); - - return new AuthenticationTicket(null, null); - } - - this.logger.WriteInformation(string.Concat("Unknown authentication error: ", error)); - return new AuthenticationTicket(null, null); } @@ -111,7 +98,15 @@ protected override async Task AuthenticateCoreAsync() using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "https://api.imgur.com/oauth2/token")) { - httpRequestMessage.Content = new FormUrlEncodedContent(new[] { new KeyValuePair("client_id", this.Options.ClientId), new KeyValuePair("client_secret", this.Options.ClientSecret), new KeyValuePair("grant_type", "authorization_code"), new KeyValuePair("code", code) }); + httpRequestMessage.Content = + new FormUrlEncodedContent( + new [] + { + new KeyValuePair("client_id", this.Options.ClientId), + new KeyValuePair("client_secret", this.Options.ClientSecret), + new KeyValuePair("grant_type", "authorization_code"), + new KeyValuePair("code", code) + }); using (var httpResponseMessage = await this.httpClient.SendAsync(httpRequestMessage, this.Request.CallCancelled)) { @@ -141,20 +136,20 @@ protected override async Task AuthenticateCoreAsync() } var identity = new ClaimsIdentity(this.Options.AuthenticationType, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType); - identity.AddClaim(new Claim(ClaimTypes.Name, authenticationResponse.account_username, XmlSchemaString, this.Options.AuthenticationType)); - identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, authenticationResponse.account_id.ToString("D", CultureInfo.InvariantCulture), XmlSchemaString, this.Options.AuthenticationType)); - identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, authenticationResponse.account_username, XmlSchemaString, this.Options.AuthenticationType)); + identity.AddClaim(new Claim(ClaimTypes.Name, authenticationResponse.AccountUsername, "http://www.w3.org/2001/XMLSchema#string", this.Options.AuthenticationType)); + identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, authenticationResponse.AccountId.ToString("D", CultureInfo.InvariantCulture), "http://www.w3.org/2001/XMLSchema#string", this.Options.AuthenticationType)); + identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, authenticationResponse.AccountUsername, "http://www.w3.org/2001/XMLSchema#string", this.Options.AuthenticationType)); var context = new ImgurAuthenticatedContext(this.Context, this.Options); - context.AccessToken = authenticationResponse.access_token; - context.AccountId = authenticationResponse.account_id; - context.AccountUsername = authenticationResponse.account_username; - context.ExpiresIn = authenticationResponse.expires_in; + context.AccessToken = authenticationResponse.AccessToken; + context.AccountId = authenticationResponse.AccountId; + context.AccountUsername = authenticationResponse.AccountUsername; + context.ExpiresIn = authenticationResponse.ExpiresIn; context.Identity = identity; context.Properties = properties; - context.RefreshToken = authenticationResponse.refresh_token; - context.Scope = authenticationResponse.scope; - context.TokenType = authenticationResponse.token_type; + context.RefreshToken = authenticationResponse.RefreshToken; + context.Scope = authenticationResponse.Scope; + context.TokenType = authenticationResponse.TokenType; await this.Options.Provider.Authenticated(context); @@ -221,19 +216,26 @@ public override async Task InvokeAsync() private class AuthenticationResponse { - public string access_token { get; set; } + [JsonProperty(PropertyName = "access_token")] + public string AccessToken { get; set; } - public int expires_in { get; set; } + [JsonProperty(PropertyName = "account_id")] + public int AccountId { get; set; } - public string token_type { get; set; } + [JsonProperty(PropertyName = "account_username")] + public string AccountUsername { get; set; } - public string scope { get; set; } + [JsonProperty(PropertyName = "expires_in")] + public int ExpiresIn { get; set; } - public string refresh_token { get; set; } + [JsonProperty(PropertyName = "refresh_token")] + public string RefreshToken { get; set; } - public int account_id { get; set; } + [JsonProperty(PropertyName = "scope")] + public string Scope { get; set; } - public string account_username { get; set; } + [JsonProperty(PropertyName = "token_type")] + public string TokenType { get; set; } } } } diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs index cb32897b..78a285ff 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs @@ -21,7 +21,8 @@ public class ImgurAuthenticationMiddleware : AuthenticationMiddleware { - public ImgurAuthenticatedContext(IOwinContext context, ImgurAuthenticationOptions options) : base(context, options) + public ImgurAuthenticatedContext(IOwinContext context, ImgurAuthenticationOptions options) + : base(context, options) { } diff --git a/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs b/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs index 6db56e97..dfd689e3 100644 --- a/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs +++ b/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs @@ -6,7 +6,8 @@ public class ImgurReturnEndpointContext : ReturnEndpointContext { - public ImgurReturnEndpointContext(IOwinContext context, AuthenticationTicket ticket) : base(context, ticket) + public ImgurReturnEndpointContext(IOwinContext context, AuthenticationTicket ticket) + : base(context, ticket) { } } From fd02b65a129329b6a65c87703bc00daddfc45839 Mon Sep 17 00:00:00 2001 From: Albireo Date: Mon, 13 Jul 2015 18:32:55 +0200 Subject: [PATCH 11/18] Remove magic strings --- .../Imgur/ImgurAuthenticationDefaults.cs | 28 +++++++++- .../Imgur/ImgurAuthenticationHandler.cs | 54 +++++++++---------- .../Imgur/ImgurAuthenticationMiddleware.cs | 10 ++-- .../Imgur/ImgurAuthenticationOptions.cs | 2 +- 4 files changed, 61 insertions(+), 33 deletions(-) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs index 7c16387f..b7b8fddc 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs @@ -2,6 +2,32 @@ namespace Owin.Security.Providers.Imgur { internal static class ImgurAuthenticationDefaults { - public const string AuthenticationType = "Imgur"; + internal const string AccessDeniedErrorMessage = "access_denied"; + internal const string AccessTokenPropertyName = "access_token"; + internal const string AccountIdPropertyName = "account_id"; + internal const string AccountUsernamePropertyName = "account_username"; + internal const string AuthenticationType = "Imgur"; + internal const string AuthorizationCodeGrantType = "authorization_code"; + internal const string AuthorizationUri = "https://api.imgur.com/oauth2/authorize"; + internal const string CallbackPath = "/signin-imgur"; + internal const string ClientIdParameter = "client_id"; + internal const string ClientSecretParameter = "client_secret"; + internal const string CodeParameter = "code"; + internal const string CodeResponseType = "code"; + internal const string CommunicationFailureMessage = ""; // TODO + internal const string DeserializationFailureMessage = ""; // TODO + internal const string ErrorParameter = "error"; + internal const string ExpiresInPropertyName = "expires_in"; + internal const string GrantTypeParameter = "grant_type"; + internal const string Int32Format = "D"; + internal const string InvalidAuthenticationTicketMessage = ""; // TODO + internal const string RefreshInPropertyName = "refresh_token"; + internal const string ResponseTypeParameter = "response_type"; + internal const string ScopePropertyName = "scope"; + internal const string StateParameter = "state"; + internal const string TokenTypePropertyName = "token_type"; + internal const string TokenUri = "https://api.imgur.com/oauth2/token"; + internal const string Version = "v1"; + internal const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; } } diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs index d16471a2..c38d1d8e 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs @@ -63,10 +63,10 @@ protected override Task ApplyResponseChallengeAsync() var state = this.Options.StateDataFormat.Protect(challenge.Properties); - var authorizationUri = "https://api.imgur.com/oauth2/authorize"; - authorizationUri = WebUtilities.AddQueryString(authorizationUri, "client_id", Uri.EscapeDataString(this.Options.ClientId)); - authorizationUri = WebUtilities.AddQueryString(authorizationUri, "response_type", "code"); - authorizationUri = WebUtilities.AddQueryString(authorizationUri, "state", Uri.EscapeDataString(state)); + var authorizationUri = ImgurAuthenticationDefaults.AuthorizationUri; + authorizationUri = WebUtilities.AddQueryString(authorizationUri, ImgurAuthenticationDefaults.ClientIdParameter, Uri.EscapeDataString(this.Options.ClientId)); + authorizationUri = WebUtilities.AddQueryString(authorizationUri, ImgurAuthenticationDefaults.ResponseTypeParameter, ImgurAuthenticationDefaults.CodeResponseType); + authorizationUri = WebUtilities.AddQueryString(authorizationUri, ImgurAuthenticationDefaults.StateParameter, Uri.EscapeDataString(state)); this.Response.Redirect(authorizationUri); @@ -75,13 +75,13 @@ protected override Task ApplyResponseChallengeAsync() protected override async Task AuthenticateCoreAsync() { - if (this.Request.Query.Get("error") != null) + if (this.Request.Query.Get(ImgurAuthenticationDefaults.ErrorParameter) != null) { return new AuthenticationTicket(null, null); } - var code = this.Request.Query.Get("code"); - var state = this.Request.Query.Get("state"); + var code = this.Request.Query.Get(ImgurAuthenticationDefaults.CodeParameter); + var state = this.Request.Query.Get(ImgurAuthenticationDefaults.StateParameter); var properties = this.Options.StateDataFormat.Unprotect(state); if (properties == null) @@ -96,23 +96,23 @@ protected override async Task AuthenticateCoreAsync() AuthenticationResponse authenticationResponse; - using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "https://api.imgur.com/oauth2/token")) + using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, ImgurAuthenticationDefaults.TokenUri)) { httpRequestMessage.Content = new FormUrlEncodedContent( new [] { - new KeyValuePair("client_id", this.Options.ClientId), - new KeyValuePair("client_secret", this.Options.ClientSecret), - new KeyValuePair("grant_type", "authorization_code"), - new KeyValuePair("code", code) + new KeyValuePair(ImgurAuthenticationDefaults.ClientIdParameter, this.Options.ClientId), + new KeyValuePair(ImgurAuthenticationDefaults.ClientSecretParameter, this.Options.ClientSecret), + new KeyValuePair(ImgurAuthenticationDefaults.GrantTypeParameter, ImgurAuthenticationDefaults.AuthorizationCodeGrantType), + new KeyValuePair(ImgurAuthenticationDefaults.CodeParameter, code) }); using (var httpResponseMessage = await this.httpClient.SendAsync(httpRequestMessage, this.Request.CallCancelled)) { if (!httpResponseMessage.IsSuccessStatusCode) { - throw new Exception(); // TODO + throw new Exception(ImgurAuthenticationDefaults.CommunicationFailureMessage); } using (var stream = await httpResponseMessage.Content.ReadAsStreamAsync()) @@ -132,13 +132,13 @@ protected override async Task AuthenticateCoreAsync() if (authenticationResponse == null) { - throw new Exception(); // TODO + throw new Exception(ImgurAuthenticationDefaults.DeserializationFailureMessage); } var identity = new ClaimsIdentity(this.Options.AuthenticationType, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType); - identity.AddClaim(new Claim(ClaimTypes.Name, authenticationResponse.AccountUsername, "http://www.w3.org/2001/XMLSchema#string", this.Options.AuthenticationType)); - identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, authenticationResponse.AccountId.ToString("D", CultureInfo.InvariantCulture), "http://www.w3.org/2001/XMLSchema#string", this.Options.AuthenticationType)); - identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, authenticationResponse.AccountUsername, "http://www.w3.org/2001/XMLSchema#string", this.Options.AuthenticationType)); + identity.AddClaim(new Claim(ClaimTypes.Name, authenticationResponse.AccountUsername, ImgurAuthenticationDefaults.XmlSchemaString, this.Options.AuthenticationType)); + identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, authenticationResponse.AccountId.ToString(ImgurAuthenticationDefaults.Int32Format, CultureInfo.InvariantCulture), ImgurAuthenticationDefaults.XmlSchemaString, this.Options.AuthenticationType)); + identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, authenticationResponse.AccountUsername, ImgurAuthenticationDefaults.XmlSchemaString, this.Options.AuthenticationType)); var context = new ImgurAuthenticatedContext(this.Context, this.Options); context.AccessToken = authenticationResponse.AccessToken; @@ -172,9 +172,7 @@ public override async Task InvokeAsync() if (ticket == null) { - this.logger.WriteError("Invalid return state, unable to redirect."); - - throw new Exception("Invalid return state, unable to redirect."); + throw new Exception(ImgurAuthenticationDefaults.InvalidAuthenticationTicketMessage); } var context = new ImgurReturnEndpointContext(this.Context, ticket); @@ -204,7 +202,7 @@ public override async Task InvokeAsync() if (context.Identity == null) { - location = WebUtilities.AddQueryString(location, "error", "access_denied"); + location = WebUtilities.AddQueryString(location, ImgurAuthenticationDefaults.ErrorParameter, ImgurAuthenticationDefaults.AccessDeniedErrorMessage); } this.Response.Redirect(location); @@ -216,25 +214,25 @@ public override async Task InvokeAsync() private class AuthenticationResponse { - [JsonProperty(PropertyName = "access_token")] + [JsonProperty(PropertyName = ImgurAuthenticationDefaults.AccessTokenPropertyName)] public string AccessToken { get; set; } - [JsonProperty(PropertyName = "account_id")] + [JsonProperty(PropertyName = ImgurAuthenticationDefaults.AccountIdPropertyName)] public int AccountId { get; set; } - [JsonProperty(PropertyName = "account_username")] + [JsonProperty(PropertyName = ImgurAuthenticationDefaults.AccountUsernamePropertyName)] public string AccountUsername { get; set; } - [JsonProperty(PropertyName = "expires_in")] + [JsonProperty(PropertyName = ImgurAuthenticationDefaults.ExpiresInPropertyName)] public int ExpiresIn { get; set; } - [JsonProperty(PropertyName = "refresh_token")] + [JsonProperty(PropertyName = ImgurAuthenticationDefaults.RefreshInPropertyName)] public string RefreshToken { get; set; } - [JsonProperty(PropertyName = "scope")] + [JsonProperty(PropertyName = ImgurAuthenticationDefaults.ScopePropertyName)] public string Scope { get; set; } - [JsonProperty(PropertyName = "token_type")] + [JsonProperty(PropertyName = ImgurAuthenticationDefaults.TokenTypePropertyName)] public string TokenType { get; set; } } } diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs index 78a285ff..0f9ec7b4 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs @@ -36,12 +36,16 @@ public ImgurAuthenticationMiddleware(OwinMiddleware next, IAppBuilder appBuilder if (string.IsNullOrWhiteSpace(this.Options.ClientId)) { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.Exception_OptionMustBeProvided, "ClientId"), "options"); + var message = string.Format(CultureInfo.InvariantCulture, Resources.Exception_OptionMustBeProvided, "ClientId"); + + throw new ArgumentException(message, "options"); } if (string.IsNullOrWhiteSpace(this.Options.ClientSecret)) { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.Exception_OptionMustBeProvided, "ClientSecret"), "options"); + var message = string.Format(CultureInfo.InvariantCulture, Resources.Exception_OptionMustBeProvided, "ClientSecret"); + + throw new ArgumentException(message, "options"); } if (this.Options.Provider == null) @@ -56,7 +60,7 @@ public ImgurAuthenticationMiddleware(OwinMiddleware next, IAppBuilder appBuilder if (this.Options.StateDataFormat == null) { - var dataProtector = appBuilder.CreateDataProtector(TypeFullName, this.Options.AuthenticationType, "v1"); + var dataProtector = appBuilder.CreateDataProtector(TypeFullName, this.Options.AuthenticationType, ImgurAuthenticationDefaults.Version); this.Options.StateDataFormat = new PropertiesDataFormat(dataProtector); } diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs index a4a98e5c..33c358dc 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs @@ -15,7 +15,7 @@ public ImgurAuthenticationOptions() { this.AuthenticationMode = AuthenticationMode.Passive; this.BackchannelTimeout = TimeSpan.FromSeconds(60); - this.CallbackPath = new PathString("/signin-imgur"); + this.CallbackPath = new PathString(ImgurAuthenticationDefaults.CallbackPath); this.Caption = ImgurAuthenticationDefaults.AuthenticationType; } From 857afa28bc9687c8af04c6e85ed5e1107777285f Mon Sep 17 00:00:00 2001 From: Albireo Date: Mon, 13 Jul 2015 18:38:30 +0200 Subject: [PATCH 12/18] Reformat code --- .../Imgur/ImgurAuthenticationHandler.cs | 83 ++++++++++++++++--- .../Imgur/ImgurAuthenticationMiddleware.cs | 18 +++- 2 files changed, 85 insertions(+), 16 deletions(-) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs index c38d1d8e..331e20a8 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs @@ -64,9 +64,24 @@ protected override Task ApplyResponseChallengeAsync() var state = this.Options.StateDataFormat.Protect(challenge.Properties); var authorizationUri = ImgurAuthenticationDefaults.AuthorizationUri; - authorizationUri = WebUtilities.AddQueryString(authorizationUri, ImgurAuthenticationDefaults.ClientIdParameter, Uri.EscapeDataString(this.Options.ClientId)); - authorizationUri = WebUtilities.AddQueryString(authorizationUri, ImgurAuthenticationDefaults.ResponseTypeParameter, ImgurAuthenticationDefaults.CodeResponseType); - authorizationUri = WebUtilities.AddQueryString(authorizationUri, ImgurAuthenticationDefaults.StateParameter, Uri.EscapeDataString(state)); + + authorizationUri = + WebUtilities.AddQueryString( + authorizationUri, + ImgurAuthenticationDefaults.ClientIdParameter, + Uri.EscapeDataString(this.Options.ClientId)); + + authorizationUri = + WebUtilities.AddQueryString( + authorizationUri, + ImgurAuthenticationDefaults.ResponseTypeParameter, + ImgurAuthenticationDefaults.CodeResponseType); + + authorizationUri = + WebUtilities.AddQueryString( + authorizationUri, + ImgurAuthenticationDefaults.StateParameter, + Uri.EscapeDataString(state)); this.Response.Redirect(authorizationUri); @@ -102,10 +117,21 @@ protected override async Task AuthenticateCoreAsync() new FormUrlEncodedContent( new [] { - new KeyValuePair(ImgurAuthenticationDefaults.ClientIdParameter, this.Options.ClientId), - new KeyValuePair(ImgurAuthenticationDefaults.ClientSecretParameter, this.Options.ClientSecret), - new KeyValuePair(ImgurAuthenticationDefaults.GrantTypeParameter, ImgurAuthenticationDefaults.AuthorizationCodeGrantType), - new KeyValuePair(ImgurAuthenticationDefaults.CodeParameter, code) + new KeyValuePair( + ImgurAuthenticationDefaults.ClientIdParameter, + this.Options.ClientId), + + new KeyValuePair( + ImgurAuthenticationDefaults.ClientSecretParameter, + this.Options.ClientSecret), + + new KeyValuePair( + ImgurAuthenticationDefaults.GrantTypeParameter, + ImgurAuthenticationDefaults.AuthorizationCodeGrantType), + + new KeyValuePair( + ImgurAuthenticationDefaults.CodeParameter, + code) }); using (var httpResponseMessage = await this.httpClient.SendAsync(httpRequestMessage, this.Request.CallCancelled)) @@ -135,10 +161,32 @@ protected override async Task AuthenticateCoreAsync() throw new Exception(ImgurAuthenticationDefaults.DeserializationFailureMessage); } - var identity = new ClaimsIdentity(this.Options.AuthenticationType, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType); - identity.AddClaim(new Claim(ClaimTypes.Name, authenticationResponse.AccountUsername, ImgurAuthenticationDefaults.XmlSchemaString, this.Options.AuthenticationType)); - identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, authenticationResponse.AccountId.ToString(ImgurAuthenticationDefaults.Int32Format, CultureInfo.InvariantCulture), ImgurAuthenticationDefaults.XmlSchemaString, this.Options.AuthenticationType)); - identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, authenticationResponse.AccountUsername, ImgurAuthenticationDefaults.XmlSchemaString, this.Options.AuthenticationType)); + var identity = + new ClaimsIdentity( + this.Options.AuthenticationType, + ClaimsIdentity.DefaultNameClaimType, + ClaimsIdentity.DefaultRoleClaimType); + + identity.AddClaim( + new Claim( + ClaimTypes.Name, + authenticationResponse.AccountUsername, + ImgurAuthenticationDefaults.XmlSchemaString, + this.Options.AuthenticationType)); + + identity.AddClaim( + new Claim( + ClaimTypes.NameIdentifier, + authenticationResponse.AccountId.ToString(ImgurAuthenticationDefaults.Int32Format, CultureInfo.InvariantCulture), + ImgurAuthenticationDefaults.XmlSchemaString, + this.Options.AuthenticationType)); + + identity.AddClaim( + new Claim( + ClaimsIdentity.DefaultNameClaimType, + authenticationResponse.AccountUsername, + ImgurAuthenticationDefaults.XmlSchemaString, + this.Options.AuthenticationType)); var context = new ImgurAuthenticatedContext(this.Context, this.Options); context.AccessToken = authenticationResponse.AccessToken; @@ -187,7 +235,12 @@ public override async Task InvokeAsync() if (!identity.AuthenticationType.Equals(context.SignInAsAuthenticationType, StringComparison.OrdinalIgnoreCase)) { - identity = new ClaimsIdentity(identity.Claims, context.SignInAsAuthenticationType, identity.NameClaimType, identity.RoleClaimType); + identity = + new ClaimsIdentity( + identity.Claims, + context.SignInAsAuthenticationType, + identity.NameClaimType, + identity.RoleClaimType); } this.Context.Authentication.SignIn(context.Properties, identity); @@ -202,7 +255,11 @@ public override async Task InvokeAsync() if (context.Identity == null) { - location = WebUtilities.AddQueryString(location, ImgurAuthenticationDefaults.ErrorParameter, ImgurAuthenticationDefaults.AccessDeniedErrorMessage); + location = + WebUtilities.AddQueryString( + location, + ImgurAuthenticationDefaults.ErrorParameter, + ImgurAuthenticationDefaults.AccessDeniedErrorMessage); } this.Response.Redirect(location); diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs index 0f9ec7b4..862b38fb 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs @@ -36,14 +36,22 @@ public ImgurAuthenticationMiddleware(OwinMiddleware next, IAppBuilder appBuilder if (string.IsNullOrWhiteSpace(this.Options.ClientId)) { - var message = string.Format(CultureInfo.InvariantCulture, Resources.Exception_OptionMustBeProvided, "ClientId"); + var message = + string.Format( + CultureInfo.InvariantCulture, + Resources.Exception_OptionMustBeProvided, + "ClientId"); throw new ArgumentException(message, "options"); } if (string.IsNullOrWhiteSpace(this.Options.ClientSecret)) { - var message = string.Format(CultureInfo.InvariantCulture, Resources.Exception_OptionMustBeProvided, "ClientSecret"); + var message = + string.Format( + CultureInfo.InvariantCulture, + Resources.Exception_OptionMustBeProvided, + "ClientSecret"); throw new ArgumentException(message, "options"); } @@ -60,7 +68,11 @@ public ImgurAuthenticationMiddleware(OwinMiddleware next, IAppBuilder appBuilder if (this.Options.StateDataFormat == null) { - var dataProtector = appBuilder.CreateDataProtector(TypeFullName, this.Options.AuthenticationType, ImgurAuthenticationDefaults.Version); + var dataProtector = + appBuilder.CreateDataProtector( + TypeFullName, + this.Options.AuthenticationType, + ImgurAuthenticationDefaults.Version); this.Options.StateDataFormat = new PropertiesDataFormat(dataProtector); } From 3f8adc48a81c644c5b879715fa88e66b626618cc Mon Sep 17 00:00:00 2001 From: Albireo Date: Mon, 13 Jul 2015 18:50:04 +0200 Subject: [PATCH 13/18] Add exceptions messages --- .../Imgur/ImgurAuthenticationDefaults.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs index b7b8fddc..d3a40698 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs @@ -14,13 +14,13 @@ internal static class ImgurAuthenticationDefaults internal const string ClientSecretParameter = "client_secret"; internal const string CodeParameter = "code"; internal const string CodeResponseType = "code"; - internal const string CommunicationFailureMessage = ""; // TODO - internal const string DeserializationFailureMessage = ""; // TODO + internal const string CommunicationFailureMessage = "An error occurred while talking with imgur's server."; + internal const string DeserializationFailureMessage = "The deserialization of the imgur's response failed. Perhaps imgur changed the response format?"; internal const string ErrorParameter = "error"; internal const string ExpiresInPropertyName = "expires_in"; internal const string GrantTypeParameter = "grant_type"; internal const string Int32Format = "D"; - internal const string InvalidAuthenticationTicketMessage = ""; // TODO + internal const string InvalidAuthenticationTicketMessage = "Invalid authentication ticket."; internal const string RefreshInPropertyName = "refresh_token"; internal const string ResponseTypeParameter = "response_type"; internal const string ScopePropertyName = "scope"; From 46a06e6844df3339f9580bd965a712c12f14add1 Mon Sep 17 00:00:00 2001 From: Albireo Date: Mon, 13 Jul 2015 18:50:24 +0200 Subject: [PATCH 14/18] Add XML documentation markup --- .../Imgur/ImgurAuthenticationDefaults.cs | 54 +++++++++++++++++++ .../Imgur/ImgurAuthenticationExtensions.cs | 5 ++ .../Imgur/ImgurAuthenticationHandler.cs | 18 +++++++ .../Imgur/ImgurAuthenticationMiddleware.cs | 10 ++++ .../Imgur/ImgurAuthenticationOptions.cs | 12 +++++ .../Provider/IImgurAuthenticationProvider.cs | 7 +++ .../Provider/ImgurAuthenticatedContext.cs | 13 +++++ .../Provider/ImgurAuthenticationProvider.cs | 10 ++++ .../Provider/ImgurReturnEndpointContext.cs | 4 ++ 9 files changed, 133 insertions(+) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs index d3a40698..b585d8a7 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs @@ -1,33 +1,87 @@ namespace Owin.Security.Providers.Imgur { + /// internal static class ImgurAuthenticationDefaults { + /// internal const string AccessDeniedErrorMessage = "access_denied"; + + /// internal const string AccessTokenPropertyName = "access_token"; + + /// internal const string AccountIdPropertyName = "account_id"; + + /// internal const string AccountUsernamePropertyName = "account_username"; + + /// internal const string AuthenticationType = "Imgur"; + + /// internal const string AuthorizationCodeGrantType = "authorization_code"; + + /// internal const string AuthorizationUri = "https://api.imgur.com/oauth2/authorize"; + + /// internal const string CallbackPath = "/signin-imgur"; + + /// internal const string ClientIdParameter = "client_id"; + + /// internal const string ClientSecretParameter = "client_secret"; + + /// internal const string CodeParameter = "code"; + + /// internal const string CodeResponseType = "code"; + + /// internal const string CommunicationFailureMessage = "An error occurred while talking with imgur's server."; + + /// internal const string DeserializationFailureMessage = "The deserialization of the imgur's response failed. Perhaps imgur changed the response format?"; + + /// internal const string ErrorParameter = "error"; + + /// internal const string ExpiresInPropertyName = "expires_in"; + + /// internal const string GrantTypeParameter = "grant_type"; + + /// internal const string Int32Format = "D"; + + /// internal const string InvalidAuthenticationTicketMessage = "Invalid authentication ticket."; + + /// internal const string RefreshInPropertyName = "refresh_token"; + + /// internal const string ResponseTypeParameter = "response_type"; + + /// internal const string ScopePropertyName = "scope"; + + /// internal const string StateParameter = "state"; + + /// internal const string TokenTypePropertyName = "token_type"; + + /// internal const string TokenUri = "https://api.imgur.com/oauth2/token"; + + /// internal const string Version = "v1"; + + /// internal const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; } } diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationExtensions.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationExtensions.cs index b9059ab9..ebc3a78d 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationExtensions.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationExtensions.cs @@ -1,7 +1,12 @@ namespace Owin.Security.Providers.Imgur { + /// public static class ImgurAuthenticationExtensions { + /// + /// + /// + /// public static IAppBuilder UseImgurAuthentication(this IAppBuilder appBuilder, ImgurAuthenticationOptions options) { return appBuilder.Use(appBuilder, options); diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs index 331e20a8..27ef6686 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs @@ -17,11 +17,15 @@ using Owin.Security.Providers.Imgur.Provider; + /// public class ImgurAuthenticationHandler : AuthenticationHandler { private readonly HttpClient httpClient; private readonly ILogger logger; + /// + /// + /// public ImgurAuthenticationHandler(HttpClient httpClient, ILogger logger) { if (httpClient == null) @@ -38,6 +42,8 @@ public ImgurAuthenticationHandler(HttpClient httpClient, ILogger logger) this.logger = logger; } + /// + /// protected override Task ApplyResponseChallengeAsync() { if (this.Response.StatusCode != 401) @@ -88,6 +94,8 @@ protected override Task ApplyResponseChallengeAsync() return Task.FromResult(null); } + /// + /// protected override async Task AuthenticateCoreAsync() { if (this.Request.Query.Get(ImgurAuthenticationDefaults.ErrorParameter) != null) @@ -204,6 +212,8 @@ protected override async Task AuthenticateCoreAsync() return new AuthenticationTicket(context.Identity, context.Properties); } + /// + /// public override async Task InvokeAsync() { if (!this.Options.CallbackPath.HasValue) @@ -269,26 +279,34 @@ public override async Task InvokeAsync() return context.IsRequestCompleted; } + /// private class AuthenticationResponse { + /// [JsonProperty(PropertyName = ImgurAuthenticationDefaults.AccessTokenPropertyName)] public string AccessToken { get; set; } + /// [JsonProperty(PropertyName = ImgurAuthenticationDefaults.AccountIdPropertyName)] public int AccountId { get; set; } + /// [JsonProperty(PropertyName = ImgurAuthenticationDefaults.AccountUsernamePropertyName)] public string AccountUsername { get; set; } + /// [JsonProperty(PropertyName = ImgurAuthenticationDefaults.ExpiresInPropertyName)] public int ExpiresIn { get; set; } + /// [JsonProperty(PropertyName = ImgurAuthenticationDefaults.RefreshInPropertyName)] public string RefreshToken { get; set; } + /// [JsonProperty(PropertyName = ImgurAuthenticationDefaults.ScopePropertyName)] public string Scope { get; set; } + /// [JsonProperty(PropertyName = ImgurAuthenticationDefaults.TokenTypePropertyName)] public string TokenType { get; set; } } diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs index 862b38fb..964a6a41 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs @@ -14,6 +14,7 @@ using Owin.Security.Providers.Imgur.Provider; using Owin.Security.Providers.Properties; + /// public class ImgurAuthenticationMiddleware : AuthenticationMiddleware { private readonly HttpClient httpClient; @@ -21,6 +22,10 @@ public class ImgurAuthenticationMiddleware : AuthenticationMiddleware + /// + /// + /// public ImgurAuthenticationMiddleware(OwinMiddleware next, IAppBuilder appBuilder, ImgurAuthenticationOptions options) : base(next, options) { @@ -83,11 +88,16 @@ public ImgurAuthenticationMiddleware(OwinMiddleware next, IAppBuilder appBuilder this.logger = appBuilder.CreateLogger(); } + /// + /// protected override AuthenticationHandler CreateHandler() { return new ImgurAuthenticationHandler(this.httpClient, this.logger); } + /// + /// + /// private static HttpMessageHandler ResolveHttpMessageHandler(ImgurAuthenticationOptions options) { var httpMessageHandler = options.BackchannelHttpHandler ?? new WebRequestHandler(); diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs index 33c358dc..c9563080 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs @@ -8,8 +8,10 @@ using Owin.Security.Providers.Imgur.Provider; + /// public class ImgurAuthenticationOptions : AuthenticationOptions { + /// public ImgurAuthenticationOptions() : base(ImgurAuthenticationDefaults.AuthenticationType) { @@ -19,14 +21,19 @@ public ImgurAuthenticationOptions() this.Caption = ImgurAuthenticationDefaults.AuthenticationType; } + /// public ICertificateValidator BackchannelCertificateValidator { get; set; } + /// public HttpMessageHandler BackchannelHttpHandler { get; set; } + /// public TimeSpan BackchannelTimeout { get; set; } + /// public PathString CallbackPath { get; set; } + /// public string Caption { get @@ -40,14 +47,19 @@ public string Caption } } + /// public string ClientId { get; set; } + /// public string ClientSecret { get; set; } + /// public IImgurAuthenticationProvider Provider { get; set; } + /// public string SignInAsAuthenticationType { get; set; } + /// public ISecureDataFormat StateDataFormat { get; set; } } } diff --git a/Owin.Security.Providers/Imgur/Provider/IImgurAuthenticationProvider.cs b/Owin.Security.Providers/Imgur/Provider/IImgurAuthenticationProvider.cs index 71cf4cb8..7786870a 100644 --- a/Owin.Security.Providers/Imgur/Provider/IImgurAuthenticationProvider.cs +++ b/Owin.Security.Providers/Imgur/Provider/IImgurAuthenticationProvider.cs @@ -2,10 +2,17 @@ { using System.Threading.Tasks; + /// public interface IImgurAuthenticationProvider { + /// + /// + /// Task Authenticated(ImgurAuthenticatedContext context); + /// + /// + /// Task ReturnEndpoint(ImgurReturnEndpointContext context); } } diff --git a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs index d29f0c86..56bd148a 100644 --- a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs +++ b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs @@ -6,29 +6,42 @@ using Microsoft.Owin.Security; using Microsoft.Owin.Security.Provider; + /// public class ImgurAuthenticatedContext : BaseContext { + /// + /// + /// public ImgurAuthenticatedContext(IOwinContext context, ImgurAuthenticationOptions options) : base(context, options) { } + /// public string AccessToken { get; set; } + /// public int AccountId { get; set; } + /// public string AccountUsername { get; set; } + /// public int ExpiresIn { get; set; } + /// public ClaimsIdentity Identity { get; set; } + /// public AuthenticationProperties Properties { get; set; } + /// public string RefreshToken { get; set; } + /// public string Scope { get; set; } + /// public string TokenType { get; set; } } } diff --git a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs index 80445df9..7ffadf43 100644 --- a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs +++ b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs @@ -3,23 +3,33 @@ using System; using System.Threading.Tasks; + /// public class ImgurAuthenticationProvider : IImgurAuthenticationProvider { + /// public ImgurAuthenticationProvider() { this.OnAuthenticated = context => Task.FromResult(null); this.OnReturnEndpoint = context => Task.FromResult(null); } + /// public Func OnAuthenticated { get; set; } + /// public Func OnReturnEndpoint { get; set; } + /// + /// + /// public Task Authenticated(ImgurAuthenticatedContext context) { return this.OnAuthenticated(context); } + /// + /// + /// public Task ReturnEndpoint(ImgurReturnEndpointContext context) { return this.OnReturnEndpoint(context); diff --git a/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs b/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs index dfd689e3..41b697d0 100644 --- a/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs +++ b/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs @@ -4,8 +4,12 @@ using Microsoft.Owin.Security; using Microsoft.Owin.Security.Provider; + /// public class ImgurReturnEndpointContext : ReturnEndpointContext { + /// + /// + /// public ImgurReturnEndpointContext(IOwinContext context, AuthenticationTicket ticket) : base(context, ticket) { From 912ad402d2939a777c72c9cc054c251b34747358 Mon Sep 17 00:00:00 2001 From: Albireo Date: Mon, 13 Jul 2015 19:05:08 +0200 Subject: [PATCH 15/18] Refactor code --- .../Imgur/ImgurAuthenticationHandler.cs | 270 +++++++++++------- .../Imgur/ImgurAuthenticationMiddleware.cs | 110 ++++--- 2 files changed, 244 insertions(+), 136 deletions(-) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs index 27ef6686..7422adb7 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs @@ -58,36 +58,15 @@ protected override Task ApplyResponseChallengeAsync() return Task.FromResult(null); } - var currentUri = this.Request.Uri.AbsoluteUri; - if (string.IsNullOrWhiteSpace(challenge.Properties.RedirectUri)) { - challenge.Properties.RedirectUri = currentUri; + challenge.Properties.RedirectUri = this.Request.Uri.AbsoluteUri; } this.GenerateCorrelationId(challenge.Properties); var state = this.Options.StateDataFormat.Protect(challenge.Properties); - - var authorizationUri = ImgurAuthenticationDefaults.AuthorizationUri; - - authorizationUri = - WebUtilities.AddQueryString( - authorizationUri, - ImgurAuthenticationDefaults.ClientIdParameter, - Uri.EscapeDataString(this.Options.ClientId)); - - authorizationUri = - WebUtilities.AddQueryString( - authorizationUri, - ImgurAuthenticationDefaults.ResponseTypeParameter, - ImgurAuthenticationDefaults.CodeResponseType); - - authorizationUri = - WebUtilities.AddQueryString( - authorizationUri, - ImgurAuthenticationDefaults.StateParameter, - Uri.EscapeDataString(state)); + var authorizationUri = this.GetAuthorizationUri(state); this.Response.Redirect(authorizationUri); @@ -117,30 +96,121 @@ protected override async Task AuthenticateCoreAsync() return new AuthenticationTicket(null, properties); } - AuthenticationResponse authenticationResponse; + var authenticationResponse = await this.GetAuthenticationResponse(code); - using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, ImgurAuthenticationDefaults.TokenUri)) + if (authenticationResponse == null) { - httpRequestMessage.Content = - new FormUrlEncodedContent( - new [] - { - new KeyValuePair( - ImgurAuthenticationDefaults.ClientIdParameter, - this.Options.ClientId), + throw new Exception(ImgurAuthenticationDefaults.DeserializationFailureMessage); + } - new KeyValuePair( - ImgurAuthenticationDefaults.ClientSecretParameter, - this.Options.ClientSecret), + var identity = this.GetIdentity(authenticationResponse); + var context = this.GetImgurAuthenticatedContext(authenticationResponse, identity, properties); - new KeyValuePair( - ImgurAuthenticationDefaults.GrantTypeParameter, - ImgurAuthenticationDefaults.AuthorizationCodeGrantType), + await this.Options.Provider.Authenticated(context); - new KeyValuePair( - ImgurAuthenticationDefaults.CodeParameter, - code) - }); + return new AuthenticationTicket(context.Identity, context.Properties); + } + + /// + /// + public override async Task InvokeAsync() + { + if (!this.Options.CallbackPath.HasValue) + { + return false; + } + + if (!this.Options.CallbackPath.Value.Equals(this.Request.Path.Value, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + var ticket = await this.AuthenticateAsync(); + + if (ticket == null) + { + throw new Exception(ImgurAuthenticationDefaults.InvalidAuthenticationTicketMessage); + } + + var context = this.GetImgurReturnEndpointContext(ticket); + + await this.Options.Provider.ReturnEndpoint(context); + + this.SignIn(context); + + if (context.IsRequestCompleted || context.RedirectUri == null) + { + return context.IsRequestCompleted; + } + + var location = GetRedirectLocation(context); + + this.Response.Redirect(location); + + context.RequestCompleted(); + + return context.IsRequestCompleted; + } + + /// + /// + private void SignIn(ImgurReturnEndpointContext context) + { + if (context.SignInAsAuthenticationType == null || context.Identity == null) + { + return; + } + + var identity = context.Identity; + + if (!identity.AuthenticationType.Equals(context.SignInAsAuthenticationType, StringComparison.OrdinalIgnoreCase)) + { + identity = + new ClaimsIdentity( + identity.Claims, + context.SignInAsAuthenticationType, + identity.NameClaimType, + identity.RoleClaimType); + } + + this.Context.Authentication.SignIn(context.Properties, identity); + } + + /// + /// + /// + private HttpContent GetAuthenticationRequestContent(string code) + { + return + new FormUrlEncodedContent( + new[] + { + new KeyValuePair( + ImgurAuthenticationDefaults.ClientIdParameter, + this.Options.ClientId), + + new KeyValuePair( + ImgurAuthenticationDefaults.ClientSecretParameter, + this.Options.ClientSecret), + + new KeyValuePair( + ImgurAuthenticationDefaults.GrantTypeParameter, + ImgurAuthenticationDefaults.AuthorizationCodeGrantType), + + new KeyValuePair( + ImgurAuthenticationDefaults.CodeParameter, + code) + }); + } + + /// + /// + /// + private async Task GetAuthenticationResponse(string code) + { + using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, ImgurAuthenticationDefaults.TokenUri)) + { + httpRequestMessage.Content = this.GetAuthenticationRequestContent(code); using (var httpResponseMessage = await this.httpClient.SendAsync(httpRequestMessage, this.Request.CallCancelled)) { @@ -157,18 +227,47 @@ protected override async Task AuthenticateCoreAsync() { using (var jsonTextReader = new JsonTextReader(streamReader)) { - authenticationResponse = jsonSerializer.Deserialize(jsonTextReader); + return jsonSerializer.Deserialize(jsonTextReader); } } } } } + } - if (authenticationResponse == null) - { - throw new Exception(ImgurAuthenticationDefaults.DeserializationFailureMessage); - } + /// + /// + /// + private string GetAuthorizationUri(string state) + { + var authorizationUri = ImgurAuthenticationDefaults.AuthorizationUri; + + authorizationUri = + WebUtilities.AddQueryString( + authorizationUri, + ImgurAuthenticationDefaults.ClientIdParameter, + Uri.EscapeDataString(this.Options.ClientId)); + + authorizationUri = + WebUtilities.AddQueryString( + authorizationUri, + ImgurAuthenticationDefaults.ResponseTypeParameter, + ImgurAuthenticationDefaults.CodeResponseType); + authorizationUri = + WebUtilities.AddQueryString( + authorizationUri, + ImgurAuthenticationDefaults.StateParameter, + Uri.EscapeDataString(state)); + + return authorizationUri; + } + + /// + /// + /// + private ClaimsIdentity GetIdentity(AuthenticationResponse authenticationResponse) + { var identity = new ClaimsIdentity( this.Options.AuthenticationType, @@ -196,6 +295,16 @@ protected override async Task AuthenticateCoreAsync() ImgurAuthenticationDefaults.XmlSchemaString, this.Options.AuthenticationType)); + return identity; + } + + /// + /// + /// + /// + /// + private ImgurAuthenticatedContext GetImgurAuthenticatedContext(AuthenticationResponse authenticationResponse, ClaimsIdentity identity, AuthenticationProperties properties) + { var context = new ImgurAuthenticatedContext(this.Context, this.Options); context.AccessToken = authenticationResponse.AccessToken; context.AccountId = authenticationResponse.AccountId; @@ -207,76 +316,37 @@ protected override async Task AuthenticateCoreAsync() context.Scope = authenticationResponse.Scope; context.TokenType = authenticationResponse.TokenType; - await this.Options.Provider.Authenticated(context); - - return new AuthenticationTicket(context.Identity, context.Properties); + return context; } /// + /// /// - public override async Task InvokeAsync() + private ImgurReturnEndpointContext GetImgurReturnEndpointContext(AuthenticationTicket ticket) { - if (!this.Options.CallbackPath.HasValue) - { - return false; - } - - if (!this.Options.CallbackPath.Value.Equals(this.Request.Path.Value, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - var ticket = await this.AuthenticateAsync(); - - if (ticket == null) - { - throw new Exception(ImgurAuthenticationDefaults.InvalidAuthenticationTicketMessage); - } - var context = new ImgurReturnEndpointContext(this.Context, ticket); context.SignInAsAuthenticationType = this.Options.SignInAsAuthenticationType; context.RedirectUri = ticket.Properties.RedirectUri; - await this.Options.Provider.ReturnEndpoint(context); - - if (context.SignInAsAuthenticationType != null && context.Identity != null) - { - var identity = context.Identity; - - if (!identity.AuthenticationType.Equals(context.SignInAsAuthenticationType, StringComparison.OrdinalIgnoreCase)) - { - identity = - new ClaimsIdentity( - identity.Claims, - context.SignInAsAuthenticationType, - identity.NameClaimType, - identity.RoleClaimType); - } - - this.Context.Authentication.SignIn(context.Properties, identity); - } - - if (context.IsRequestCompleted || context.RedirectUri == null) - { - return context.IsRequestCompleted; - } + return context; + } + /// + /// + /// + private static string GetRedirectLocation(ImgurReturnEndpointContext context) + { var location = context.RedirectUri; if (context.Identity == null) { location = WebUtilities.AddQueryString( - location, - ImgurAuthenticationDefaults.ErrorParameter, - ImgurAuthenticationDefaults.AccessDeniedErrorMessage); + location, + ImgurAuthenticationDefaults.ErrorParameter, + ImgurAuthenticationDefaults.AccessDeniedErrorMessage); } - - this.Response.Redirect(location); - - context.RequestCompleted(); - - return context.IsRequestCompleted; + return location; } /// diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs index 964a6a41..46df6f60 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs @@ -39,60 +39,98 @@ public ImgurAuthenticationMiddleware(OwinMiddleware next, IAppBuilder appBuilder throw new ArgumentNullException("options"); } - if (string.IsNullOrWhiteSpace(this.Options.ClientId)) - { - var message = - string.Format( - CultureInfo.InvariantCulture, - Resources.Exception_OptionMustBeProvided, - "ClientId"); + this.CheckClientId(); + this.CheckClientSecret(); + this.SetProvider(); + this.SetSignInAsAuthenticationType(appBuilder); + this.SetStateDataFormat(appBuilder); - throw new ArgumentException(message, "options"); - } + var httpMessageHandler = ResolveHttpMessageHandler(this.Options); - if (string.IsNullOrWhiteSpace(this.Options.ClientSecret)) - { - var message = - string.Format( - CultureInfo.InvariantCulture, - Resources.Exception_OptionMustBeProvided, - "ClientSecret"); + this.httpClient = new HttpClient(httpMessageHandler); + this.logger = appBuilder.CreateLogger(); + } - throw new ArgumentException(message, "options"); - } + /// + /// + protected override AuthenticationHandler CreateHandler() + { + return new ImgurAuthenticationHandler(this.httpClient, this.logger); + } - if (this.Options.Provider == null) + /// + private void CheckClientSecret() + { + if (!string.IsNullOrWhiteSpace(this.Options.ClientSecret)) { - this.Options.Provider = new ImgurAuthenticationProvider(); + return; } - if (string.IsNullOrWhiteSpace(this.Options.SignInAsAuthenticationType)) + var message = + string.Format( + CultureInfo.InvariantCulture, + Resources.Exception_OptionMustBeProvided, + "ClientSecret"); + + throw new ArgumentException(message, "options"); + } + + /// + private void CheckClientId() + { + if (!string.IsNullOrWhiteSpace(this.Options.ClientId)) { - this.Options.SignInAsAuthenticationType = appBuilder.GetDefaultSignInAsAuthenticationType(); + return; } - if (this.Options.StateDataFormat == null) - { - var dataProtector = - appBuilder.CreateDataProtector( - TypeFullName, - this.Options.AuthenticationType, - ImgurAuthenticationDefaults.Version); + var message = + string.Format( + CultureInfo.InvariantCulture, + Resources.Exception_OptionMustBeProvided, + "ClientId"); - this.Options.StateDataFormat = new PropertiesDataFormat(dataProtector); + throw new ArgumentException(message, "options"); + } + + /// + private void SetProvider() + { + if (this.Options.Provider != null) + { + return; } - var httpMessageHandler = ResolveHttpMessageHandler(this.Options); + this.Options.Provider = new ImgurAuthenticationProvider(); + } - this.httpClient = new HttpClient(httpMessageHandler); - this.logger = appBuilder.CreateLogger(); + /// + /// + private void SetSignInAsAuthenticationType(IAppBuilder appBuilder) + { + if (!string.IsNullOrWhiteSpace(this.Options.SignInAsAuthenticationType)) + { + return; + } + + this.Options.SignInAsAuthenticationType = appBuilder.GetDefaultSignInAsAuthenticationType(); } /// - /// - protected override AuthenticationHandler CreateHandler() + /// + private void SetStateDataFormat(IAppBuilder appBuilder) { - return new ImgurAuthenticationHandler(this.httpClient, this.logger); + if (this.Options.StateDataFormat != null) + { + return; + } + + var dataProtector = + appBuilder.CreateDataProtector( + TypeFullName, + this.Options.AuthenticationType, + ImgurAuthenticationDefaults.Version); + + this.Options.StateDataFormat = new PropertiesDataFormat(dataProtector); } /// From e75341d38c6c2039b4edcd5d7771ec4662db78bd Mon Sep 17 00:00:00 2001 From: Albireo Date: Mon, 13 Jul 2015 19:41:17 +0200 Subject: [PATCH 16/18] Reorder methods, fix method name --- .../Imgur/ImgurAuthenticationHandler.cs | 134 +++++++++--------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs index 7422adb7..62b78341 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs @@ -42,6 +42,47 @@ public ImgurAuthenticationHandler(HttpClient httpClient, ILogger logger) this.logger = logger; } + /// + /// + public override async Task InvokeAsync() + { + if (!this.Options.CallbackPath.HasValue) + { + return false; + } + + if (!this.Options.CallbackPath.Value.Equals(this.Request.Path.Value, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + var ticket = await this.AuthenticateAsync(); + + if (ticket == null) + { + throw new Exception(ImgurAuthenticationDefaults.InvalidAuthenticationTicketMessage); + } + + var context = this.GetImgurReturnEndpointContext(ticket); + + await this.Options.Provider.ReturnEndpoint(context); + + this.SignIn(context); + + if (context.IsRequestCompleted || context.RedirectUri == null) + { + return context.IsRequestCompleted; + } + + var location = GetRedirectLocation(context); + + this.Response.Redirect(location); + + context.RequestCompleted(); + + return context.IsRequestCompleted; + } + /// /// protected override Task ApplyResponseChallengeAsync() @@ -96,7 +137,7 @@ protected override async Task AuthenticateCoreAsync() return new AuthenticationTicket(null, properties); } - var authenticationResponse = await this.GetAuthenticationResponse(code); + var authenticationResponse = await this.GetAuthenticationResponseAsync(code); if (authenticationResponse == null) { @@ -111,71 +152,6 @@ protected override async Task AuthenticateCoreAsync() return new AuthenticationTicket(context.Identity, context.Properties); } - /// - /// - public override async Task InvokeAsync() - { - if (!this.Options.CallbackPath.HasValue) - { - return false; - } - - if (!this.Options.CallbackPath.Value.Equals(this.Request.Path.Value, StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - var ticket = await this.AuthenticateAsync(); - - if (ticket == null) - { - throw new Exception(ImgurAuthenticationDefaults.InvalidAuthenticationTicketMessage); - } - - var context = this.GetImgurReturnEndpointContext(ticket); - - await this.Options.Provider.ReturnEndpoint(context); - - this.SignIn(context); - - if (context.IsRequestCompleted || context.RedirectUri == null) - { - return context.IsRequestCompleted; - } - - var location = GetRedirectLocation(context); - - this.Response.Redirect(location); - - context.RequestCompleted(); - - return context.IsRequestCompleted; - } - - /// - /// - private void SignIn(ImgurReturnEndpointContext context) - { - if (context.SignInAsAuthenticationType == null || context.Identity == null) - { - return; - } - - var identity = context.Identity; - - if (!identity.AuthenticationType.Equals(context.SignInAsAuthenticationType, StringComparison.OrdinalIgnoreCase)) - { - identity = - new ClaimsIdentity( - identity.Claims, - context.SignInAsAuthenticationType, - identity.NameClaimType, - identity.RoleClaimType); - } - - this.Context.Authentication.SignIn(context.Properties, identity); - } - /// /// /// @@ -206,7 +182,7 @@ private HttpContent GetAuthenticationRequestContent(string code) /// /// /// - private async Task GetAuthenticationResponse(string code) + private async Task GetAuthenticationResponseAsync(string code) { using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, ImgurAuthenticationDefaults.TokenUri)) { @@ -331,6 +307,30 @@ private ImgurReturnEndpointContext GetImgurReturnEndpointContext(AuthenticationT return context; } + /// + /// + private void SignIn(ImgurReturnEndpointContext context) + { + if (context.SignInAsAuthenticationType == null || context.Identity == null) + { + return; + } + + var identity = context.Identity; + + if (!identity.AuthenticationType.Equals(context.SignInAsAuthenticationType, StringComparison.OrdinalIgnoreCase)) + { + identity = + new ClaimsIdentity( + identity.Claims, + context.SignInAsAuthenticationType, + identity.NameClaimType, + identity.RoleClaimType); + } + + this.Context.Authentication.SignIn(context.Properties, identity); + } + /// /// /// From 344b4a8074056930a2d4ada7e95881d1bdb0fea6 Mon Sep 17 00:00:00 2001 From: Albireo Date: Mon, 13 Jul 2015 19:42:11 +0200 Subject: [PATCH 17/18] Fill XML documentation (part 1) --- .../Imgur/ImgurAuthenticationExtensions.cs | 10 +++---- .../Imgur/ImgurAuthenticationOptions.cs | 27 ++++++++++--------- .../Provider/IImgurAuthenticationProvider.cs | 14 +++++----- .../Provider/ImgurAuthenticatedContext.cs | 26 +++++++++--------- .../Provider/ImgurAuthenticationProvider.cs | 20 +++++++------- .../Provider/ImgurReturnEndpointContext.cs | 8 +++--- 6 files changed, 54 insertions(+), 51 deletions(-) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationExtensions.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationExtensions.cs index ebc3a78d..0a293144 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationExtensions.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationExtensions.cs @@ -1,12 +1,12 @@ namespace Owin.Security.Providers.Imgur { - /// + /// imgur extensions for the . public static class ImgurAuthenticationExtensions { - /// - /// - /// - /// + /// Configures the to use to authenticate user. + /// The OWIN to be configured. + /// The with the settings to be used by the . + /// The configured . public static IAppBuilder UseImgurAuthentication(this IAppBuilder appBuilder, ImgurAuthenticationOptions options) { return appBuilder.Use(appBuilder, options); diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs index c9563080..dbace7b0 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationOptions.cs @@ -8,10 +8,10 @@ using Owin.Security.Providers.Imgur.Provider; - /// + /// Configuration options for the . public class ImgurAuthenticationOptions : AuthenticationOptions { - /// + /// Creates a new . public ImgurAuthenticationOptions() : base(ImgurAuthenticationDefaults.AuthenticationType) { @@ -21,19 +21,22 @@ public ImgurAuthenticationOptions() this.Caption = ImgurAuthenticationDefaults.AuthenticationType; } - /// + /// Gets or sets the a pinned certificate validator to use to validate the endpoints used in back channel communications belong to StackExchange. + /// If this property is null then the default certificate checks are performed, validating the subject name and if the signing chain is a trusted party. public ICertificateValidator BackchannelCertificateValidator { get; set; } - /// + /// The HttpMessageHandler used to communicate with StackExchange. + /// This cannot be set at the same time as BackchannelCertificateValidator unless the value can be downcast to a WebRequestHandler. public HttpMessageHandler BackchannelHttpHandler { get; set; } - /// + /// Gets or sets timeout value in milliseconds for back channel communications with imgur. public TimeSpan BackchannelTimeout { get; set; } - /// + /// The request path within the application's base path where the user-agent will be returned. The middleware will process this request when it arrives. + /// The default value is "/signin-imgur". public PathString CallbackPath { get; set; } - /// + /// Get or sets the text that the user can display on a sign in user interface. public string Caption { get @@ -47,19 +50,19 @@ public string Caption } } - /// + /// Gets or sets the imgur application client id. public string ClientId { get; set; } - /// + /// Gets or sets the imgur application client secret. public string ClientSecret { get; set; } - /// + /// Gets or sets the used in the authentication events. public IImgurAuthenticationProvider Provider { get; set; } - /// + /// Gets or sets the name of another authentication middleware which will be responsible for actually issuing a user. public string SignInAsAuthenticationType { get; set; } - /// + /// Gets or sets the type used to secure the data handled by the middleware. public ISecureDataFormat StateDataFormat { get; set; } } } diff --git a/Owin.Security.Providers/Imgur/Provider/IImgurAuthenticationProvider.cs b/Owin.Security.Providers/Imgur/Provider/IImgurAuthenticationProvider.cs index 7786870a..6a79d2f9 100644 --- a/Owin.Security.Providers/Imgur/Provider/IImgurAuthenticationProvider.cs +++ b/Owin.Security.Providers/Imgur/Provider/IImgurAuthenticationProvider.cs @@ -2,17 +2,17 @@ { using System.Threading.Tasks; - /// + /// Specifies callback methods which the invokes to enable developers control over the authentication process. public interface IImgurAuthenticationProvider { - /// - /// - /// + /// Invoked whenever imgur succesfully authenticates a user. + /// The that contains information about the login session and the user's . + /// A representing the completed operation. Task Authenticated(ImgurAuthenticatedContext context); - /// - /// - /// + /// Invoked prior to the being saved in a local cookie and the browser being redirected to the originally requested URL. + /// The of the authentication request. + /// A representing the completed operation. Task ReturnEndpoint(ImgurReturnEndpointContext context); } } diff --git a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs index 56bd148a..38c8edd1 100644 --- a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs +++ b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticatedContext.cs @@ -6,42 +6,42 @@ using Microsoft.Owin.Security; using Microsoft.Owin.Security.Provider; - /// + /// Contains information about the login session and the user's . public class ImgurAuthenticatedContext : BaseContext { - /// - /// - /// + /// Creates a new . + /// The OWIN context of the autentication request. + /// The used to set up the . public ImgurAuthenticatedContext(IOwinContext context, ImgurAuthenticationOptions options) : base(context, options) { } - /// + /// Gets or sets the access token for the authenticated user. public string AccessToken { get; set; } - /// + /// Gets or sets the account id of the authenticated user. public int AccountId { get; set; } - /// + /// Gets or sets the account username of the authenticated user. public string AccountUsername { get; set; } - /// + /// Gets or sets the duration of the access token. public int ExpiresIn { get; set; } - /// + /// Gets or sets the for the authenticated user. public ClaimsIdentity Identity { get; set; } - /// + /// Gets or sets the of the authentication request. public AuthenticationProperties Properties { get; set; } - /// + /// Gets or sets the refresh token for the authenticated user. public string RefreshToken { get; set; } - /// + /// Gets or sets the scope of the access token. public string Scope { get; set; } - /// + /// Gets or sets the type of the access token. public string TokenType { get; set; } } } diff --git a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs index 7ffadf43..ff41b26a 100644 --- a/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs +++ b/Owin.Security.Providers/Imgur/Provider/ImgurAuthenticationProvider.cs @@ -3,33 +3,33 @@ using System; using System.Threading.Tasks; - /// + /// Default implementation. public class ImgurAuthenticationProvider : IImgurAuthenticationProvider { - /// + /// Creates a new . public ImgurAuthenticationProvider() { this.OnAuthenticated = context => Task.FromResult(null); this.OnReturnEndpoint = context => Task.FromResult(null); } - /// + /// Gets or sets the function that is invoked when the Authenticated method is invoked. public Func OnAuthenticated { get; set; } - /// + /// Gets or sets the function that is invoked when the ReturnEndpoint method is invoked. public Func OnReturnEndpoint { get; set; } - /// - /// - /// + /// Invoked whenever imgur succesfully authenticates a user. + /// The that contains information about the login session and the user's . + /// A representing the completed operation. public Task Authenticated(ImgurAuthenticatedContext context) { return this.OnAuthenticated(context); } - /// - /// - /// + /// Invoked prior to the being saved in a local cookie and the browser being redirected to the originally requested URL. + /// The of the authentication request. + /// A representing the completed operation. public Task ReturnEndpoint(ImgurReturnEndpointContext context) { return this.OnReturnEndpoint(context); diff --git a/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs b/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs index 41b697d0..d4c59d03 100644 --- a/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs +++ b/Owin.Security.Providers/Imgur/Provider/ImgurReturnEndpointContext.cs @@ -4,12 +4,12 @@ using Microsoft.Owin.Security; using Microsoft.Owin.Security.Provider; - /// + /// Provide context information to the middleware provider. public class ImgurReturnEndpointContext : ReturnEndpointContext { - /// - /// - /// + /// Creates a new . + /// The OWIN context of the authentication request. + /// The of the authentication request. public ImgurReturnEndpointContext(IOwinContext context, AuthenticationTicket ticket) : base(context, ticket) { From 70fae47aa70f75c6d06862f9e8275ba37741a66d Mon Sep 17 00:00:00 2001 From: Albireo Date: Tue, 14 Jul 2015 21:33:09 +0200 Subject: [PATCH 18/18] Fill XML documentation (part 2) --- .../Imgur/ImgurAuthenticationDefaults.cs | 60 ++++++------ .../Imgur/ImgurAuthenticationHandler.cs | 95 ++++++++++--------- .../Imgur/ImgurAuthenticationMiddleware.cs | 46 ++++----- 3 files changed, 102 insertions(+), 99 deletions(-) diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs index b585d8a7..8aaa4bac 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationDefaults.cs @@ -1,87 +1,87 @@ namespace Owin.Security.Providers.Imgur { - /// + /// Configuration strings for the imgur provider. internal static class ImgurAuthenticationDefaults { - /// + /// The error message for user authentication failure. internal const string AccessDeniedErrorMessage = "access_denied"; - /// + /// The name of the access token property in the imgur authentication response. internal const string AccessTokenPropertyName = "access_token"; - /// + /// The name of the account id property in the imgur authentication response. internal const string AccountIdPropertyName = "account_id"; - /// + /// The name of the account username property in the imgur authentication response. internal const string AccountUsernamePropertyName = "account_username"; - /// + /// The name of the provider. internal const string AuthenticationType = "Imgur"; - /// + /// The grant type to be used. internal const string AuthorizationCodeGrantType = "authorization_code"; - /// - internal const string AuthorizationUri = "https://api.imgur.com/oauth2/authorize"; + /// The user authorization endpoint URL. + internal const string AuthorizationUrl = "https://api.imgur.com/oauth2/authorize"; - /// + /// The default callback path. internal const string CallbackPath = "/signin-imgur"; - /// + /// The name of the application client id parameter. internal const string ClientIdParameter = "client_id"; - /// + /// The name of the application client secret parameter. internal const string ClientSecretParameter = "client_secret"; - /// + /// The name of the response code parameter. internal const string CodeParameter = "code"; - /// + /// The code type of the authentication response. internal const string CodeResponseType = "code"; - /// + /// The message for the communication failure error. internal const string CommunicationFailureMessage = "An error occurred while talking with imgur's server."; - /// + /// The message for the authentication response deserialization failure error. internal const string DeserializationFailureMessage = "The deserialization of the imgur's response failed. Perhaps imgur changed the response format?"; - /// + /// The name of the error parameter. internal const string ErrorParameter = "error"; - /// + /// The name of the access token duration property in the imgur authentication response. internal const string ExpiresInPropertyName = "expires_in"; - /// + /// The name of the grant type parameter. internal const string GrantTypeParameter = "grant_type"; - /// + /// The format to use to stringify s. internal const string Int32Format = "D"; - /// + /// The message for the invalid authentication ticket error. internal const string InvalidAuthenticationTicketMessage = "Invalid authentication ticket."; - /// + /// The name of the refresh token property in the imgur authentication response. internal const string RefreshInPropertyName = "refresh_token"; - /// + /// The name of the response type parameter. internal const string ResponseTypeParameter = "response_type"; - /// + /// The name of the scope property in the imgur authentication response. internal const string ScopePropertyName = "scope"; - /// + /// The name of the state parameter. internal const string StateParameter = "state"; - /// + /// The name of the token type property in the imgur authentication response. internal const string TokenTypePropertyName = "token_type"; - /// - internal const string TokenUri = "https://api.imgur.com/oauth2/token"; + /// The token exchange endpoint URL. + internal const string TokenUrl = "https://api.imgur.com/oauth2/token"; - /// + /// The version of the provider. internal const string Version = "v1"; - /// + /// The string value type for s. internal const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; } } diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs index 62b78341..dd9f2897 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationHandler.cs @@ -12,6 +12,7 @@ using Microsoft.Owin.Logging; using Microsoft.Owin.Security; using Microsoft.Owin.Security.Infrastructure; + using Microsoft.Owin.Security.Provider; using Newtonsoft.Json; @@ -23,9 +24,9 @@ public class ImgurAuthenticationHandler : AuthenticationHandler - /// - /// + /// Creates a new . + /// The to be used for back channel calls. + /// The to be used by the . public ImgurAuthenticationHandler(HttpClient httpClient, ILogger logger) { if (httpClient == null) @@ -42,8 +43,8 @@ public ImgurAuthenticationHandler(HttpClient httpClient, ILogger logger) this.logger = logger; } - /// - /// + /// Is called once by common code after initialization. + /// Return true if the request is handled by this , returns false if the request should be passed to the next . public override async Task InvokeAsync() { if (!this.Options.CallbackPath.HasValue) @@ -83,8 +84,8 @@ public override async Task InvokeAsync() return context.IsRequestCompleted; } - /// - /// + /// Handles authentication challenges by intercepting 401 responses. + /// A representing the completed operation. protected override Task ApplyResponseChallengeAsync() { if (this.Response.StatusCode != 401) @@ -114,8 +115,9 @@ protected override Task ApplyResponseChallengeAsync() return Task.FromResult(null); } - /// - /// + /// The core authentication logic which must be provided by the . + /// The ticket data provided by the authentication logic. + /// Will be invoked at most once per request. Do not call directly, call the wrapping Authenticate method instead. protected override async Task AuthenticateCoreAsync() { if (this.Request.Query.Get(ImgurAuthenticationDefaults.ErrorParameter) != null) @@ -152,9 +154,9 @@ protected override async Task AuthenticateCoreAsync() return new AuthenticationTicket(context.Identity, context.Properties); } - /// - /// - /// + /// Gets the payload for the back channel authentication request. + /// The authorization code supplied by imgur. + /// The with the payload for the back channel authentication request. private HttpContent GetAuthenticationRequestContent(string code) { return @@ -179,12 +181,12 @@ private HttpContent GetAuthenticationRequestContent(string code) }); } - /// - /// - /// + /// Gets the from imgur. + /// The authorization code supplied by imgur. + /// The from imgur. private async Task GetAuthenticationResponseAsync(string code) { - using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, ImgurAuthenticationDefaults.TokenUri)) + using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, ImgurAuthenticationDefaults.TokenUrl)) { httpRequestMessage.Content = this.GetAuthenticationRequestContent(code); @@ -211,12 +213,12 @@ private async Task GetAuthenticationResponseAsync(string } } - /// - /// - /// + /// Gets the authorization URL for the back channel call. + /// The encrypted for the current authentication session. + /// The authorization URL for the back channel call. private string GetAuthorizationUri(string state) { - var authorizationUri = ImgurAuthenticationDefaults.AuthorizationUri; + var authorizationUri = ImgurAuthenticationDefaults.AuthorizationUrl; authorizationUri = WebUtilities.AddQueryString( @@ -239,9 +241,9 @@ private string GetAuthorizationUri(string state) return authorizationUri; } - /// - /// - /// + /// Gets the for the identity of the user. + /// The returned by imgur. + /// The for the identity of the user. private ClaimsIdentity GetIdentity(AuthenticationResponse authenticationResponse) { var identity = @@ -274,11 +276,11 @@ private ClaimsIdentity GetIdentity(AuthenticationResponse authenticationResponse return identity; } - /// - /// - /// - /// - /// + /// Gets the for the current authentication session. + /// The returned by imgur. + /// The for the identity of the user. + /// The for the current authentication session. + /// The for the current authentication session. private ImgurAuthenticatedContext GetImgurAuthenticatedContext(AuthenticationResponse authenticationResponse, ClaimsIdentity identity, AuthenticationProperties properties) { var context = new ImgurAuthenticatedContext(this.Context, this.Options); @@ -295,9 +297,9 @@ private ImgurAuthenticatedContext GetImgurAuthenticatedContext(AuthenticationRes return context; } - /// - /// - /// + /// Gets the for the current authentication session. + /// The for the current authentication session. + /// The for the current authentication session. private ImgurReturnEndpointContext GetImgurReturnEndpointContext(AuthenticationTicket ticket) { var context = new ImgurReturnEndpointContext(this.Context, ticket); @@ -307,9 +309,9 @@ private ImgurReturnEndpointContext GetImgurReturnEndpointContext(AuthenticationT return context; } - /// - /// - private void SignIn(ImgurReturnEndpointContext context) + /// Adds authentication information to the OWIN context to let the appropriate authenticate the user. + /// The for the current authentication session. + private void SignIn(ReturnEndpointContext context) { if (context.SignInAsAuthenticationType == null || context.Identity == null) { @@ -331,10 +333,10 @@ private void SignIn(ImgurReturnEndpointContext context) this.Context.Authentication.SignIn(context.Properties, identity); } - /// - /// - /// - private static string GetRedirectLocation(ImgurReturnEndpointContext context) + /// Gets the URL where the user should be redirect to. + /// The for the current authentication session. + /// The URL where the user should be redirect to. + private static string GetRedirectLocation(ReturnEndpointContext context) { var location = context.RedirectUri; @@ -346,37 +348,38 @@ private static string GetRedirectLocation(ImgurReturnEndpointContext context) ImgurAuthenticationDefaults.ErrorParameter, ImgurAuthenticationDefaults.AccessDeniedErrorMessage); } + return location; } - /// + /// Response payload returned by imgur with the information of the authenticated user. private class AuthenticationResponse { - /// + /// Gets or sets the access token for the authenticated user. [JsonProperty(PropertyName = ImgurAuthenticationDefaults.AccessTokenPropertyName)] public string AccessToken { get; set; } - /// + /// Gets or sets the account id of the authenticated user. [JsonProperty(PropertyName = ImgurAuthenticationDefaults.AccountIdPropertyName)] public int AccountId { get; set; } - /// + /// Gets or sets the account username of the authenticated user. [JsonProperty(PropertyName = ImgurAuthenticationDefaults.AccountUsernamePropertyName)] public string AccountUsername { get; set; } - /// + /// Gets or sets the duration of the access token. [JsonProperty(PropertyName = ImgurAuthenticationDefaults.ExpiresInPropertyName)] public int ExpiresIn { get; set; } - /// + /// Gets or sets the refresh token for the authenticated user. [JsonProperty(PropertyName = ImgurAuthenticationDefaults.RefreshInPropertyName)] public string RefreshToken { get; set; } - /// + /// Gets or sets the scope of the access token. [JsonProperty(PropertyName = ImgurAuthenticationDefaults.ScopePropertyName)] public string Scope { get; set; } - /// + /// Gets or sets the type of the access token. [JsonProperty(PropertyName = ImgurAuthenticationDefaults.TokenTypePropertyName)] public string TokenType { get; set; } } diff --git a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs index 46df6f60..94c89f48 100644 --- a/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/Imgur/ImgurAuthenticationMiddleware.cs @@ -14,7 +14,7 @@ using Owin.Security.Providers.Imgur.Provider; using Owin.Security.Providers.Properties; - /// + /// OWIN authentication middleware for imgur. public class ImgurAuthenticationMiddleware : AuthenticationMiddleware { private readonly HttpClient httpClient; @@ -22,10 +22,10 @@ public class ImgurAuthenticationMiddleware : AuthenticationMiddleware - /// - /// - /// + /// Creates a new . + /// The next in the configuration chain. + /// The OWIN being configured. + /// The to be used to set up the . public ImgurAuthenticationMiddleware(OwinMiddleware next, IAppBuilder appBuilder, ImgurAuthenticationOptions options) : base(next, options) { @@ -51,17 +51,17 @@ public ImgurAuthenticationMiddleware(OwinMiddleware next, IAppBuilder appBuilder this.logger = appBuilder.CreateLogger(); } - /// - /// + /// Creates the to be used by the . + /// The to be used by the . protected override AuthenticationHandler CreateHandler() { return new ImgurAuthenticationHandler(this.httpClient, this.logger); } - /// - private void CheckClientSecret() + /// Checks that the imgur application client id has been set. + private void CheckClientId() { - if (!string.IsNullOrWhiteSpace(this.Options.ClientSecret)) + if (!string.IsNullOrWhiteSpace(this.Options.ClientId)) { return; } @@ -70,15 +70,15 @@ private void CheckClientSecret() string.Format( CultureInfo.InvariantCulture, Resources.Exception_OptionMustBeProvided, - "ClientSecret"); + "ClientId"); throw new ArgumentException(message, "options"); } - /// - private void CheckClientId() + /// Checks that the imgur application client secret has been set. + private void CheckClientSecret() { - if (!string.IsNullOrWhiteSpace(this.Options.ClientId)) + if (!string.IsNullOrWhiteSpace(this.Options.ClientSecret)) { return; } @@ -87,12 +87,12 @@ private void CheckClientId() string.Format( CultureInfo.InvariantCulture, Resources.Exception_OptionMustBeProvided, - "ClientId"); + "ClientSecret"); throw new ArgumentException(message, "options"); } - /// + /// Sets the provider to if it hasn't been set. private void SetProvider() { if (this.Options.Provider != null) @@ -103,8 +103,8 @@ private void SetProvider() this.Options.Provider = new ImgurAuthenticationProvider(); } - /// - /// + /// Sets the name authentication middleware responsible for signing in the user if it hasn't been set. + /// The OWIN being configured. private void SetSignInAsAuthenticationType(IAppBuilder appBuilder) { if (!string.IsNullOrWhiteSpace(this.Options.SignInAsAuthenticationType)) @@ -115,8 +115,8 @@ private void SetSignInAsAuthenticationType(IAppBuilder appBuilder) this.Options.SignInAsAuthenticationType = appBuilder.GetDefaultSignInAsAuthenticationType(); } - /// - /// + /// Sets the data protector to if it hasn't been set. + /// The OWIN being configured. private void SetStateDataFormat(IAppBuilder appBuilder) { if (this.Options.StateDataFormat != null) @@ -133,9 +133,9 @@ private void SetStateDataFormat(IAppBuilder appBuilder) this.Options.StateDataFormat = new PropertiesDataFormat(dataProtector); } - /// - /// - /// + /// Gets the to be used for the back channel calls. + /// The used to configure the . + /// The to be used for the back channel calls. private static HttpMessageHandler ResolveHttpMessageHandler(ImgurAuthenticationOptions options) { var httpMessageHandler = options.BackchannelHttpHandler ?? new WebRequestHandler();