From a83da598165339a7b2bce932e7d593f7330a4fd3 Mon Sep 17 00:00:00 2001 From: Ricardo Peres Date: Thu, 19 Mar 2015 14:51:44 +0000 Subject: [PATCH 01/22] - Removed scope; - Added comments; --- .../FoursquareAuthenticationHandler.cs | 6 +- .../FoursquareAuthenticationMiddleware.cs | 8 ++ .../FoursquareAuthenticationOptions.cs | 6 -- .../FoursquareAuthenticatedContext.cs | 85 +++++++++++++++++++ .../FoursquareAuthenticationProvider.cs | 22 +++++ .../FoursquareReturnEndpointContext.cs | 3 + .../IFoursquareAuthenticationProvider.cs | 13 +++ 7 files changed, 132 insertions(+), 11 deletions(-) diff --git a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationHandler.cs b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationHandler.cs index 8979ac6..b17631c 100644 --- a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationHandler.cs +++ b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationHandler.cs @@ -174,17 +174,13 @@ namespace Owin.Security.Providers.Foursquare // OAuth2 10.12 CSRF this.GenerateCorrelationId(extra); - // OAuth2 3.3 space separated - var scope = string.Join(" ", this.Options.Scope); - var state = this.Options.StateDataFormat.Protect(extra); var authorizationEndpoint = AuthorizationEndpoint + "?client_id=" + Uri.EscapeDataString(this.Options.ClientId) + "&response_type=code" + "&redirect_uri=" + Uri.EscapeDataString(redirectUri) + - "&state=" + Uri.EscapeDataString(state) + - "&scope=" + Uri.EscapeDataString(scope); + "&state=" + Uri.EscapeDataString(state); this.Response.Redirect(authorizationEndpoint); } diff --git a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationMiddleware.cs b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationMiddleware.cs index 6980598..f12f0d5 100644 --- a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationMiddleware.cs @@ -51,6 +51,14 @@ namespace Owin.Security.Providers.Foursquare this._httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB } + /// + /// Provides the object for processing + /// authentication-related requests. + /// + /// + /// An configured with the + /// supplied to the constructor. + /// protected override AuthenticationHandler CreateHandler() { return new FoursquareAuthenticationHandler(this._httpClient, this._logger); diff --git a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationOptions.cs b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationOptions.cs index defcec3..e1356d2 100644 --- a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationOptions.cs +++ b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationOptions.cs @@ -18,7 +18,6 @@ namespace Owin.Security.Providers.Foursquare this.CallbackPath = "/signin-foursquare"; this.AuthenticationMode = AuthenticationMode.Passive; this.BackchannelTimeout = TimeSpan.FromSeconds(60); - this.Scope = new List(); } /// @@ -82,11 +81,6 @@ namespace Owin.Security.Providers.Foursquare /// public ISecureDataFormat StateDataFormat { get; set; } - /// - /// A list of permissions to request. - /// - public IList Scope { get; private set; } - /// /// Get or sets the text that the user can display on a sign in user interface. /// diff --git a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs index d85da87..d7a5ae1 100644 --- a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs +++ b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs @@ -7,8 +7,17 @@ using Newtonsoft.Json.Linq; namespace Owin.Security.Providers.Foursquare.Provider { + /// + /// Contains information about the login session as well as the user . + /// public class FoursquareAuthenticatedContext : BaseContext { + /// + /// Initializes a + /// + /// The OWIN environment + /// The JSON-serialized user + /// GitHub Access token public FoursquareAuthenticatedContext(IOwinContext context, JObject user, string accessToken) : base(context) { @@ -49,29 +58,105 @@ namespace Owin.Security.Providers.Foursquare.Provider this.Link = "https://foursquare.com/user/" + this.Id; } + /// + /// Gets the JSON-serialized user + /// + /// + /// Contains the Foursquare user obtained from the User Info endpoint. By default this is https://api.foursquare.com/v2/users/self but it can be + /// overridden in the options + /// public JObject User { get; private set; } + /// + /// Gets the Foursquare access token + /// public string AccessToken { get; private set; } + /// + /// Gets the Foursquare user ID + /// public string Id { get; private set; } + /// + /// Gets the user's first name + /// public string FirstName { get; private set; } + /// + /// Gets the user's last name + /// public string LastName { get; private set; } + /// + /// Gets the user's full name + /// public string Name { get; private set; } + /// + /// Gets the user's gender + /// public string Gender { get; private set; } + /// + /// Gets the user's photo + /// public string Photo { get; private set; } + /// + /// Gets the user's friends + /// public string Friends { get; private set; } + /// + /// Gets the user's home city + /// public string HomeCity { get; private set; } + /// + /// Gets the user's biography + /// public string Bio { get; private set; } + /// + /// Gets the user's contact + /// public string Contact { get; private set; } + /// + /// Gets the user's phone + /// public string Phone { get; private set; } + /// + /// Gets the user's email + /// public string Email { get; private set; } + /// + /// Gets the user's Twitter handle + /// public string Twitter { get; private set; } + /// + /// Gets the user's Facebook id + /// public string Facebook { get; private set; } + /// + /// Gets the user's badges + /// public string Badges { get; private set; } + /// + /// Gets the user's mayorships + /// public string Mayorships { get; private set; } + /// + /// Gets the user's checkins + /// public string Checkins { get; private set; } + /// + /// Gets the user's photos + /// public string Photos { get; private set; } + /// + /// Gets the user's scores + /// public string Scores { get; private set; } + /// + /// Gets the user's link + /// public string Link { get; private set; } + /// + /// Gets the representing the user + /// public ClaimsIdentity Identity { get; set; } + /// + /// Gets or sets a property bag for common authentication properties + /// public AuthenticationProperties Properties { get; set; } private static string TryGetValue(JObject user, string propertyName) diff --git a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticationProvider.cs b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticationProvider.cs index ebe5746..e1e682d 100644 --- a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticationProvider.cs +++ b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticationProvider.cs @@ -3,23 +3,45 @@ using System.Threading.Tasks; namespace Owin.Security.Providers.Foursquare.Provider { + /// + /// Default implementation. + /// public class FoursquareAuthenticationProvider : IFoursquareAuthenticationProvider { + /// + /// Initializes a + /// public FoursquareAuthenticationProvider() { 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 GitHub succesfully authenticates a user + /// + /// Contains information about the login session as well as the user . + /// A representing the completed operation. public virtual Task Authenticated(FoursquareAuthenticatedContext 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. + /// + /// + /// A representing the completed operation. public virtual Task ReturnEndpoint(FoursquareReturnEndpointContext context) { return this.OnReturnEndpoint(context); diff --git a/Owin.Security.Providers/Foursquare/Provider/FoursquareReturnEndpointContext.cs b/Owin.Security.Providers/Foursquare/Provider/FoursquareReturnEndpointContext.cs index 8074b4d..27fd33f 100644 --- a/Owin.Security.Providers/Foursquare/Provider/FoursquareReturnEndpointContext.cs +++ b/Owin.Security.Providers/Foursquare/Provider/FoursquareReturnEndpointContext.cs @@ -4,6 +4,9 @@ using Microsoft.Owin.Security.Provider; namespace Owin.Security.Providers.Foursquare.Provider { + /// + /// Provides context information to middleware providers. + /// public class FoursquareReturnEndpointContext : ReturnEndpointContext { /// diff --git a/Owin.Security.Providers/Foursquare/Provider/IFoursquareAuthenticationProvider.cs b/Owin.Security.Providers/Foursquare/Provider/IFoursquareAuthenticationProvider.cs index 0403897..3cc8d38 100644 --- a/Owin.Security.Providers/Foursquare/Provider/IFoursquareAuthenticationProvider.cs +++ b/Owin.Security.Providers/Foursquare/Provider/IFoursquareAuthenticationProvider.cs @@ -2,10 +2,23 @@ namespace Owin.Security.Providers.Foursquare.Provider { + /// + /// Specifies callback methods which the invokes to enable developer control over the authentication process. /> + /// public interface IFoursquareAuthenticationProvider { + /// + /// Invoked whenever GitHub succesfully authenticates a user + /// + /// Contains information about the login session as well as the user . + /// A representing the completed operation. Task Authenticated(FoursquareAuthenticatedContext context); + /// + /// Invoked prior to the being saved in a local cookie and the browser being redirected to the originally requested URL. + /// + /// + /// A representing the completed operation. Task ReturnEndpoint(FoursquareReturnEndpointContext context); } } \ No newline at end of file From 7b8d376846ea9585ae2b8120d2958e7327eee70d Mon Sep 17 00:00:00 2001 From: Ricardo Peres Date: Thu, 19 Mar 2015 22:08:15 +0000 Subject: [PATCH 02/22] - Changed version to a fixed date; --- .../Foursquare/FoursquareAuthenticationHandler.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationHandler.cs b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationHandler.cs index b17631c..0006af0 100644 --- a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationHandler.cs +++ b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationHandler.cs @@ -20,6 +20,8 @@ namespace Owin.Security.Providers.Foursquare private const string GraphApiEndpoint = "https://api.foursquare.com/v2/users/self"; private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; + private static readonly DateTime VersionDate = new DateTime(2015, 3, 19); + private readonly ILogger _logger; private readonly HttpClient _httpClient; @@ -103,7 +105,7 @@ namespace Owin.Security.Providers.Foursquare return new AuthenticationTicket(null, properties); } - var graphResponse = await this._httpClient.GetAsync(GraphApiEndpoint + "?oauth_token=" + Uri.EscapeDataString(accessToken) + "&m=foursquare&v=" + DateTime.Today.ToString("yyyyyMMdd"), this.Request.CallCancelled); + var graphResponse = await this._httpClient.GetAsync(GraphApiEndpoint + "?oauth_token=" + Uri.EscapeDataString(accessToken) + "&m=foursquare&v=" + VersionDate.ToString("yyyyyMMdd"), this.Request.CallCancelled); graphResponse.EnsureSuccessStatusCode(); var accountstring = await graphResponse.Content.ReadAsStringAsync(); From 6d001e3e136a29953dd3f8b11e342d826d80f46b Mon Sep 17 00:00:00 2001 From: Ivan Nikitin Date: Tue, 24 Mar 2015 19:14:26 +0100 Subject: [PATCH 03/22] Flickr support --- Owin.Security.Providers/Flickr/Constants.cs | 7 + .../Flickr/FlickrAuthenticationExtensions.cs | 29 ++ .../Flickr/FlickrAuthenticationHandler.cs | 367 ++++++++++++++++++ .../Flickr/FlickrAuthenticationMiddleware.cs | 90 +++++ .../Flickr/FlickrAuthenticationOptions.cs | 99 +++++ .../Flickr/Messages/AccessToken.cs | 25 ++ .../Flickr/Messages/RequestToken.cs | 29 ++ .../Flickr/Messages/RequestTokenSerializer.cs | 106 +++++ .../Flickr/Messages/Serializers.cs | 22 ++ .../Provider/FlickrAuthenticatedContext.cs | 66 ++++ .../Provider/FlickrAuthenticationProvider.cs | 45 +++ .../Provider/FlickrReturnEndpointContext.cs | 21 + .../Provider/IFlickrAuthenticationProvider.cs | 26 ++ .../Owin.Security.Providers.csproj | 13 + .../App_Start/Startup.Auth.cs | 3 + 15 files changed, 948 insertions(+) create mode 100644 Owin.Security.Providers/Flickr/Constants.cs create mode 100644 Owin.Security.Providers/Flickr/FlickrAuthenticationExtensions.cs create mode 100644 Owin.Security.Providers/Flickr/FlickrAuthenticationHandler.cs create mode 100644 Owin.Security.Providers/Flickr/FlickrAuthenticationMiddleware.cs create mode 100644 Owin.Security.Providers/Flickr/FlickrAuthenticationOptions.cs create mode 100644 Owin.Security.Providers/Flickr/Messages/AccessToken.cs create mode 100644 Owin.Security.Providers/Flickr/Messages/RequestToken.cs create mode 100644 Owin.Security.Providers/Flickr/Messages/RequestTokenSerializer.cs create mode 100644 Owin.Security.Providers/Flickr/Messages/Serializers.cs create mode 100644 Owin.Security.Providers/Flickr/Provider/FlickrAuthenticatedContext.cs create mode 100644 Owin.Security.Providers/Flickr/Provider/FlickrAuthenticationProvider.cs create mode 100644 Owin.Security.Providers/Flickr/Provider/FlickrReturnEndpointContext.cs create mode 100644 Owin.Security.Providers/Flickr/Provider/IFlickrAuthenticationProvider.cs diff --git a/Owin.Security.Providers/Flickr/Constants.cs b/Owin.Security.Providers/Flickr/Constants.cs new file mode 100644 index 0000000..e5a32d3 --- /dev/null +++ b/Owin.Security.Providers/Flickr/Constants.cs @@ -0,0 +1,7 @@ +namespace Owin.Security.Providers.Flickr +{ + internal static class Constants + { + public const string DefaultAuthenticationType = "Flickr"; + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/Flickr/FlickrAuthenticationExtensions.cs b/Owin.Security.Providers/Flickr/FlickrAuthenticationExtensions.cs new file mode 100644 index 0000000..b1fe1d8 --- /dev/null +++ b/Owin.Security.Providers/Flickr/FlickrAuthenticationExtensions.cs @@ -0,0 +1,29 @@ +using System; + +namespace Owin.Security.Providers.Flickr +{ + public static class FlickrAuthenticationExtensions + { + public static IAppBuilder UseFlickrAuthentication(this IAppBuilder app, + FlickrAuthenticationOptions options) + { + if (app == null) + throw new ArgumentNullException("app"); + if (options == null) + throw new ArgumentNullException("options"); + + app.Use(typeof(FlickrAuthenticationMiddleware), app, options); + + return app; + } + + public static IAppBuilder UseFlickrAuthentication(this IAppBuilder app, string appKey, string appSecret) + { + return app.UseFlickrAuthentication(new FlickrAuthenticationOptions + { + AppKey = appKey, + AppSecret = appSecret + }); + } + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/Flickr/FlickrAuthenticationHandler.cs b/Owin.Security.Providers/Flickr/FlickrAuthenticationHandler.cs new file mode 100644 index 0000000..93591b4 --- /dev/null +++ b/Owin.Security.Providers/Flickr/FlickrAuthenticationHandler.cs @@ -0,0 +1,367 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Runtime.InteropServices; +using System.Security.Claims; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Owin; +using Microsoft.Owin.Helpers; +using Microsoft.Owin.Infrastructure; +using Microsoft.Owin.Logging; +using Microsoft.Owin.Security; +using Microsoft.Owin.Security.Infrastructure; +using Newtonsoft.Json.Linq; +using Owin.Security.Providers.Flickr.Messages; + +namespace Owin.Security.Providers.Flickr +{ + internal class FlickrAuthenticationHandler : AuthenticationHandler + { + private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + private const string StateCookie = "__FlickrState"; + private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; + private const string RequestTokenEndpoint = "https://www.flickr.com/services/oauth/request_token"; + private const string AuthenticationEndpoint = "https://www.flickr.com/services/oauth/authorize?oauth_token="; + private const string AccessTokenEndpoint = "https://www.flickr.com/services/oauth/access_token"; + + private readonly HttpClient httpClient; + private readonly ILogger logger; + + public FlickrAuthenticationHandler(HttpClient httpClient, ILogger logger) + { + this.httpClient = httpClient; + this.logger = logger; + } + + public override async Task InvokeAsync() + { + if (Options.CallbackPath.HasValue && Options.CallbackPath == Request.Path) + { + return await InvokeReturnPathAsync(); + } + return false; + } + + protected override async Task AuthenticateCoreAsync() + { + AuthenticationProperties properties = null; + try + { + IReadableStringCollection query = Request.Query; + string protectedRequestToken = Request.Cookies[StateCookie]; + + RequestToken requestToken = Options.StateDataFormat.Unprotect(protectedRequestToken); + + if (requestToken == null) + { + logger.WriteWarning("Invalid state"); + return null; + } + + properties = requestToken.Properties; + + string returnedToken = query.Get("oauth_token"); + if (string.IsNullOrWhiteSpace(returnedToken)) + { + logger.WriteWarning("Missing oauth_token"); + return new AuthenticationTicket(null, properties); + } + + if (returnedToken != requestToken.Token) + { + logger.WriteWarning("Unmatched token"); + return new AuthenticationTicket(null, properties); + } + + string oauthVerifier = query.Get("oauth_verifier"); + if (string.IsNullOrWhiteSpace(oauthVerifier)) + { + logger.WriteWarning("Missing or blank oauth_verifier"); + return new AuthenticationTicket(null, properties); + } + + AccessToken accessToken = await ObtainAccessTokenAsync(Options.AppKey, Options.AppSecret, requestToken, oauthVerifier); + + var context = new FlickrAuthenticatedContext(Context, accessToken); + + context.Identity = new ClaimsIdentity( + Options.AuthenticationType, + ClaimsIdentity.DefaultNameClaimType, + ClaimsIdentity.DefaultRoleClaimType); + if (!String.IsNullOrEmpty(context.UserId)) + { + context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.UserId, + XmlSchemaString, Options.AuthenticationType)); + } + if (!String.IsNullOrEmpty(context.FullName)) + { + context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName, + XmlSchemaString, Options.AuthenticationType)); + } + if (!String.IsNullOrEmpty(context.UserName)) + { + context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.FullName, + XmlSchemaString, Options.AuthenticationType)); + } + context.Properties = requestToken.Properties; + + Response.Cookies.Delete(StateCookie); + + await Options.Provider.Authenticated(context); + + return new AuthenticationTicket(context.Identity, context.Properties); + } + catch (Exception ex) + { + logger.WriteError("Authentication failed", ex); + return new AuthenticationTicket(null, properties); + } + } + + protected override async Task ApplyResponseChallengeAsync() + { + if (Response.StatusCode != 401) + { + return; + } + + AuthenticationResponseChallenge challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode); + + if (challenge != null) + { + string requestPrefix = Request.Scheme + "://" + Request.Host; + string callBackUrl = requestPrefix + RequestPathBase + Options.CallbackPath; + + AuthenticationProperties extra = challenge.Properties; + if (string.IsNullOrEmpty(extra.RedirectUri)) + { + extra.RedirectUri = requestPrefix + Request.PathBase + Request.Path + Request.QueryString; + } + + RequestToken requestToken = await ObtainRequestTokenAsync(Options.AppKey, Options.AppSecret, callBackUrl, extra); + + if (requestToken.CallbackConfirmed) + { + string FlickrAuthenticationEndpoint = AuthenticationEndpoint + requestToken.Token + "&perms=" + Options.Scope; + + var cookieOptions = new CookieOptions + { + HttpOnly = true, + Secure = Request.IsSecure + }; + + Response.StatusCode = 302; + Response.Cookies.Append(StateCookie, Options.StateDataFormat.Protect(requestToken), cookieOptions); + Response.Headers.Set("Location", FlickrAuthenticationEndpoint); + } + else + { + logger.WriteError("requestToken CallbackConfirmed!=true"); + } + } + } + + public async Task InvokeReturnPathAsync() + { + AuthenticationTicket model = await AuthenticateAsync(); + if (model == null) + { + logger.WriteWarning("Invalid return state, unable to redirect."); + Response.StatusCode = 500; + return true; + } + + var context = new FlickrReturnEndpointContext(Context, model) + { + SignInAsAuthenticationType = Options.SignInAsAuthenticationType, + RedirectUri = model.Properties.RedirectUri + }; + model.Properties.RedirectUri = null; + + await Options.Provider.ReturnEndpoint(context); + + if (context.SignInAsAuthenticationType != null && context.Identity != null) + { + ClaimsIdentity signInIdentity = context.Identity; + if (!string.Equals(signInIdentity.AuthenticationType, context.SignInAsAuthenticationType, StringComparison.Ordinal)) + { + signInIdentity = new ClaimsIdentity(signInIdentity.Claims, context.SignInAsAuthenticationType, signInIdentity.NameClaimType, signInIdentity.RoleClaimType); + } + Context.Authentication.SignIn(context.Properties, signInIdentity); + } + + if (!context.IsRequestCompleted && context.RedirectUri != null) + { + if (context.Identity == null) + { + // add a redirect hint that sign-in failed in some way + context.RedirectUri = WebUtilities.AddQueryString(context.RedirectUri, "error", "access_denied"); + } + Response.Redirect(context.RedirectUri); + context.RequestCompleted(); + } + + return context.IsRequestCompleted; + } + + private async Task ObtainRequestTokenAsync(string AppKey, string AppSecret, string callBackUri, AuthenticationProperties properties) + { + logger.WriteVerbose("ObtainRequestToken"); + + string nonce = Guid.NewGuid().ToString("N"); + + var authorizationParts = new SortedDictionary + { + { "oauth_callback", callBackUri }, + { "oauth_consumer_key", AppKey }, + { "oauth_nonce", nonce }, + { "oauth_signature_method", "HMAC-SHA1" }, + { "oauth_timestamp", GenerateTimeStamp() }, + { "oauth_version", "1.0" } + }; + + var parameterBuilder = new StringBuilder(); + foreach (var authorizationKey in authorizationParts) + { + parameterBuilder.AppendFormat("{0}={1}&", Uri.EscapeDataString(authorizationKey.Key), Uri.EscapeDataString(authorizationKey.Value)); + } + parameterBuilder.Length--; + string parameterString = parameterBuilder.ToString(); + + var canonicalizedRequestBuilder = new StringBuilder(); + canonicalizedRequestBuilder.Append(HttpMethod.Post.Method); + canonicalizedRequestBuilder.Append("&"); + canonicalizedRequestBuilder.Append(Uri.EscapeDataString(RequestTokenEndpoint)); + canonicalizedRequestBuilder.Append("&"); + canonicalizedRequestBuilder.Append(Uri.EscapeDataString(parameterString)); + + string signature = ComputeSignature(AppSecret, null, canonicalizedRequestBuilder.ToString()); + authorizationParts.Add("oauth_signature", signature); + + //-- + var authorizationHeaderBuilder = new StringBuilder(); + authorizationHeaderBuilder.Append("OAuth "); + foreach (var authorizationPart in authorizationParts) + { + authorizationHeaderBuilder.AppendFormat( + "{0}=\"{1}\", ", authorizationPart.Key, Uri.EscapeDataString(authorizationPart.Value)); + } + authorizationHeaderBuilder.Length = authorizationHeaderBuilder.Length - 2; + + var request = new HttpRequestMessage(HttpMethod.Post, RequestTokenEndpoint); + request.Headers.Add("Authorization", authorizationHeaderBuilder.ToString()); + + HttpResponseMessage response = await httpClient.SendAsync(request, Request.CallCancelled); + response.EnsureSuccessStatusCode(); + string responseText = await response.Content.ReadAsStringAsync(); + + IFormCollection responseParameters = WebHelpers.ParseForm(responseText); + if (string.Equals(responseParameters["oauth_callback_confirmed"], "true", StringComparison.InvariantCulture)) + { + return new RequestToken { Token = Uri.UnescapeDataString(responseParameters["oauth_token"]), TokenSecret = Uri.UnescapeDataString(responseParameters["oauth_token_secret"]), CallbackConfirmed = true, Properties = properties }; + } + + return new RequestToken(); + } + + private async Task ObtainAccessTokenAsync(string AppKey, string AppSecret, RequestToken token, string verifier) + { + logger.WriteVerbose("ObtainAccessToken"); + + string nonce = Guid.NewGuid().ToString("N"); + + var authorizationParts = new SortedDictionary + { + { "oauth_consumer_key", AppKey }, + { "oauth_nonce", nonce }, + { "oauth_signature_method", "HMAC-SHA1" }, + { "oauth_token", token.Token }, + { "oauth_timestamp", GenerateTimeStamp() }, + { "oauth_verifier", verifier }, + { "oauth_version", "1.0" }, + }; + + var parameterBuilder = new StringBuilder(); + foreach (var authorizationKey in authorizationParts) + { + parameterBuilder.AppendFormat("{0}={1}&", Uri.EscapeDataString(authorizationKey.Key), Uri.EscapeDataString(authorizationKey.Value)); + } + parameterBuilder.Length--; + string parameterString = parameterBuilder.ToString(); + + var canonicalizedRequestBuilder = new StringBuilder(); + canonicalizedRequestBuilder.Append(HttpMethod.Post.Method); + canonicalizedRequestBuilder.Append("&"); + canonicalizedRequestBuilder.Append(Uri.EscapeDataString(AccessTokenEndpoint)); + canonicalizedRequestBuilder.Append("&"); + canonicalizedRequestBuilder.Append(Uri.EscapeDataString(parameterString)); + + string signature = ComputeSignature(AppSecret, token.TokenSecret, canonicalizedRequestBuilder.ToString()); + authorizationParts.Add("oauth_signature", signature); + + var authorizationHeaderBuilder = new StringBuilder(); + authorizationHeaderBuilder.Append("OAuth "); + foreach (var authorizationPart in authorizationParts) + { + authorizationHeaderBuilder.AppendFormat( + "{0}=\"{1}\", ", authorizationPart.Key, Uri.EscapeDataString(authorizationPart.Value)); + } + authorizationHeaderBuilder.Length = authorizationHeaderBuilder.Length - 2; + + var request = new HttpRequestMessage(HttpMethod.Post, AccessTokenEndpoint); + request.Headers.Add("Authorization", authorizationHeaderBuilder.ToString()); + + var formPairs = new List>() + { + new KeyValuePair("oauth_verifier", verifier) + }; + + request.Content = new FormUrlEncodedContent(formPairs); + + HttpResponseMessage response = await httpClient.SendAsync(request, Request.CallCancelled); + + if (!response.IsSuccessStatusCode) + { + logger.WriteError("AccessToken request failed with a status code of " + response.StatusCode); + response.EnsureSuccessStatusCode(); // throw + } + + string responseText = await response.Content.ReadAsStringAsync(); + IFormCollection responseParameters = WebHelpers.ParseForm(responseText); + + return new AccessToken + { + Token = Uri.UnescapeDataString(responseParameters["oauth_token"]), + TokenSecret = Uri.UnescapeDataString(responseParameters["oauth_token_secret"]), + UserId = Uri.UnescapeDataString(responseParameters["user_nsid"]), + UserName = Uri.UnescapeDataString(responseParameters["username"]), + FullName = Uri.UnescapeDataString(responseParameters["fullname"]), + }; + } + + private static string GenerateTimeStamp() + { + TimeSpan secondsSinceUnixEpocStart = DateTime.UtcNow - Epoch; + return Convert.ToInt64(secondsSinceUnixEpocStart.TotalSeconds).ToString(CultureInfo.InvariantCulture); + } + + private static string ComputeSignature(string AppSecret, string tokenSecret, string signatureData) + { + using (var algorithm = new HMACSHA1()) + { + algorithm.Key = Encoding.ASCII.GetBytes( + string.Format(CultureInfo.InvariantCulture, + "{0}&{1}", + Uri.EscapeDataString(AppSecret), + string.IsNullOrEmpty(tokenSecret) ? string.Empty : Uri.EscapeDataString(tokenSecret))); + byte[] hash = algorithm.ComputeHash(Encoding.ASCII.GetBytes(signatureData)); + return Convert.ToBase64String(hash); + } + } + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/Flickr/FlickrAuthenticationMiddleware.cs b/Owin.Security.Providers/Flickr/FlickrAuthenticationMiddleware.cs new file mode 100644 index 0000000..3eb4be0 --- /dev/null +++ b/Owin.Security.Providers/Flickr/FlickrAuthenticationMiddleware.cs @@ -0,0 +1,90 @@ +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.Properties; +using Owin.Security.Providers.Flickr.Messages; +using Microsoft.Owin.Security.DataHandler.Encoder; + +namespace Owin.Security.Providers.Flickr +{ + public class FlickrAuthenticationMiddleware : AuthenticationMiddleware + { + private readonly HttpClient httpClient; + private readonly ILogger logger; + + public FlickrAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, + FlickrAuthenticationOptions options) + : base(next, options) + { + if (String.IsNullOrWhiteSpace(Options.AppKey)) + throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, + Resources.Exception_OptionMustBeProvided, "AppKey")); + if (String.IsNullOrWhiteSpace(Options.AppSecret)) + throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, + Resources.Exception_OptionMustBeProvided, "AppSecret")); + + logger = app.CreateLogger(); + + if (Options.Provider == null) + Options.Provider = new FlickrAuthenticationProvider(); + + if (Options.StateDataFormat == null) + { + IDataProtector dataProtector = app.CreateDataProtector( + typeof(FlickrAuthenticationMiddleware).FullName, + Options.AuthenticationType, "v1"); + Options.StateDataFormat = new SecureDataFormat( + Serializers.RequestToken, + dataProtector, + TextEncodings.Base64Url); + } + + if (String.IsNullOrEmpty(Options.SignInAsAuthenticationType)) + Options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(); + + httpClient = new HttpClient(ResolveHttpMessageHandler(Options)) + { + Timeout = Options.BackchannelTimeout, + MaxResponseContentBufferSize = 1024*1024*10 + }; + } + + /// + /// Provides the object for processing + /// authentication-related requests. + /// + /// + /// An configured with the + /// supplied to the constructor. + /// + protected override AuthenticationHandler CreateHandler() + { + return new FlickrAuthenticationHandler(httpClient, logger); + } + + private HttpMessageHandler ResolveHttpMessageHandler(FlickrAuthenticationOptions options) + { + HttpMessageHandler handler = options.BackchannelHttpHandler ?? new WebRequestHandler(); + + // If they provided a validator, apply it or fail. + if (options.BackchannelCertificateValidator != null) + { + // Set the cert validate callback + var webRequestHandler = handler as WebRequestHandler; + if (webRequestHandler == null) + { + throw new InvalidOperationException(Resources.Exception_ValidatorHandlerMismatch); + } + webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate; + } + + return handler; + } + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/Flickr/FlickrAuthenticationOptions.cs b/Owin.Security.Providers/Flickr/FlickrAuthenticationOptions.cs new file mode 100644 index 0000000..9dff4c5 --- /dev/null +++ b/Owin.Security.Providers/Flickr/FlickrAuthenticationOptions.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using Microsoft.Owin; +using Microsoft.Owin.Security; +using Owin.Security.Providers.Flickr.Messages; + +namespace Owin.Security.Providers.Flickr { + public class FlickrAuthenticationOptions : AuthenticationOptions + { + /// + /// Gets or sets the a pinned certificate validator to use to validate the endpoints used + /// in back channel communications belong to Flickr. + /// + /// + /// The pinned certificate validator. + /// + /// + /// 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 Flickr. + /// 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 Flickr. + /// + /// + /// The back channel timeout in milliseconds. + /// + 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. + /// Default value is "/signin-Flickr". + /// + 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 { return Description.Caption; } + set { Description.Caption = value; } + } + + /// + /// Gets or sets the Flickr supplied App Key + /// + public string AppKey { get; set; } + + /// + /// Gets or sets the Flickr supplied App Secret + /// + public string AppSecret { get; set; } + + /// + /// Gets or sets the used in the authentication events + /// + public IFlickrAuthenticationProvider Provider { get; set; } + + /// + /// A list of permissions to request. + /// + public string Scope { 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 data handled by the middleware. + /// + public ISecureDataFormat StateDataFormat { get; set; } + + /// + /// Initializes a new + /// + public FlickrAuthenticationOptions() + : base("Flickr") + { + Caption = Constants.DefaultAuthenticationType; + CallbackPath = new PathString("/signin-flickr"); + AuthenticationMode = AuthenticationMode.Passive; + Scope = "read"; + BackchannelTimeout = TimeSpan.FromSeconds(60); + } + } +} diff --git a/Owin.Security.Providers/Flickr/Messages/AccessToken.cs b/Owin.Security.Providers/Flickr/Messages/AccessToken.cs new file mode 100644 index 0000000..40c10dd --- /dev/null +++ b/Owin.Security.Providers/Flickr/Messages/AccessToken.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +namespace Owin.Security.Providers.Flickr.Messages +{ + /// + /// Flickr access token + /// + public class AccessToken : RequestToken + { + /// + /// Gets or sets the Flickr User ID + /// + public string UserId { get; set; } + + /// + /// Gets or sets the Flickr User Name + /// + public string UserName { get; set; } + + /// + /// Gets or sets the Flickr User Full Name + /// + public string FullName { get; set; } + } +} diff --git a/Owin.Security.Providers/Flickr/Messages/RequestToken.cs b/Owin.Security.Providers/Flickr/Messages/RequestToken.cs new file mode 100644 index 0000000..74748aa --- /dev/null +++ b/Owin.Security.Providers/Flickr/Messages/RequestToken.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using Microsoft.Owin.Security; + +namespace Owin.Security.Providers.Flickr.Messages +{ + /// + /// Yahoo request token + /// + public class RequestToken + { + /// + /// Gets or sets the Yahoo token + /// + public string Token { get; set; } + + /// + /// Gets or sets the Yahoo token secret + /// + public string TokenSecret { get; set; } + + public bool CallbackConfirmed { get; set; } + + /// + /// Gets or sets a property bag for common authentication properties + /// + public AuthenticationProperties Properties { get; set; } + } +} diff --git a/Owin.Security.Providers/Flickr/Messages/RequestTokenSerializer.cs b/Owin.Security.Providers/Flickr/Messages/RequestTokenSerializer.cs new file mode 100644 index 0000000..56b0253 --- /dev/null +++ b/Owin.Security.Providers/Flickr/Messages/RequestTokenSerializer.cs @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using Microsoft.Owin.Security; +using Microsoft.Owin.Security.DataHandler.Serializer; + +namespace Owin.Security.Providers.Flickr.Messages +{ + /// + /// Serializes and deserializes Yahoo request and access tokens so that they can be used by other application components. + /// + public class RequestTokenSerializer : IDataSerializer + { + private const int FormatVersion = 1; + + /// + /// Serialize a request token + /// + /// The token to serialize + /// A byte array containing the serialized token + [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "Dispose is idempotent")] + public virtual byte[] Serialize(RequestToken model) + { + using (var memory = new MemoryStream()) + { + using (var writer = new BinaryWriter(memory)) + { + Write(writer, model); + writer.Flush(); + return memory.ToArray(); + } + } + } + + /// + /// Deserializes a request token + /// + /// A byte array containing the serialized token + /// The Yahoo request token + [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "Dispose is idempotent")] + public virtual RequestToken Deserialize(byte[] data) + { + using (var memory = new MemoryStream(data)) + { + using (var reader = new BinaryReader(memory)) + { + return Read(reader); + } + } + } + + /// + /// Writes a Yahoo request token as a series of bytes. Used by the method. + /// + /// The writer to use in writing the token + /// The token to write + public static void Write(BinaryWriter writer, RequestToken token) + { + if (writer == null) + { + throw new ArgumentNullException("writer"); + } + if (token == null) + { + throw new ArgumentNullException("token"); + } + + writer.Write(FormatVersion); + writer.Write(token.Token); + writer.Write(token.TokenSecret); + writer.Write(token.CallbackConfirmed); + PropertiesSerializer.Write(writer, token.Properties); + } + + /// + /// Reads a Yahoo request token from a series of bytes. Used by the method. + /// + /// The reader to use in reading the token bytes + /// The token + public static RequestToken Read(BinaryReader reader) + { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + if (reader.ReadInt32() != FormatVersion) + { + return null; + } + + string token = reader.ReadString(); + string tokenSecret = reader.ReadString(); + bool callbackConfirmed = reader.ReadBoolean(); + AuthenticationProperties properties = PropertiesSerializer.Read(reader); + if (properties == null) + { + return null; + } + + return new RequestToken { Token = token, TokenSecret = tokenSecret, CallbackConfirmed = callbackConfirmed, Properties = properties }; + } + } +} diff --git a/Owin.Security.Providers/Flickr/Messages/Serializers.cs b/Owin.Security.Providers/Flickr/Messages/Serializers.cs new file mode 100644 index 0000000..bcf577d --- /dev/null +++ b/Owin.Security.Providers/Flickr/Messages/Serializers.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using Microsoft.Owin.Security.DataHandler.Serializer; + +namespace Owin.Security.Providers.Flickr.Messages +{ + /// + /// Provides access to a request token serializer + /// + public static class Serializers + { + static Serializers() + { + RequestToken = new RequestTokenSerializer(); + } + + /// + /// Gets or sets a statically-avaliable serializer object. The value for this property will be by default. + /// + public static IDataSerializer RequestToken { get; set; } + } +} diff --git a/Owin.Security.Providers/Flickr/Provider/FlickrAuthenticatedContext.cs b/Owin.Security.Providers/Flickr/Provider/FlickrAuthenticatedContext.cs new file mode 100644 index 0000000..d8bba84 --- /dev/null +++ b/Owin.Security.Providers/Flickr/Provider/FlickrAuthenticatedContext.cs @@ -0,0 +1,66 @@ +using System; +using System.Linq; +using System.Runtime.InteropServices; +using System.Security.Claims; +using Microsoft.Owin; +using Microsoft.Owin.Security; +using Microsoft.Owin.Security.Provider; +using Newtonsoft.Json.Linq; +using Owin.Security.Providers.Flickr.Messages; + +namespace Owin.Security.Providers.Flickr { + /// + /// Contains information about the login session as well as the user . + /// + public class FlickrAuthenticatedContext : BaseContext { + /// + /// Initializes a + /// + /// The OWIN environment + /// Flick access toke + public FlickrAuthenticatedContext(IOwinContext context, AccessToken accessToken) + : base(context) + { + FullName = accessToken.FullName; + UserId = accessToken.UserId; + UserName = accessToken.UserName; + AccessToken = accessToken.Token; + AccessTokenSecret = accessToken.TokenSecret; + } + + /// + /// Gets user full name + /// + public string FullName { get; private set; } + + /// + /// Gets the Flickr user ID + /// + public string UserId { get; private set; } + + /// + /// Gets the Flickr username + /// + public string UserName { get; private set; } + + /// + /// Gets the Flickr access token + /// + public string AccessToken { get; private set; } + + /// + /// Gets the Flickr access token secret + /// + public string AccessTokenSecret { get; private set; } + + /// + /// Gets the representing the user + /// + public ClaimsIdentity Identity { get; set; } + + /// + /// Gets or sets a property bag for common authentication properties + /// + public AuthenticationProperties Properties { get; set; } + } +} diff --git a/Owin.Security.Providers/Flickr/Provider/FlickrAuthenticationProvider.cs b/Owin.Security.Providers/Flickr/Provider/FlickrAuthenticationProvider.cs new file mode 100644 index 0000000..c043f44 --- /dev/null +++ b/Owin.Security.Providers/Flickr/Provider/FlickrAuthenticationProvider.cs @@ -0,0 +1,45 @@ +using System; +using System.Threading.Tasks; + +namespace Owin.Security.Providers.Flickr { + /// + /// Default implementation. + /// + public class FlickrAuthenticationProvider : IFlickrAuthenticationProvider { + /// + /// Initializes a + /// + public FlickrAuthenticationProvider() { + OnAuthenticated = context => Task.FromResult(null); + 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 Flickr succesfully authenticates a user + /// + /// Contains information about the login session as well as the user . + /// A representing the completed operation. + public virtual Task Authenticated(FlickrAuthenticatedContext context) { + return OnAuthenticated(context); + } + + /// + /// Invoked prior to the being saved in a local cookie and the browser being redirected to the originally requested URL. + /// + /// + /// A representing the completed operation. + public virtual Task ReturnEndpoint(FlickrReturnEndpointContext context) { + return OnReturnEndpoint(context); + } + } +} diff --git a/Owin.Security.Providers/Flickr/Provider/FlickrReturnEndpointContext.cs b/Owin.Security.Providers/Flickr/Provider/FlickrReturnEndpointContext.cs new file mode 100644 index 0000000..1b9ad25 --- /dev/null +++ b/Owin.Security.Providers/Flickr/Provider/FlickrReturnEndpointContext.cs @@ -0,0 +1,21 @@ +using Microsoft.Owin; +using Microsoft.Owin.Security; +using Microsoft.Owin.Security.Provider; + +namespace Owin.Security.Providers.Flickr { + /// + /// Provides context information to middleware providers. + /// + public class FlickrReturnEndpointContext : ReturnEndpointContext { + /// + /// + /// + /// OWIN environment + /// The authentication ticket + public FlickrReturnEndpointContext( + IOwinContext context, + AuthenticationTicket ticket) + : base(context, ticket) { + } + } +} diff --git a/Owin.Security.Providers/Flickr/Provider/IFlickrAuthenticationProvider.cs b/Owin.Security.Providers/Flickr/Provider/IFlickrAuthenticationProvider.cs new file mode 100644 index 0000000..96d54d7 --- /dev/null +++ b/Owin.Security.Providers/Flickr/Provider/IFlickrAuthenticationProvider.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Owin.Security.Providers.Flickr { + /// + /// Specifies callback methods which the invokes to enable developer control over the authentication process. /> + /// + public interface IFlickrAuthenticationProvider { + /// + /// Invoked whenever Flickr succesfully authenticates a user + /// + /// Contains information about the login session as well as the user . + /// A representing the completed operation. + Task Authenticated(FlickrAuthenticatedContext context); + + /// + /// Invoked prior to the being saved in a local cookie and the browser being redirected to the originally requested URL. + /// + /// + /// A representing the completed operation. + Task ReturnEndpoint(FlickrReturnEndpointContext context); + } +} diff --git a/Owin.Security.Providers/Owin.Security.Providers.csproj b/Owin.Security.Providers/Owin.Security.Providers.csproj index a638670..3364ab0 100644 --- a/Owin.Security.Providers/Owin.Security.Providers.csproj +++ b/Owin.Security.Providers/Owin.Security.Providers.csproj @@ -112,6 +112,19 @@ + + + + + + + + + + + + + diff --git a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs index bf04d4a..cdfdb3b 100755 --- a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs +++ b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs @@ -10,6 +10,7 @@ using Owin.Security.Providers.BattleNet; using Owin.Security.Providers.Buffer; using Owin.Security.Providers.Dropbox; using Owin.Security.Providers.EveOnline; +using Owin.Security.Providers.Flickr; using Owin.Security.Providers.Foursquare; using Owin.Security.Providers.GitHub; using Owin.Security.Providers.GooglePlus; @@ -209,6 +210,8 @@ namespace OwinOAuthProvidersDemo //app.UseFoursquareAuthentication( // clientId: "", // clientSecret: ""); + + //app.UseFlickrAuthentication("", ""); } } } \ No newline at end of file From 5a8dcfbd4bf827f746b297014c81f92d6bff9c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Bertrand?= Date: Wed, 25 Mar 2015 07:15:46 +0100 Subject: [PATCH 04/22] Simplify Steam auth options overrides --- .../Steam/SteamAuthenticationExtensions.cs | 10 ++-------- .../Steam/SteamAuthenticationOptions.cs | 11 ++++++++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Owin.Security.Providers/Steam/SteamAuthenticationExtensions.cs b/Owin.Security.Providers/Steam/SteamAuthenticationExtensions.cs index 96328a0..d3b3ba9 100644 --- a/Owin.Security.Providers/Steam/SteamAuthenticationExtensions.cs +++ b/Owin.Security.Providers/Steam/SteamAuthenticationExtensions.cs @@ -1,5 +1,4 @@ -using Microsoft.Owin; -using System; +using System; namespace Owin.Security.Providers.Steam { @@ -25,8 +24,7 @@ namespace Owin.Security.Providers.Steam throw new ArgumentNullException("options"); } - app.Use(typeof(SteamAuthenticationMiddleware), app, options); - return app; + return app.Use(typeof(SteamAuthenticationMiddleware), app, options); } /// @@ -39,10 +37,6 @@ namespace Owin.Security.Providers.Steam { return UseSteamAuthentication(app, new SteamAuthenticationOptions { - ProviderDiscoveryUri = "http://steamcommunity.com/openid/", - Caption = "Steam", - AuthenticationType = "Steam", - CallbackPath = new PathString("/signin-openidsteam"), ApplicationKey = applicationKey }); } diff --git a/Owin.Security.Providers/Steam/SteamAuthenticationOptions.cs b/Owin.Security.Providers/Steam/SteamAuthenticationOptions.cs index 080c758..33849cc 100644 --- a/Owin.Security.Providers/Steam/SteamAuthenticationOptions.cs +++ b/Owin.Security.Providers/Steam/SteamAuthenticationOptions.cs @@ -1,9 +1,18 @@ -using Owin.Security.Providers.OpenID; +using Microsoft.Owin; +using Owin.Security.Providers.OpenID; namespace Owin.Security.Providers.Steam { public sealed class SteamAuthenticationOptions : OpenIDAuthenticationOptions { public string ApplicationKey { get; set; } + + public SteamAuthenticationOptions() + { + ProviderDiscoveryUri = "http://steamcommunity.com/openid/"; + Caption = "Steam"; + AuthenticationType = "Steam"; + CallbackPath = new PathString("/signin-openidsteam"); + } } } From 5322c9310cb4075bd6d1b9abd4dcfe154acab701 Mon Sep 17 00:00:00 2001 From: ByteBlast Date: Wed, 25 Mar 2015 13:44:19 +0000 Subject: [PATCH 05/22] Corrected typo --- .../Foursquare/Provider/FoursquareAuthenticatedContext.cs | 2 +- .../Foursquare/Provider/FoursquareAuthenticationProvider.cs | 2 +- .../Foursquare/Provider/IFoursquareAuthenticationProvider.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs index d7a5ae1..be337f1 100644 --- a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs +++ b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs @@ -17,7 +17,7 @@ namespace Owin.Security.Providers.Foursquare.Provider /// /// The OWIN environment /// The JSON-serialized user - /// GitHub Access token + /// Foursquare Access token public FoursquareAuthenticatedContext(IOwinContext context, JObject user, string accessToken) : base(context) { diff --git a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticationProvider.cs b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticationProvider.cs index e1e682d..8890a96 100644 --- a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticationProvider.cs +++ b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticationProvider.cs @@ -28,7 +28,7 @@ namespace Owin.Security.Providers.Foursquare.Provider public Func OnReturnEndpoint { get; set; } /// - /// Invoked whenever GitHub succesfully authenticates a user + /// Invoked whenever Foursquare succesfully authenticates a user /// /// Contains information about the login session as well as the user . /// A representing the completed operation. diff --git a/Owin.Security.Providers/Foursquare/Provider/IFoursquareAuthenticationProvider.cs b/Owin.Security.Providers/Foursquare/Provider/IFoursquareAuthenticationProvider.cs index 3cc8d38..c6f79f3 100644 --- a/Owin.Security.Providers/Foursquare/Provider/IFoursquareAuthenticationProvider.cs +++ b/Owin.Security.Providers/Foursquare/Provider/IFoursquareAuthenticationProvider.cs @@ -8,7 +8,7 @@ namespace Owin.Security.Providers.Foursquare.Provider public interface IFoursquareAuthenticationProvider { /// - /// Invoked whenever GitHub succesfully authenticates a user + /// Invoked whenever Foursquare succesfully authenticates a user /// /// Contains information about the login session as well as the user . /// A representing the completed operation. From 5efd13c4eb088eddb77c3ea02120d6a90e352899 Mon Sep 17 00:00:00 2001 From: ByteBlast Date: Wed, 25 Mar 2015 13:45:58 +0000 Subject: [PATCH 06/22] Normalized indentation --- .../FoursquareAuthenticationHandler.cs | 316 +++++++++--------- .../FoursquareAuthenticationMiddleware.cs | 124 +++---- .../FoursquareAuthenticationOptions.cs | 148 ++++---- .../FoursquareAuthenticatedContext.cs | 302 ++++++++--------- .../FoursquareAuthenticationProvider.cs | 78 ++--- .../FoursquareReturnEndpointContext.cs | 30 +- .../IFoursquareAuthenticationProvider.cs | 34 +- 7 files changed, 516 insertions(+), 516 deletions(-) diff --git a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationHandler.cs b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationHandler.cs index 0006af0..cfe1140 100644 --- a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationHandler.cs +++ b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationHandler.cs @@ -13,74 +13,74 @@ using Owin.Security.Providers.Foursquare.Provider; namespace Owin.Security.Providers.Foursquare { - public class FoursquareAuthenticationHandler : AuthenticationHandler - { - private const string AuthorizationEndpoint = "https://foursquare.com/oauth2/authenticate"; - private const string TokenEndpoint = "https://foursquare.com/oauth2/access_token"; - private const string GraphApiEndpoint = "https://api.foursquare.com/v2/users/self"; - private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; + public class FoursquareAuthenticationHandler : AuthenticationHandler + { + private const string AuthorizationEndpoint = "https://foursquare.com/oauth2/authenticate"; + private const string TokenEndpoint = "https://foursquare.com/oauth2/access_token"; + private const string GraphApiEndpoint = "https://api.foursquare.com/v2/users/self"; + private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; - private static readonly DateTime VersionDate = new DateTime(2015, 3, 19); + private static readonly DateTime VersionDate = new DateTime(2015, 3, 19); - private readonly ILogger _logger; - private readonly HttpClient _httpClient; + private readonly ILogger _logger; + private readonly HttpClient _httpClient; - public FoursquareAuthenticationHandler(HttpClient httpClient, ILogger logger) - { - this._httpClient = httpClient; - this._logger = logger; - } + public FoursquareAuthenticationHandler(HttpClient httpClient, ILogger logger) + { + this._httpClient = httpClient; + this._logger = logger; + } - public override async Task InvokeAsync() - { - if ((string.IsNullOrEmpty(this.Options.CallbackPath) == false) && (this.Options.CallbackPath == this.Request.Path.ToString())) - { - return await this.InvokeReturnPathAsync(); - } + public override async Task InvokeAsync() + { + if ((string.IsNullOrEmpty(this.Options.CallbackPath) == false) && (this.Options.CallbackPath == this.Request.Path.ToString())) + { + return await this.InvokeReturnPathAsync(); + } - return false; - } + return false; + } - protected override async Task AuthenticateCoreAsync() - { - this._logger.WriteVerbose("AuthenticateCore"); + protected override async Task AuthenticateCoreAsync() + { + this._logger.WriteVerbose("AuthenticateCore"); - AuthenticationProperties properties = null; + AuthenticationProperties properties = null; - try - { - string code = null; - string state = null; + try + { + string code = null; + string state = null; - var query = this.Request.Query; - var values = query.GetValues("code"); + var query = this.Request.Query; + var values = query.GetValues("code"); - if ((values != null) && (values.Count == 1)) - { - code = values[0]; - } + if ((values != null) && (values.Count == 1)) + { + code = values[0]; + } - values = query.GetValues("state"); + values = query.GetValues("state"); - if ((values != null) && (values.Count == 1)) - { - state = values[0]; - } + if ((values != null) && (values.Count == 1)) + { + state = values[0]; + } - properties = this.Options.StateDataFormat.Unprotect(state); + properties = this.Options.StateDataFormat.Unprotect(state); - if (properties == null) - { - return null; - } + if (properties == null) + { + return null; + } - // OAuth2 10.12 CSRF - if (this.ValidateCorrelationId(properties, this._logger) == false) - { - return new AuthenticationTicket(null, properties); - } + // OAuth2 10.12 CSRF + if (this.ValidateCorrelationId(properties, this._logger) == false) + { + return new AuthenticationTicket(null, properties); + } - var tokenRequestParameters = new List>() + var tokenRequestParameters = new List>() { new KeyValuePair("client_id", this.Options.ClientId), new KeyValuePair("client_secret", this.Options.ClientSecret), @@ -89,153 +89,153 @@ namespace Owin.Security.Providers.Foursquare new KeyValuePair("code", code), }; - var requestContent = new FormUrlEncodedContent(tokenRequestParameters); + var requestContent = new FormUrlEncodedContent(tokenRequestParameters); - var response = await this._httpClient.PostAsync(TokenEndpoint, requestContent, this.Request.CallCancelled); - response.EnsureSuccessStatusCode(); + var response = await this._httpClient.PostAsync(TokenEndpoint, requestContent, this.Request.CallCancelled); + response.EnsureSuccessStatusCode(); - var oauthTokenResponse = await response.Content.ReadAsStringAsync(); + var oauthTokenResponse = await response.Content.ReadAsStringAsync(); - var oauth2Token = JObject.Parse(oauthTokenResponse); - var accessToken = oauth2Token["access_token"].Value(); + var oauth2Token = JObject.Parse(oauthTokenResponse); + var accessToken = oauth2Token["access_token"].Value(); - if (string.IsNullOrWhiteSpace(accessToken) == true) - { - this._logger.WriteWarning("Access token was not found"); - return new AuthenticationTicket(null, properties); - } + if (string.IsNullOrWhiteSpace(accessToken) == true) + { + this._logger.WriteWarning("Access token was not found"); + return new AuthenticationTicket(null, properties); + } - var graphResponse = await this._httpClient.GetAsync(GraphApiEndpoint + "?oauth_token=" + Uri.EscapeDataString(accessToken) + "&m=foursquare&v=" + VersionDate.ToString("yyyyyMMdd"), this.Request.CallCancelled); - graphResponse.EnsureSuccessStatusCode(); + var graphResponse = await this._httpClient.GetAsync(GraphApiEndpoint + "?oauth_token=" + Uri.EscapeDataString(accessToken) + "&m=foursquare&v=" + VersionDate.ToString("yyyyyMMdd"), this.Request.CallCancelled); + graphResponse.EnsureSuccessStatusCode(); - var accountstring = await graphResponse.Content.ReadAsStringAsync(); - var accountInformation = JObject.Parse(accountstring); - var user = (JObject)accountInformation["response"]["user"]; + var accountstring = await graphResponse.Content.ReadAsStringAsync(); + var accountInformation = JObject.Parse(accountstring); + var user = (JObject)accountInformation["response"]["user"]; - var context = new FoursquareAuthenticatedContext(this.Context, user, accessToken); + var context = new FoursquareAuthenticatedContext(this.Context, user, accessToken); - context.Identity = new ClaimsIdentity( - new[] + context.Identity = new ClaimsIdentity( + new[] { new Claim(ClaimTypes.NameIdentifier, context.Id, XmlSchemaString, this.Options.AuthenticationType), new Claim(ClaimTypes.Name, context.Name, XmlSchemaString, this.Options.AuthenticationType), new Claim("urn:foursquare:id", context.Id, XmlSchemaString, this.Options.AuthenticationType), new Claim("urn:foursquare:name", context.Name, XmlSchemaString, this.Options.AuthenticationType), }, - this.Options.AuthenticationType, - ClaimsIdentity.DefaultNameClaimType, - ClaimsIdentity.DefaultRoleClaimType); + this.Options.AuthenticationType, + ClaimsIdentity.DefaultNameClaimType, + ClaimsIdentity.DefaultRoleClaimType); - if (string.IsNullOrWhiteSpace(context.Email) == false) - { - context.Identity.AddClaim(new Claim(ClaimTypes.Email, context.Email, XmlSchemaString, this.Options.AuthenticationType)); - } + if (string.IsNullOrWhiteSpace(context.Email) == false) + { + context.Identity.AddClaim(new Claim(ClaimTypes.Email, context.Email, XmlSchemaString, this.Options.AuthenticationType)); + } - if (string.IsNullOrWhiteSpace(context.Twitter) == false) - { - context.Identity.AddClaim(new Claim("urn:foursquare:twitter", context.Twitter, XmlSchemaString, this.Options.AuthenticationType)); - } + if (string.IsNullOrWhiteSpace(context.Twitter) == false) + { + context.Identity.AddClaim(new Claim("urn:foursquare:twitter", context.Twitter, XmlSchemaString, this.Options.AuthenticationType)); + } - await this.Options.Provider.Authenticated(context); + await this.Options.Provider.Authenticated(context); - context.Properties = properties; + context.Properties = properties; - return new AuthenticationTicket(context.Identity, context.Properties); - } - catch (Exception ex) - { - this._logger.WriteWarning("Authentication failed", ex); - return new AuthenticationTicket(null, properties); - } - } + return new AuthenticationTicket(context.Identity, context.Properties); + } + catch (Exception ex) + { + this._logger.WriteWarning("Authentication failed", ex); + return new AuthenticationTicket(null, properties); + } + } - protected override Task ApplyResponseChallengeAsync() - { - this._logger.WriteVerbose("ApplyResponseChallenge"); + protected override Task ApplyResponseChallengeAsync() + { + this._logger.WriteVerbose("ApplyResponseChallenge"); - if (this.Response.StatusCode != (int)HttpStatusCode.Unauthorized) - { - return Task.FromResult(null); - } + if (this.Response.StatusCode != (int)HttpStatusCode.Unauthorized) + { + return Task.FromResult(null); + } - var challenge = Helper.LookupChallenge(this.Options.AuthenticationType, this.Options.AuthenticationMode); + var challenge = Helper.LookupChallenge(this.Options.AuthenticationType, this.Options.AuthenticationMode); - if (challenge != null) - { - var baseUri = this.Request.Scheme + Uri.SchemeDelimiter + this.Request.Host + this.Request.PathBase; - var currentUri = baseUri + this.Request.Path + this.Request.QueryString; - var redirectUri = baseUri + this.Options.CallbackPath; + if (challenge != null) + { + var baseUri = this.Request.Scheme + Uri.SchemeDelimiter + this.Request.Host + this.Request.PathBase; + var currentUri = baseUri + this.Request.Path + this.Request.QueryString; + var redirectUri = baseUri + this.Options.CallbackPath; - var extra = challenge.Properties; + var extra = challenge.Properties; - if (string.IsNullOrEmpty(extra.RedirectUri) == true) - { - extra.RedirectUri = currentUri; - } + if (string.IsNullOrEmpty(extra.RedirectUri) == true) + { + extra.RedirectUri = currentUri; + } - // OAuth2 10.12 CSRF - this.GenerateCorrelationId(extra); + // OAuth2 10.12 CSRF + this.GenerateCorrelationId(extra); - var state = this.Options.StateDataFormat.Protect(extra); + var state = this.Options.StateDataFormat.Protect(extra); - var authorizationEndpoint = AuthorizationEndpoint + - "?client_id=" + Uri.EscapeDataString(this.Options.ClientId) + - "&response_type=code" + - "&redirect_uri=" + Uri.EscapeDataString(redirectUri) + - "&state=" + Uri.EscapeDataString(state); + var authorizationEndpoint = AuthorizationEndpoint + + "?client_id=" + Uri.EscapeDataString(this.Options.ClientId) + + "&response_type=code" + + "&redirect_uri=" + Uri.EscapeDataString(redirectUri) + + "&state=" + Uri.EscapeDataString(state); - this.Response.Redirect(authorizationEndpoint); - } + this.Response.Redirect(authorizationEndpoint); + } - return Task.FromResult(null); - } + return Task.FromResult(null); + } - public async Task InvokeReturnPathAsync() - { - this._logger.WriteVerbose("InvokeReturnPath"); + public async Task InvokeReturnPathAsync() + { + this._logger.WriteVerbose("InvokeReturnPath"); - var model = await this.AuthenticateAsync(); + var model = await this.AuthenticateAsync(); - var context = new FoursquareReturnEndpointContext(Context, model); - context.SignInAsAuthenticationType = this.Options.SignInAsAuthenticationType; - context.RedirectUri = model.Properties.RedirectUri; + var context = new FoursquareReturnEndpointContext(Context, model); + context.SignInAsAuthenticationType = this.Options.SignInAsAuthenticationType; + context.RedirectUri = model.Properties.RedirectUri; - model.Properties.RedirectUri = null; + model.Properties.RedirectUri = null; - await this.Options.Provider.ReturnEndpoint(context); + await this.Options.Provider.ReturnEndpoint(context); - if ((context.SignInAsAuthenticationType != null) && (context.Identity != null)) - { - var signInIdentity = context.Identity; + if ((context.SignInAsAuthenticationType != null) && (context.Identity != null)) + { + var signInIdentity = context.Identity; - if (string.Equals(signInIdentity.AuthenticationType, context.SignInAsAuthenticationType, StringComparison.Ordinal) == false) - { - signInIdentity = new ClaimsIdentity(signInIdentity.Claims, context.SignInAsAuthenticationType, signInIdentity.NameClaimType, signInIdentity.RoleClaimType); - } + if (string.Equals(signInIdentity.AuthenticationType, context.SignInAsAuthenticationType, StringComparison.Ordinal) == false) + { + signInIdentity = new ClaimsIdentity(signInIdentity.Claims, context.SignInAsAuthenticationType, signInIdentity.NameClaimType, signInIdentity.RoleClaimType); + } - this.Context.Authentication.SignIn(context.Properties, signInIdentity); - } + this.Context.Authentication.SignIn(context.Properties, signInIdentity); + } - if ((context.IsRequestCompleted == false) && (context.RedirectUri != null)) - { - if (context.Identity == null) - { - context.RedirectUri = WebUtilities.AddQueryString(context.RedirectUri, "error", "access_denied"); - } + if ((context.IsRequestCompleted == false) && (context.RedirectUri != null)) + { + if (context.Identity == null) + { + context.RedirectUri = WebUtilities.AddQueryString(context.RedirectUri, "error", "access_denied"); + } - this.Response.Redirect(context.RedirectUri); + this.Response.Redirect(context.RedirectUri); - context.RequestCompleted(); - } + context.RequestCompleted(); + } - return context.IsRequestCompleted; - } + return context.IsRequestCompleted; + } - private string GenerateRedirectUri() - { - var requestPrefix = this.Request.Scheme + "://" + this.Request.Host; - var redirectUri = requestPrefix + this.RequestPathBase + this.Options.CallbackPath; - return redirectUri; - } - } + private string GenerateRedirectUri() + { + var requestPrefix = this.Request.Scheme + "://" + this.Request.Host; + var redirectUri = requestPrefix + this.RequestPathBase + this.Options.CallbackPath; + return redirectUri; + } + } } \ No newline at end of file diff --git a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationMiddleware.cs b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationMiddleware.cs index f12f0d5..300e5f2 100644 --- a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationMiddleware.cs @@ -10,80 +10,80 @@ using Owin.Security.Providers.Foursquare.Provider; namespace Owin.Security.Providers.Foursquare { - public class FoursquareAuthenticationMiddleware : AuthenticationMiddleware - { - private readonly ILogger _logger; - private readonly HttpClient _httpClient; + public class FoursquareAuthenticationMiddleware : AuthenticationMiddleware + { + private readonly ILogger _logger; + private readonly HttpClient _httpClient; - public FoursquareAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, FoursquareAuthenticationOptions options) - : base(next, options) - { - if (string.IsNullOrWhiteSpace(this.Options.ClientId) == true) - { - throw new ArgumentException("The 'ClientId' must be provided."); - } + public FoursquareAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, FoursquareAuthenticationOptions options) + : base(next, options) + { + if (string.IsNullOrWhiteSpace(this.Options.ClientId) == true) + { + throw new ArgumentException("The 'ClientId' must be provided."); + } - if (string.IsNullOrWhiteSpace(this.Options.ClientSecret) == true) - { - throw new ArgumentException("The 'ClientSecret' option must be provided."); - } + if (string.IsNullOrWhiteSpace(this.Options.ClientSecret) == true) + { + throw new ArgumentException("The 'ClientSecret' option must be provided."); + } - this._logger = app.CreateLogger(); + this._logger = app.CreateLogger(); - if (this.Options.Provider == null) - { - this.Options.Provider = new FoursquareAuthenticationProvider(); - } + if (this.Options.Provider == null) + { + this.Options.Provider = new FoursquareAuthenticationProvider(); + } - if (this.Options.StateDataFormat == null) - { - var dataProtector = app.CreateDataProtector(typeof(FoursquareAuthenticationMiddleware).FullName, this.Options.AuthenticationType, "v1"); - this.Options.StateDataFormat = new PropertiesDataFormat(dataProtector); - } + if (this.Options.StateDataFormat == null) + { + var dataProtector = app.CreateDataProtector(typeof(FoursquareAuthenticationMiddleware).FullName, this.Options.AuthenticationType, "v1"); + this.Options.StateDataFormat = new PropertiesDataFormat(dataProtector); + } - if (string.IsNullOrEmpty(this.Options.SignInAsAuthenticationType) == true) - { - this.Options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(); - } + if (string.IsNullOrEmpty(this.Options.SignInAsAuthenticationType) == true) + { + this.Options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(); + } - this._httpClient = new HttpClient(ResolveHttpMessageHandler(this.Options)); - this._httpClient.Timeout = this.Options.BackchannelTimeout; - this._httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB - } + this._httpClient = new HttpClient(ResolveHttpMessageHandler(this.Options)); + this._httpClient.Timeout = this.Options.BackchannelTimeout; + this._httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB + } - /// - /// Provides the object for processing - /// authentication-related requests. - /// - /// - /// An configured with the - /// supplied to the constructor. - /// - protected override AuthenticationHandler CreateHandler() - { - return new FoursquareAuthenticationHandler(this._httpClient, this._logger); - } + /// + /// Provides the object for processing + /// authentication-related requests. + /// + /// + /// An configured with the + /// supplied to the constructor. + /// + protected override AuthenticationHandler CreateHandler() + { + return new FoursquareAuthenticationHandler(this._httpClient, this._logger); + } - private static HttpMessageHandler ResolveHttpMessageHandler(FoursquareAuthenticationOptions options) - { - var handler = options.BackchannelHttpHandler ?? new WebRequestHandler(); + private static HttpMessageHandler ResolveHttpMessageHandler(FoursquareAuthenticationOptions options) + { + var handler = options.BackchannelHttpHandler ?? new WebRequestHandler(); - // If they provided a validator, apply it or fail. - if (options.BackchannelCertificateValidator != null) - { - // Set the cert validate callback - var webRequestHandler = handler as WebRequestHandler; + // If they provided a validator, apply it or fail. + if (options.BackchannelCertificateValidator != null) + { + // Set the cert validate callback + var webRequestHandler = handler as WebRequestHandler; - if (webRequestHandler == null) - { - throw new InvalidOperationException("Validator Handler Mismatch"); - } + if (webRequestHandler == null) + { + throw new InvalidOperationException("Validator Handler Mismatch"); + } - webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate; - } + webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate; + } - return handler; - } + return handler; + } - } + } } \ No newline at end of file diff --git a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationOptions.cs b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationOptions.cs index e1356d2..41d8ab9 100644 --- a/Owin.Security.Providers/Foursquare/FoursquareAuthenticationOptions.cs +++ b/Owin.Security.Providers/Foursquare/FoursquareAuthenticationOptions.cs @@ -6,88 +6,88 @@ using Owin.Security.Providers.Foursquare.Provider; namespace Owin.Security.Providers.Foursquare { - public class FoursquareAuthenticationOptions : AuthenticationOptions - { - /// - /// Initializes a new - /// - public FoursquareAuthenticationOptions() - : base(Constants.DefaultAuthenticationType) - { - this.Caption = Constants.DefaultAuthenticationType; - this.CallbackPath = "/signin-foursquare"; - this.AuthenticationMode = AuthenticationMode.Passive; - this.BackchannelTimeout = TimeSpan.FromSeconds(60); - } + public class FoursquareAuthenticationOptions : AuthenticationOptions + { + /// + /// Initializes a new + /// + public FoursquareAuthenticationOptions() + : base(Constants.DefaultAuthenticationType) + { + this.Caption = Constants.DefaultAuthenticationType; + this.CallbackPath = "/signin-foursquare"; + this.AuthenticationMode = AuthenticationMode.Passive; + this.BackchannelTimeout = TimeSpan.FromSeconds(60); + } - /// - /// Gets or sets the Foursquare supplied Client ID - /// - public string ClientId { get; set; } + /// + /// Gets or sets the Foursquare supplied Client ID + /// + public string ClientId { get; set; } - /// - /// Gets or sets the Foursquare supplied Client Secret - /// - public string ClientSecret { get; set; } + /// + /// Gets or sets the Foursquare supplied Client Secret + /// + public string ClientSecret { get; set; } - /// - /// Gets or sets the a pinned certificate validator to use to validate the endpoints used - /// in back channel communications belong to Foursquare. - /// - /// - /// The pinned certificate validator. - /// - /// - /// 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; } + /// + /// Gets or sets the a pinned certificate validator to use to validate the endpoints used + /// in back channel communications belong to Foursquare. + /// + /// + /// The pinned certificate validator. + /// + /// + /// 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; } - /// - /// Gets or sets timeout value in milliseconds for back channel communications with Foursquare. - /// - /// - /// The back channel timeout in milliseconds. - /// - public TimeSpan BackchannelTimeout { get; set; } + /// + /// Gets or sets timeout value in milliseconds for back channel communications with Foursquare. + /// + /// + /// The back channel timeout in milliseconds. + /// + public TimeSpan BackchannelTimeout { get; set; } - /// - /// The HttpMessageHandler used to communicate with Foursquare. - /// This cannot be set at the same time as BackchannelCertificateValidator unless the value - /// can be downcast to a WebRequestHandler. - /// - public HttpMessageHandler BackchannelHttpHandler { get; set; } + /// + /// The HttpMessageHandler used to communicate with Foursquare. + /// This cannot be set at the same time as BackchannelCertificateValidator unless the value + /// can be downcast to a WebRequestHandler. + /// + public HttpMessageHandler BackchannelHttpHandler { 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. - /// Default value is "/signin-foursquare". - /// - public string CallbackPath { 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. + /// Default value is "/signin-foursquare". + /// + public string CallbackPath { 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 name of another authentication middleware which will be responsible for actually issuing a user + /// . + /// + public string SignInAsAuthenticationType { get; set; } - /// - /// Gets or sets the used in the authentication events - /// - public IFoursquareAuthenticationProvider Provider { get; set; } + /// + /// Gets or sets the used in the authentication events + /// + public IFoursquareAuthenticationProvider Provider { get; set; } - /// - /// Gets or sets the type used to secure data handled by the middleware. - /// - public ISecureDataFormat StateDataFormat { get; set; } + /// + /// Gets or sets the type used to secure data handled by the middleware. + /// + public ISecureDataFormat StateDataFormat { get; set; } - /// - /// Get or sets the text that the user can display on a sign in user interface. - /// - public string Caption - { - get { return this.Description.Caption; } - set { this.Description.Caption = value; } - } - } + /// + /// Get or sets the text that the user can display on a sign in user interface. + /// + public string Caption + { + get { return this.Description.Caption; } + set { this.Description.Caption = value; } + } + } } \ No newline at end of file diff --git a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs index be337f1..7454588 100644 --- a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs +++ b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs @@ -7,162 +7,162 @@ using Newtonsoft.Json.Linq; namespace Owin.Security.Providers.Foursquare.Provider { - /// - /// Contains information about the login session as well as the user . - /// - public class FoursquareAuthenticatedContext : BaseContext - { - /// - /// Initializes a - /// - /// The OWIN environment - /// The JSON-serialized user + /// + /// Contains information about the login session as well as the user . + /// + public class FoursquareAuthenticatedContext : BaseContext + { + /// + /// Initializes a + /// + /// The OWIN environment + /// The JSON-serialized user /// Foursquare Access token - public FoursquareAuthenticatedContext(IOwinContext context, JObject user, string accessToken) - : base(context) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } + public FoursquareAuthenticatedContext(IOwinContext context, JObject user, string accessToken) + : base(context) + { + if (user == null) + { + throw new ArgumentNullException("user"); + } - this.User = user; - this.AccessToken = accessToken; + this.User = user; + this.AccessToken = accessToken; - var userId = this.User["id"]; + var userId = this.User["id"]; - if (userId == null) - { - throw new ArgumentException("The user does not have an id.", "user"); - } + if (userId == null) + { + throw new ArgumentException("The user does not have an id.", "user"); + } - this.Id = TryGetValue(user, "id"); - this.FirstName = TryGetValue(user, "firstName"); - this.LastName = TryGetValue(user, "lastName"); - this.Name = this.FirstName + " " + this.LastName; - this.Gender = TryGetValue(user, "gender"); - this.Photo = TryGetValue(user, "photo"); - this.Friends = TryGetValue(user, "friends"); - this.HomeCity = TryGetValue(user, "homeCity"); - this.Bio = TryGetValue(user, "bio"); - this.Contact = TryGetValue(user, "contact"); - this.Phone = TryGetValue(JObject.Parse(this.Contact), "phone"); - this.Email = TryGetValue(JObject.Parse(this.Contact), "email"); - this.Twitter = TryGetValue(JObject.Parse(this.Contact), "twitter"); - this.Facebook = TryGetValue(JObject.Parse(this.Contact), "facebook"); - this.Badges = TryGetValue(user, "badges"); - this.Mayorships = TryGetValue(user, "mayorships"); - this.Checkins = TryGetValue(user, "checkins"); - this.Photos = TryGetValue(user, "photos"); - this.Scores = TryGetValue(user, "scores"); - this.Link = "https://foursquare.com/user/" + this.Id; - } + this.Id = TryGetValue(user, "id"); + this.FirstName = TryGetValue(user, "firstName"); + this.LastName = TryGetValue(user, "lastName"); + this.Name = this.FirstName + " " + this.LastName; + this.Gender = TryGetValue(user, "gender"); + this.Photo = TryGetValue(user, "photo"); + this.Friends = TryGetValue(user, "friends"); + this.HomeCity = TryGetValue(user, "homeCity"); + this.Bio = TryGetValue(user, "bio"); + this.Contact = TryGetValue(user, "contact"); + this.Phone = TryGetValue(JObject.Parse(this.Contact), "phone"); + this.Email = TryGetValue(JObject.Parse(this.Contact), "email"); + this.Twitter = TryGetValue(JObject.Parse(this.Contact), "twitter"); + this.Facebook = TryGetValue(JObject.Parse(this.Contact), "facebook"); + this.Badges = TryGetValue(user, "badges"); + this.Mayorships = TryGetValue(user, "mayorships"); + this.Checkins = TryGetValue(user, "checkins"); + this.Photos = TryGetValue(user, "photos"); + this.Scores = TryGetValue(user, "scores"); + this.Link = "https://foursquare.com/user/" + this.Id; + } - /// - /// Gets the JSON-serialized user - /// - /// - /// Contains the Foursquare user obtained from the User Info endpoint. By default this is https://api.foursquare.com/v2/users/self but it can be - /// overridden in the options - /// - public JObject User { get; private set; } - /// - /// Gets the Foursquare access token - /// - public string AccessToken { get; private set; } - /// - /// Gets the Foursquare user ID - /// - public string Id { get; private set; } - /// - /// Gets the user's first name - /// - public string FirstName { get; private set; } - /// - /// Gets the user's last name - /// - public string LastName { get; private set; } - /// - /// Gets the user's full name - /// - public string Name { get; private set; } - /// - /// Gets the user's gender - /// - public string Gender { get; private set; } - /// - /// Gets the user's photo - /// - public string Photo { get; private set; } - /// - /// Gets the user's friends - /// - public string Friends { get; private set; } - /// - /// Gets the user's home city - /// - public string HomeCity { get; private set; } - /// - /// Gets the user's biography - /// - public string Bio { get; private set; } - /// - /// Gets the user's contact - /// - public string Contact { get; private set; } - /// - /// Gets the user's phone - /// - public string Phone { get; private set; } - /// - /// Gets the user's email - /// - public string Email { get; private set; } - /// - /// Gets the user's Twitter handle - /// - public string Twitter { get; private set; } - /// - /// Gets the user's Facebook id - /// - public string Facebook { get; private set; } - /// - /// Gets the user's badges - /// - public string Badges { get; private set; } - /// - /// Gets the user's mayorships - /// - public string Mayorships { get; private set; } - /// - /// Gets the user's checkins - /// - public string Checkins { get; private set; } - /// - /// Gets the user's photos - /// - public string Photos { get; private set; } - /// - /// Gets the user's scores - /// - public string Scores { get; private set; } - /// - /// Gets the user's link - /// - public string Link { get; private set; } - /// - /// Gets the representing the user - /// - public ClaimsIdentity Identity { get; set; } - /// - /// Gets or sets a property bag for common authentication properties - /// - public AuthenticationProperties Properties { get; set; } + /// + /// Gets the JSON-serialized user + /// + /// + /// Contains the Foursquare user obtained from the User Info endpoint. By default this is https://api.foursquare.com/v2/users/self but it can be + /// overridden in the options + /// + public JObject User { get; private set; } + /// + /// Gets the Foursquare access token + /// + public string AccessToken { get; private set; } + /// + /// Gets the Foursquare user ID + /// + public string Id { get; private set; } + /// + /// Gets the user's first name + /// + public string FirstName { get; private set; } + /// + /// Gets the user's last name + /// + public string LastName { get; private set; } + /// + /// Gets the user's full name + /// + public string Name { get; private set; } + /// + /// Gets the user's gender + /// + public string Gender { get; private set; } + /// + /// Gets the user's photo + /// + public string Photo { get; private set; } + /// + /// Gets the user's friends + /// + public string Friends { get; private set; } + /// + /// Gets the user's home city + /// + public string HomeCity { get; private set; } + /// + /// Gets the user's biography + /// + public string Bio { get; private set; } + /// + /// Gets the user's contact + /// + public string Contact { get; private set; } + /// + /// Gets the user's phone + /// + public string Phone { get; private set; } + /// + /// Gets the user's email + /// + public string Email { get; private set; } + /// + /// Gets the user's Twitter handle + /// + public string Twitter { get; private set; } + /// + /// Gets the user's Facebook id + /// + public string Facebook { get; private set; } + /// + /// Gets the user's badges + /// + public string Badges { get; private set; } + /// + /// Gets the user's mayorships + /// + public string Mayorships { get; private set; } + /// + /// Gets the user's checkins + /// + public string Checkins { get; private set; } + /// + /// Gets the user's photos + /// + public string Photos { get; private set; } + /// + /// Gets the user's scores + /// + public string Scores { get; private set; } + /// + /// Gets the user's link + /// + public string Link { get; private set; } + /// + /// Gets the representing the user + /// + public ClaimsIdentity Identity { get; set; } + /// + /// Gets or sets a property bag for common authentication properties + /// + public AuthenticationProperties Properties { get; set; } - private static string TryGetValue(JObject user, string propertyName) - { - JToken value; - return user.TryGetValue(propertyName, out value) ? value.ToString() : null; - } - } + private static string TryGetValue(JObject user, string propertyName) + { + JToken value; + return user.TryGetValue(propertyName, out value) ? value.ToString() : null; + } + } } \ No newline at end of file diff --git a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticationProvider.cs b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticationProvider.cs index 8890a96..841cf2e 100644 --- a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticationProvider.cs +++ b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticationProvider.cs @@ -3,48 +3,48 @@ using System.Threading.Tasks; namespace Owin.Security.Providers.Foursquare.Provider { - /// - /// Default implementation. - /// - public class FoursquareAuthenticationProvider : IFoursquareAuthenticationProvider - { - /// - /// Initializes a - /// - public FoursquareAuthenticationProvider() - { - this.OnAuthenticated = context => Task.FromResult(null); - this.OnReturnEndpoint = context => Task.FromResult(null); - } + /// + /// Default implementation. + /// + public class FoursquareAuthenticationProvider : IFoursquareAuthenticationProvider + { + /// + /// Initializes a + /// + public FoursquareAuthenticationProvider() + { + 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 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; } + /// + /// Gets or sets the function that is invoked when the ReturnEndpoint method is invoked. + /// + public Func OnReturnEndpoint { get; set; } - /// + /// /// Invoked whenever Foursquare succesfully authenticates a user - /// - /// Contains information about the login session as well as the user . - /// A representing the completed operation. - public virtual Task Authenticated(FoursquareAuthenticatedContext context) - { - return this.OnAuthenticated(context); - } + /// + /// Contains information about the login session as well as the user . + /// A representing the completed operation. + public virtual Task Authenticated(FoursquareAuthenticatedContext 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. - /// - /// - /// A representing the completed operation. - public virtual Task ReturnEndpoint(FoursquareReturnEndpointContext context) - { - return this.OnReturnEndpoint(context); - } - } + /// + /// Invoked prior to the being saved in a local cookie and the browser being redirected to the originally requested URL. + /// + /// + /// A representing the completed operation. + public virtual Task ReturnEndpoint(FoursquareReturnEndpointContext context) + { + return this.OnReturnEndpoint(context); + } + } } \ No newline at end of file diff --git a/Owin.Security.Providers/Foursquare/Provider/FoursquareReturnEndpointContext.cs b/Owin.Security.Providers/Foursquare/Provider/FoursquareReturnEndpointContext.cs index 27fd33f..6ec9a33 100644 --- a/Owin.Security.Providers/Foursquare/Provider/FoursquareReturnEndpointContext.cs +++ b/Owin.Security.Providers/Foursquare/Provider/FoursquareReturnEndpointContext.cs @@ -4,19 +4,19 @@ using Microsoft.Owin.Security.Provider; namespace Owin.Security.Providers.Foursquare.Provider { - /// - /// Provides context information to middleware providers. - /// - public class FoursquareReturnEndpointContext : ReturnEndpointContext - { - /// - /// - /// - /// OWIN environment - /// The authentication ticket - public FoursquareReturnEndpointContext(IOwinContext context, AuthenticationTicket ticket) - : base(context, ticket) - { - } - } + /// + /// Provides context information to middleware providers. + /// + public class FoursquareReturnEndpointContext : ReturnEndpointContext + { + /// + /// + /// + /// OWIN environment + /// The authentication ticket + public FoursquareReturnEndpointContext(IOwinContext context, AuthenticationTicket ticket) + : base(context, ticket) + { + } + } } \ No newline at end of file diff --git a/Owin.Security.Providers/Foursquare/Provider/IFoursquareAuthenticationProvider.cs b/Owin.Security.Providers/Foursquare/Provider/IFoursquareAuthenticationProvider.cs index c6f79f3..c46a554 100644 --- a/Owin.Security.Providers/Foursquare/Provider/IFoursquareAuthenticationProvider.cs +++ b/Owin.Security.Providers/Foursquare/Provider/IFoursquareAuthenticationProvider.cs @@ -2,23 +2,23 @@ namespace Owin.Security.Providers.Foursquare.Provider { - /// - /// Specifies callback methods which the invokes to enable developer control over the authentication process. /> - /// - public interface IFoursquareAuthenticationProvider - { - /// + /// + /// Specifies callback methods which the invokes to enable developer control over the authentication process. /> + /// + public interface IFoursquareAuthenticationProvider + { + /// /// Invoked whenever Foursquare succesfully authenticates a user - /// - /// Contains information about the login session as well as the user . - /// A representing the completed operation. - Task Authenticated(FoursquareAuthenticatedContext context); + /// + /// Contains information about the login session as well as the user . + /// A representing the completed operation. + Task Authenticated(FoursquareAuthenticatedContext context); - /// - /// Invoked prior to the being saved in a local cookie and the browser being redirected to the originally requested URL. - /// - /// - /// A representing the completed operation. - Task ReturnEndpoint(FoursquareReturnEndpointContext context); - } + /// + /// Invoked prior to the being saved in a local cookie and the browser being redirected to the originally requested URL. + /// + /// + /// A representing the completed operation. + Task ReturnEndpoint(FoursquareReturnEndpointContext context); + } } \ No newline at end of file From f6177258991eaf807e8cd6eb196537e135ed3ff0 Mon Sep 17 00:00:00 2001 From: ByteBlast Date: Wed, 25 Mar 2015 13:58:09 +0000 Subject: [PATCH 07/22] Tweaked context data types. Instead of storing Json as a string, use a JObject. This will make it easier to attain data for the user. --- .../FoursquareAuthenticatedContext.cs | 16 ++++++++-------- ...-OwinOAuthProvidersDemo-20131113093838.mdf | Bin 3211264 -> 3211264 bytes ...nOAuthProvidersDemo-20131113093838_log.ldf | Bin 1048576 -> 1048576 bytes 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs index 7454588..6596fba 100644 --- a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs +++ b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs @@ -41,15 +41,15 @@ namespace Owin.Security.Providers.Foursquare.Provider this.LastName = TryGetValue(user, "lastName"); this.Name = this.FirstName + " " + this.LastName; this.Gender = TryGetValue(user, "gender"); - this.Photo = TryGetValue(user, "photo"); + this.Photo = (JObject)user["photo"]; this.Friends = TryGetValue(user, "friends"); this.HomeCity = TryGetValue(user, "homeCity"); this.Bio = TryGetValue(user, "bio"); - this.Contact = TryGetValue(user, "contact"); - this.Phone = TryGetValue(JObject.Parse(this.Contact), "phone"); - this.Email = TryGetValue(JObject.Parse(this.Contact), "email"); - this.Twitter = TryGetValue(JObject.Parse(this.Contact), "twitter"); - this.Facebook = TryGetValue(JObject.Parse(this.Contact), "facebook"); + this.Contact = (JObject)user["contact"]; + this.Phone = TryGetValue(Contact, "phone"); + this.Email = TryGetValue(Contact, "email"); + this.Twitter = TryGetValue(Contact, "twitter"); + this.Facebook = TryGetValue(Contact, "facebook"); this.Badges = TryGetValue(user, "badges"); this.Mayorships = TryGetValue(user, "mayorships"); this.Checkins = TryGetValue(user, "checkins"); @@ -93,7 +93,7 @@ namespace Owin.Security.Providers.Foursquare.Provider /// /// Gets the user's photo /// - public string Photo { get; private set; } + public JObject Photo { get; private set; } /// /// Gets the user's friends /// @@ -109,7 +109,7 @@ namespace Owin.Security.Providers.Foursquare.Provider /// /// Gets the user's contact /// - public string Contact { get; private set; } + public JObject Contact { get; private set; } /// /// Gets the user's phone /// diff --git a/OwinOAuthProvidersDemo/App_Data/aspnet-OwinOAuthProvidersDemo-20131113093838.mdf b/OwinOAuthProvidersDemo/App_Data/aspnet-OwinOAuthProvidersDemo-20131113093838.mdf index 9c13e273623639ea9bcecfb4355cbdbc13599d5b..93d2e48cc2b4de74808e50270618c9e798058c12 100644 GIT binary patch delta 327 zcmZ9_zfQtX6vy#Cl0fFmYgYkfqPy z!gFYX-^PRx&pDsroZoPQ;8O;8Q##U#5t-UF=28e|U*+e*G|gv z>3X8&SXybU=)>x={N07v#9K?c>Lnlgo!GVIPw2O2o+F`CN zR8d16XE4x!iE}h@flIWI{_EfhU1(Ua;h={;2DpZc8{Fa!_ZVV?hqdQCeti7`%3@8= delta 329 zcmYMtJx&5q6o%n@t_moM;NXBFa%To~5Pz_shgH~Fum}3FvL?4+0d9b3K}!PFG&FWl z$Oc@2iM|sP_;Q})ik6x5H*f1z0zmO}A5naf^8iJ5O6{a)e5SsE<JBR&?`U_RxS8F=i{M1<-j z_ch;6v{5_njGEwi6G`CS@>uS9LD)VF*&d#ezy};3<6Vij6UVC(%Ix&q;W8?7s4`}& zybJlbN_@bz+EE#jS+IVY`NpvrX{5n6c6Q-lnY8(O(x|{L0#w0T`4a9uFQy@wsznj@ z=}4QO&u_y?l?9GQ2w@wot#pL2Lsnzoa~mnyBgTPeJwRHh>$v0=pAv@!=_%=~GXtj=lIINKSOD zIL@Dnf@GP2;v16e<(<*ok9>>-F59UyPkJqC>a{k_Jf72Bv}wNUqWKwSMSz4yPGv$} z&|Fq&E=IH~w$j@vzYFM6xDXnGxZMUfd7Ma~6CDERQs}B4YLR&Oj@3F$^Gyyfc$J#& z=S+87?Q~r7>u@W(0@w|G7%2H&{kJXrx6)4xu#W{=6#RO}pi9^nAr1Ro!V|Xerc~Vk zx6%RmpQ+d5zEW!2wAJSiY}vEIu(RXK7A8wwaeL)Ahhg?`wuf*iYRH|<%B|d0EjCd>hS@zJZt_7k#f=HCSrvU47#Ns<5E;k=IS_FMh82@@*ff~F zu}*Z9oxGXt&-6rPMj6JC>9NX;29pgOFTk+^yY^&(GM3HJViOn@9T^!I7Gp6KBF?~Y z7;GpL2eP4?PqQbmP@t3A9 Date: Wed, 25 Mar 2015 16:39:55 +0100 Subject: [PATCH 08/22] Flickr - Fixes incorrect variable uses --- Owin.Security.Providers/Flickr/FlickrAuthenticationHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Owin.Security.Providers/Flickr/FlickrAuthenticationHandler.cs b/Owin.Security.Providers/Flickr/FlickrAuthenticationHandler.cs index 93591b4..fa920c4 100644 --- a/Owin.Security.Providers/Flickr/FlickrAuthenticationHandler.cs +++ b/Owin.Security.Providers/Flickr/FlickrAuthenticationHandler.cs @@ -98,12 +98,12 @@ namespace Owin.Security.Providers.Flickr context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.UserId, XmlSchemaString, Options.AuthenticationType)); } - if (!String.IsNullOrEmpty(context.FullName)) + if(!String.IsNullOrEmpty(context.UserName)) { context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName, XmlSchemaString, Options.AuthenticationType)); } - if (!String.IsNullOrEmpty(context.UserName)) + if (!String.IsNullOrEmpty(context.FullName)) { context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.FullName, XmlSchemaString, Options.AuthenticationType)); From 57d8f8264d79af74f3438b0aa71e56aa16c36939 Mon Sep 17 00:00:00 2001 From: Romoku Date: Thu, 26 Mar 2015 00:34:19 -0400 Subject: [PATCH 09/22] - Added InstanceUrl to SalesforceAuthenticatedContext - Deserialize instance_url in SalesforceAuthenticationHandler Update SalesforceAuthenticatedContext.cs Update SalesforceAuthenticatedContext.cs --- .../Provider/SalesforceAuthenticatedContext.cs | 9 ++++++++- .../Salesforce/SalesforceAuthenticationHandler.cs | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Owin.Security.Providers/Salesforce/Provider/SalesforceAuthenticatedContext.cs b/Owin.Security.Providers/Salesforce/Provider/SalesforceAuthenticatedContext.cs index b4784c6..9473062 100644 --- a/Owin.Security.Providers/Salesforce/Provider/SalesforceAuthenticatedContext.cs +++ b/Owin.Security.Providers/Salesforce/Provider/SalesforceAuthenticatedContext.cs @@ -20,12 +20,14 @@ namespace Owin.Security.Providers.Salesforce /// The JSON-serialized user /// Salesforce Access token /// Salesforce Refresh token - public SalesforceAuthenticatedContext(IOwinContext context, JObject user, string accessToken, string refreshToken) + /// Salesforce instance url + public SalesforceAuthenticatedContext(IOwinContext context, JObject user, string accessToken, string refreshToken, string instanceUrl) : base(context) { User = user; AccessToken = accessToken; RefreshToken = refreshToken; + InstanceUrl = instanceUrl; Id = TryGetValue(user, "id"); UserId = TryGetValue(user, "user_id"); @@ -59,6 +61,11 @@ namespace Owin.Security.Providers.Salesforce /// public string RefreshToken { get; private set; } + /// + /// Gets the Salesforce instance url + /// + public string InstanceUrl { get; private set; } + /// /// Gets the Salesforce ID / User Info Endpoint /// diff --git a/Owin.Security.Providers/Salesforce/SalesforceAuthenticationHandler.cs b/Owin.Security.Providers/Salesforce/SalesforceAuthenticationHandler.cs index f0f726e..3296568 100644 --- a/Owin.Security.Providers/Salesforce/SalesforceAuthenticationHandler.cs +++ b/Owin.Security.Providers/Salesforce/SalesforceAuthenticationHandler.cs @@ -86,6 +86,7 @@ namespace Owin.Security.Providers.Salesforce dynamic response = JsonConvert.DeserializeObject(text); string accessToken = (string)response.access_token; string refreshToken = (string)response.refresh_token; + string instanceUrl = (string)response.instance_url; // Get the Salesforce user using the user info endpoint, which is part of the token - response.id HttpRequestMessage userRequest = new HttpRequestMessage(HttpMethod.Get, (string)response.id + "?access_token=" + Uri.EscapeDataString(accessToken)); @@ -95,7 +96,7 @@ namespace Owin.Security.Providers.Salesforce text = await userResponse.Content.ReadAsStringAsync(); JObject user = JObject.Parse(text); - var context = new SalesforceAuthenticatedContext(Context, user, accessToken, refreshToken); + var context = new SalesforceAuthenticatedContext(Context, user, accessToken, refreshToken, instanceUrl); context.Identity = new ClaimsIdentity( Options.AuthenticationType, ClaimsIdentity.DefaultNameClaimType, From 9a1cdd73f59033e7096a9e5a6d2a51ac5a255a7a Mon Sep 17 00:00:00 2001 From: ByteBlast Date: Thu, 26 Mar 2015 10:26:15 +0000 Subject: [PATCH 10/22] Removed inaccurate comment --- .../Foursquare/Provider/FoursquareAuthenticatedContext.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs index 6596fba..04b9a28 100644 --- a/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs +++ b/Owin.Security.Providers/Foursquare/Provider/FoursquareAuthenticatedContext.cs @@ -62,8 +62,7 @@ namespace Owin.Security.Providers.Foursquare.Provider /// Gets the JSON-serialized user /// /// - /// Contains the Foursquare user obtained from the User Info endpoint. By default this is https://api.foursquare.com/v2/users/self but it can be - /// overridden in the options + /// Contains the Foursquare user obtained from the User Info endpoint https://api.foursquare.com/v2/users/self /// public JObject User { get; private set; } /// From 1bd907c9be0ab8edf1ff30f4f3f8e5b8926a3074 Mon Sep 17 00:00:00 2001 From: ByteBlast Date: Thu, 26 Mar 2015 11:47:31 +0000 Subject: [PATCH 11/22] Release version 1.16 --- NuGet/Owin.Security.Providers.nuspec | 7 +++---- Owin.Security.Providers/Properties/AssemblyInfo.cs | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/NuGet/Owin.Security.Providers.nuspec b/NuGet/Owin.Security.Providers.nuspec index b19a32f..54e862f 100644 --- a/NuGet/Owin.Security.Providers.nuspec +++ b/NuGet/Owin.Security.Providers.nuspec @@ -2,7 +2,7 @@ Owin.Security.Providers - 1.15.0 + 1.16.0 Jerrie Pelser and contributors Jerrie Pelser http://opensource.org/licenses/MIT @@ -16,11 +16,10 @@ Also adds generic OpenID 2.0 providers as well as a Steam-specific implementatio - Version 1.15 + Version 1.16 Added - - Added Eve Online Provider (Thank you Mariusz Zieliński - https://github.com/mariozski) - - Added SoundCloud Provider + - Added Foursquare Provider (Thank you Ricardo Peres - https://github.com/rjperes) Copyright 2013, 2014 owin katana oauth LinkedIn Yahoo Google+ GitHub Reddit Instagram StackExchange SalesForce TripIt Buffer ArcGIS Dropbox Wordpress Battle.NET Yammer OpenID Steam Twitch diff --git a/Owin.Security.Providers/Properties/AssemblyInfo.cs b/Owin.Security.Providers/Properties/AssemblyInfo.cs index 05cfba7..e3fb8b0 100644 --- a/Owin.Security.Providers/Properties/AssemblyInfo.cs +++ b/Owin.Security.Providers/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.15.0.0")] -[assembly: AssemblyFileVersion("1.15.0.0")] +[assembly: AssemblyVersion("1.16.0.0")] +[assembly: AssemblyFileVersion("1.16.0.0")] From 56c641132f4fbbf827eaba764212b4c5cd841e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Roussin-B=C3=A9langer?= Date: Sat, 28 Mar 2015 15:59:49 -0400 Subject: [PATCH 12/22] Added wargaming openid login --- Owin.Security.Providers/Wargaming/Constant.cs | 12 ++++++ ...argamingAccountAuthenticationExtensions.cs | 40 +++++++++++++++++++ .../WargamingAuthenticationHandler.cs | 39 ++++++++++++++++++ .../WargamingAuthenticationMiddleware.cs | 32 +++++++++++++++ .../WargamingAuthenticationOptions.cs | 28 +++++++++++++ 5 files changed, 151 insertions(+) create mode 100644 Owin.Security.Providers/Wargaming/Constant.cs create mode 100644 Owin.Security.Providers/Wargaming/WargamingAccountAuthenticationExtensions.cs create mode 100644 Owin.Security.Providers/Wargaming/WargamingAuthenticationHandler.cs create mode 100644 Owin.Security.Providers/Wargaming/WargamingAuthenticationMiddleware.cs create mode 100644 Owin.Security.Providers/Wargaming/WargamingAuthenticationOptions.cs diff --git a/Owin.Security.Providers/Wargaming/Constant.cs b/Owin.Security.Providers/Wargaming/Constant.cs new file mode 100644 index 0000000..9abca13 --- /dev/null +++ b/Owin.Security.Providers/Wargaming/Constant.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Owin.Security.Providers.Wargaming +{ + internal static class Constants + { + internal const string DefaultAuthenticationType = "Wargaming"; + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/Wargaming/WargamingAccountAuthenticationExtensions.cs b/Owin.Security.Providers/Wargaming/WargamingAccountAuthenticationExtensions.cs new file mode 100644 index 0000000..764096f --- /dev/null +++ b/Owin.Security.Providers/Wargaming/WargamingAccountAuthenticationExtensions.cs @@ -0,0 +1,40 @@ +using Microsoft.Owin; +using System; + +namespace Owin.Security.Providers.Wargaming +{ + public static class WargamingAccountAuthenticationExtensions + { + public static IAppBuilder UseWargamingAccountAuthentication(this IAppBuilder app, WargamingAuthenticationOptions options) + { + if (app == null) + { + throw new ArgumentNullException("app"); + } + if (options == null) + { + throw new ArgumentNullException("options"); + } + + return app.Use(typeof(WargamingAuthenticationMiddleware), app, options); + } + + /// + /// Authenticate users using Steam + /// + /// The passed to the configuration method + /// The wargaming application key + /// The updated + public static IAppBuilder UseWargamingAccountAuthentication(this IAppBuilder app, string appId) + { + return UseWargamingAccountAuthentication(app, new WargamingAuthenticationOptions + { + ProviderDiscoveryUri = "https://na.wargaming.net/id/openid/", + Caption = "Wargaming", + AuthenticationType = "Wargaming", + CallbackPath = new PathString("/signin-wargaming"), + AppId = appId + }); + } + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/Wargaming/WargamingAuthenticationHandler.cs b/Owin.Security.Providers/Wargaming/WargamingAuthenticationHandler.cs new file mode 100644 index 0000000..8638584 --- /dev/null +++ b/Owin.Security.Providers/Wargaming/WargamingAuthenticationHandler.cs @@ -0,0 +1,39 @@ +using Microsoft.Owin.Logging; +using Newtonsoft.Json; +using Owin.Security.Providers.OpenID; +using System.Collections.Generic; +using System.Net.Http; +using System.Security.Claims; +using System.Text.RegularExpressions; +using Newtonsoft.Json.Converters; +using System.Data; + +namespace Owin.Security.Providers.Wargaming +{ + internal sealed class WargamingAuthenticationHandler : OpenIDAuthenticationHandlerBase + { + + private readonly Regex AccountIDRegex = new Regex(@"^https://na.wargaming.net/id/([0-9]{10}).*$", RegexOptions.Compiled); + + private const string UserInfoUri = "https://api.worldoftanks.com/wot/account/info/?application_id={0}&account_id={1}&fields=nickname"; + + public WargamingAuthenticationHandler(HttpClient httpClient, ILogger logger) + : base(httpClient, logger) + { + } + + protected override void SetIdentityInformations(ClaimsIdentity identity, string claimedID, IDictionary attributeExchangeProperties) + { + Match accountIDMatch = AccountIDRegex.Match(claimedID); + if (accountIDMatch.Success) + { + string accountID = accountIDMatch.Groups[1].Value; + var getUserInfoTask = _httpClient.GetStringAsync(string.Format(UserInfoUri, Options.AppId, accountID)); + getUserInfoTask.Wait(); + string userInfoRaw = getUserInfoTask.Result; + dynamic userInfo = JsonConvert.DeserializeObject(userInfoRaw); + identity.AddClaim(new Claim(ClaimTypes.Name, (string)userInfo["data"][accountID].nickname, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationType)); + } + } + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/Wargaming/WargamingAuthenticationMiddleware.cs b/Owin.Security.Providers/Wargaming/WargamingAuthenticationMiddleware.cs new file mode 100644 index 0000000..7625ab3 --- /dev/null +++ b/Owin.Security.Providers/Wargaming/WargamingAuthenticationMiddleware.cs @@ -0,0 +1,32 @@ +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.OpenID; + +namespace Owin.Security.Providers.Wargaming +{ + public class WargamingAuthenticationMiddleware : OpenIDAuthenticationMiddlewareBase + { + + /// + /// Initializes a + /// + /// The next middleware in the OWIN pipeline to invoke + /// The OWIN application + /// Configuration options for the middleware + public WargamingAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, WargamingAuthenticationOptions options) + : base(next, app, options) + { } + + protected override AuthenticationHandler CreateSpecificHandler() + { + return new WargamingAuthenticationHandler(_httpClient, _logger); + } + } +} diff --git a/Owin.Security.Providers/Wargaming/WargamingAuthenticationOptions.cs b/Owin.Security.Providers/Wargaming/WargamingAuthenticationOptions.cs new file mode 100644 index 0000000..804cddd --- /dev/null +++ b/Owin.Security.Providers/Wargaming/WargamingAuthenticationOptions.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using Microsoft.Owin; +using Microsoft.Owin.Security; +using Owin.Security.Providers.OpenID; + +namespace Owin.Security.Providers.Wargaming +{ + public class WargamingAuthenticationOptions : OpenIDAuthenticationOptions + { + + public enum Region + { + Europe, + US, + Russia + } + + /// + /// Gets or sets the Wargaming-assigned appId + /// + public string AppId { get; set; } + } + + +} From 4bda111678be6bdd5c3c21f8b66fdb06823846bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Roussin-B=C3=A9langer?= Date: Sat, 28 Mar 2015 16:00:19 -0400 Subject: [PATCH 13/22] Added modified csprof for wargaming --- Owin.Security.Providers/Owin.Security.Providers.csproj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Owin.Security.Providers/Owin.Security.Providers.csproj b/Owin.Security.Providers/Owin.Security.Providers.csproj index a638670..828d37d 100644 --- a/Owin.Security.Providers/Owin.Security.Providers.csproj +++ b/Owin.Security.Providers/Owin.Security.Providers.csproj @@ -251,6 +251,11 @@ + + + + + From fdd5ab6b1be0e63540ad9428b273fc1ae4a54a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Roussin-B=C3=A9langer?= Date: Sat, 28 Mar 2015 16:02:11 -0400 Subject: [PATCH 14/22] Added comments --- .../WargamingAccountAuthenticationExtensions.cs | 9 +++++++++ .../Wargaming/WargamingAuthenticationHandler.cs | 3 --- .../Wargaming/WargamingAuthenticationMiddleware.cs | 3 +++ .../Wargaming/WargamingAuthenticationOptions.cs | 4 +++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Owin.Security.Providers/Wargaming/WargamingAccountAuthenticationExtensions.cs b/Owin.Security.Providers/Wargaming/WargamingAccountAuthenticationExtensions.cs index 764096f..ea0fd36 100644 --- a/Owin.Security.Providers/Wargaming/WargamingAccountAuthenticationExtensions.cs +++ b/Owin.Security.Providers/Wargaming/WargamingAccountAuthenticationExtensions.cs @@ -3,8 +3,17 @@ using System; namespace Owin.Security.Providers.Wargaming { + /// + /// Extension methods for using + /// public static class WargamingAccountAuthenticationExtensions { + /// + /// Authenticate users using Wargaming + /// + /// The passed to the configuration method + /// Middleware configuration options + /// The updated public static IAppBuilder UseWargamingAccountAuthentication(this IAppBuilder app, WargamingAuthenticationOptions options) { if (app == null) diff --git a/Owin.Security.Providers/Wargaming/WargamingAuthenticationHandler.cs b/Owin.Security.Providers/Wargaming/WargamingAuthenticationHandler.cs index 8638584..8bb5477 100644 --- a/Owin.Security.Providers/Wargaming/WargamingAuthenticationHandler.cs +++ b/Owin.Security.Providers/Wargaming/WargamingAuthenticationHandler.cs @@ -5,14 +5,11 @@ using System.Collections.Generic; using System.Net.Http; using System.Security.Claims; using System.Text.RegularExpressions; -using Newtonsoft.Json.Converters; -using System.Data; namespace Owin.Security.Providers.Wargaming { internal sealed class WargamingAuthenticationHandler : OpenIDAuthenticationHandlerBase { - private readonly Regex AccountIDRegex = new Regex(@"^https://na.wargaming.net/id/([0-9]{10}).*$", RegexOptions.Compiled); private const string UserInfoUri = "https://api.worldoftanks.com/wot/account/info/?application_id={0}&account_id={1}&fields=nickname"; diff --git a/Owin.Security.Providers/Wargaming/WargamingAuthenticationMiddleware.cs b/Owin.Security.Providers/Wargaming/WargamingAuthenticationMiddleware.cs index 7625ab3..7fa890b 100644 --- a/Owin.Security.Providers/Wargaming/WargamingAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/Wargaming/WargamingAuthenticationMiddleware.cs @@ -11,6 +11,9 @@ using Owin.Security.Providers.OpenID; namespace Owin.Security.Providers.Wargaming { + /// + /// OWIN middleware for authenticating users using an OpenID provider + /// public class WargamingAuthenticationMiddleware : OpenIDAuthenticationMiddlewareBase { diff --git a/Owin.Security.Providers/Wargaming/WargamingAuthenticationOptions.cs b/Owin.Security.Providers/Wargaming/WargamingAuthenticationOptions.cs index 804cddd..040cf0a 100644 --- a/Owin.Security.Providers/Wargaming/WargamingAuthenticationOptions.cs +++ b/Owin.Security.Providers/Wargaming/WargamingAuthenticationOptions.cs @@ -10,7 +10,9 @@ namespace Owin.Security.Providers.Wargaming { public class WargamingAuthenticationOptions : OpenIDAuthenticationOptions { - + /// + /// Region to use for to log in + /// public enum Region { Europe, From ae97f04d9328b57702dfb53df263b7bbf2f06bb3 Mon Sep 17 00:00:00 2001 From: mariozski Date: Sun, 29 Mar 2015 16:49:39 +0200 Subject: [PATCH 15/22] fixed Battle.net handler constructor --- .../BattleNetAuthenticationHandler.cs | 82 ++++++++++--------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/Owin.Security.Providers/BattleNet/BattleNetAuthenticationHandler.cs b/Owin.Security.Providers/BattleNet/BattleNetAuthenticationHandler.cs index c2993df..77c0e10 100644 --- a/Owin.Security.Providers/BattleNet/BattleNetAuthenticationHandler.cs +++ b/Owin.Security.Providers/BattleNet/BattleNetAuthenticationHandler.cs @@ -16,10 +16,10 @@ namespace Owin.Security.Providers.BattleNet { private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; - private readonly string _tokenEndpoint = "https://eu.battle.net/oauth/token"; - private readonly string _accountUserIdEndpoint = "https://eu.api.battle.net/account/user/id"; - private readonly string _accountUserBattleTagEndpoint = "https://eu.api.battle.net/account/user/battletag"; - private readonly string _oauthAuthEndpoint = "https://eu.battle.net/oauth/authorize"; + private string _tokenEndpoint = "https://eu.battle.net/oauth/token"; + private string _accountUserIdEndpoint = "https://eu.api.battle.net/account/user/id"; + private string _accountUserBattleTagEndpoint = "https://eu.api.battle.net/account/user/battletag"; + private string _oauthAuthEndpoint = "https://eu.battle.net/oauth/authorize"; private readonly ILogger _logger; private readonly HttpClient _httpClient; @@ -28,42 +28,48 @@ namespace Owin.Security.Providers.BattleNet { _httpClient = httpClient; _logger = logger; - - switch (Options.Region) - { - case Region.China: - _tokenEndpoint = "https://cn.battle.net/oauth/token"; - _accountUserIdEndpoint = "https://cn.api.battle.net/account/user/id"; - _accountUserBattleTagEndpoint = "https://cn.api.battle.net/account/user/battletag"; - _oauthAuthEndpoint = "https://cn.battle.net/oauth/authorize"; - break; - case Region.Korea: - _tokenEndpoint = "https://kr.battle.net/oauth/token"; - _accountUserIdEndpoint = "https://kr.api.battle.net/account/user/id"; - _accountUserBattleTagEndpoint = "https://kr.api.battle.net/account/user/battletag"; - _oauthAuthEndpoint = "https://kr.battle.net/oauth/authorize"; - break; - case Region.Taiwan: - _tokenEndpoint = "https://tw.battle.net/oauth/token"; - _accountUserIdEndpoint = "https://tw.api.battle.net/account/user/id"; - _accountUserBattleTagEndpoint = "https://tw.api.battle.net/account/user/battletag"; - _oauthAuthEndpoint = "https://tw.battle.net/oauth/authorize"; - break; - case Region.Europe: - _tokenEndpoint = "https://eu.battle.net/oauth/token"; - _accountUserIdEndpoint = "https://eu.api.battle.net/account/user/id"; - _accountUserBattleTagEndpoint = "https://eu.api.battle.net/account/user/battletag"; - _oauthAuthEndpoint = "https://eu.battle.net/oauth/authorize"; - break; - default: - _tokenEndpoint = "https://us.battle.net/oauth/token"; - _accountUserIdEndpoint = "https://us.api.battle.net/account/user/id"; - _accountUserBattleTagEndpoint = "https://us.api.battle.net/account/user/battletag"; - _oauthAuthEndpoint = "https://us.battle.net/oauth/authorize"; - break; - } } + protected override Task InitializeCoreAsync() + { + return Task.Run(() => + { + switch (Options.Region) + { + case Region.China: + _tokenEndpoint = "https://cn.battle.net/oauth/token"; + _accountUserIdEndpoint = "https://cn.api.battle.net/account/user/id"; + _accountUserBattleTagEndpoint = "https://cn.api.battle.net/account/user/battletag"; + _oauthAuthEndpoint = "https://cn.battle.net/oauth/authorize"; + break; + case Region.Korea: + _tokenEndpoint = "https://kr.battle.net/oauth/token"; + _accountUserIdEndpoint = "https://kr.api.battle.net/account/user/id"; + _accountUserBattleTagEndpoint = "https://kr.api.battle.net/account/user/battletag"; + _oauthAuthEndpoint = "https://kr.battle.net/oauth/authorize"; + break; + case Region.Taiwan: + _tokenEndpoint = "https://tw.battle.net/oauth/token"; + _accountUserIdEndpoint = "https://tw.api.battle.net/account/user/id"; + _accountUserBattleTagEndpoint = "https://tw.api.battle.net/account/user/battletag"; + _oauthAuthEndpoint = "https://tw.battle.net/oauth/authorize"; + break; + case Region.Europe: + _tokenEndpoint = "https://eu.battle.net/oauth/token"; + _accountUserIdEndpoint = "https://eu.api.battle.net/account/user/id"; + _accountUserBattleTagEndpoint = "https://eu.api.battle.net/account/user/battletag"; + _oauthAuthEndpoint = "https://eu.battle.net/oauth/authorize"; + break; + default: + _tokenEndpoint = "https://us.battle.net/oauth/token"; + _accountUserIdEndpoint = "https://us.api.battle.net/account/user/id"; + _accountUserBattleTagEndpoint = "https://us.api.battle.net/account/user/battletag"; + _oauthAuthEndpoint = "https://us.battle.net/oauth/authorize"; + break; + } + }); + } + protected override async Task AuthenticateCoreAsync() { AuthenticationProperties properties = null; From ce63ba6f4d7836b9e99abd75196418b76b62551e Mon Sep 17 00:00:00 2001 From: qanuj Date: Sat, 4 Apr 2015 16:36:41 +0530 Subject: [PATCH 16/22] UsePayPalAuthentication Added --- .../Owin.Security.Providers.csproj | 9 + Owin.Security.Providers/PayPal/Constants.cs | 7 + .../PayPal/PayPalAuthenticationExtensions.cs | 29 +++ .../PayPal/PayPalAuthenticationHandler.cs | 238 ++++++++++++++++++ .../PayPal/PayPalAuthenticationMiddleware.cs | 87 +++++++ .../PayPal/PayPalAuthenticationOptions.cs | 154 ++++++++++++ .../Provider/IPayPalAuthenticationProvider.cs | 24 ++ .../Provider/PayPalAuthenticatedContext.cs | 84 +++++++ .../Provider/PayPalAuthenticationProvider.cs | 50 ++++ .../Provider/PayPalReturnEndpointContext.cs | 26 ++ .../App_Start/Startup.Auth.cs | 7 + 11 files changed, 715 insertions(+) create mode 100644 Owin.Security.Providers/PayPal/Constants.cs create mode 100644 Owin.Security.Providers/PayPal/PayPalAuthenticationExtensions.cs create mode 100644 Owin.Security.Providers/PayPal/PayPalAuthenticationHandler.cs create mode 100644 Owin.Security.Providers/PayPal/PayPalAuthenticationMiddleware.cs create mode 100644 Owin.Security.Providers/PayPal/PayPalAuthenticationOptions.cs create mode 100644 Owin.Security.Providers/PayPal/Provider/IPayPalAuthenticationProvider.cs create mode 100644 Owin.Security.Providers/PayPal/Provider/PayPalAuthenticatedContext.cs create mode 100644 Owin.Security.Providers/PayPal/Provider/PayPalAuthenticationProvider.cs create mode 100644 Owin.Security.Providers/PayPal/Provider/PayPalReturnEndpointContext.cs diff --git a/Owin.Security.Providers/Owin.Security.Providers.csproj b/Owin.Security.Providers/Owin.Security.Providers.csproj index a638670..a93b0fb 100644 --- a/Owin.Security.Providers/Owin.Security.Providers.csproj +++ b/Owin.Security.Providers/Owin.Security.Providers.csproj @@ -182,6 +182,15 @@ + + + + + + + + + True diff --git a/Owin.Security.Providers/PayPal/Constants.cs b/Owin.Security.Providers/PayPal/Constants.cs new file mode 100644 index 0000000..6361dfc --- /dev/null +++ b/Owin.Security.Providers/PayPal/Constants.cs @@ -0,0 +1,7 @@ +namespace Owin.Security.Providers.PayPal +{ + internal static class Constants + { + public const string DefaultAuthenticationType = "PayPal"; + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/PayPal/PayPalAuthenticationExtensions.cs b/Owin.Security.Providers/PayPal/PayPalAuthenticationExtensions.cs new file mode 100644 index 0000000..caeedbd --- /dev/null +++ b/Owin.Security.Providers/PayPal/PayPalAuthenticationExtensions.cs @@ -0,0 +1,29 @@ +using System; + +namespace Owin.Security.Providers.PayPal +{ + public static class PayPalAuthenticationExtensions + { + public static IAppBuilder UsePayPalAuthentication(this IAppBuilder app, + PayPalAuthenticationOptions options) + { + if (app == null) + throw new ArgumentNullException("app"); + if (options == null) + throw new ArgumentNullException("options"); + + app.Use(typeof(PayPalAuthenticationMiddleware), app, options); + + return app; + } + + public static IAppBuilder UsePayPalAuthentication(this IAppBuilder app, string clientId, string clientSecret, bool isSandbox=false) + { + return app.UsePayPalAuthentication(new PayPalAuthenticationOptions(isSandbox) + { + ClientId = clientId, + ClientSecret = clientSecret + }); + } + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/PayPal/PayPalAuthenticationHandler.cs b/Owin.Security.Providers/PayPal/PayPalAuthenticationHandler.cs new file mode 100644 index 0000000..fcc4985 --- /dev/null +++ b/Owin.Security.Providers/PayPal/PayPalAuthenticationHandler.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.Owin; +using Microsoft.Owin.Infrastructure; +using Microsoft.Owin.Logging; +using Microsoft.Owin.Security; +using Microsoft.Owin.Security.Infrastructure; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Text; + +namespace Owin.Security.Providers.PayPal +{ + public class PayPalAuthenticationHandler : AuthenticationHandler + { + private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; + + private readonly ILogger _logger; + private readonly HttpClient _httpClient; + + public PayPalAuthenticationHandler(HttpClient httpClient, ILogger logger) + { + this._httpClient = httpClient; + this._logger = logger; + } + + protected override async Task AuthenticateCoreAsync() + { + AuthenticationProperties properties = null; + string error = "Unknown"; + try + { + string code = null; + string state = null; + + IReadableStringCollection query = Request.Query; + IList values = query.GetValues("code"); + + if(values != null && values.Count == 1) + { + code = values[0]; + } + + values = query.GetValues("error"); + if(values != null && values.Count == 1) + { + error = values[0]; + } + + values = query.GetValues("state"); + if(values != null && values.Count == 1) + { + state = values[0]; + } + + properties = Options.StateDataFormat.Unprotect(state); + if(properties == null) + { + return null; + } + + // OAuth2 10.12 CSRF + if(!ValidateCorrelationId(properties, _logger)) + { + return new AuthenticationTicket(null, properties); + } + + string requestPrefix = Request.Scheme + "://" + Request.Host; + string redirectUri = requestPrefix + Request.PathBase + Options.CallbackPath; + + // Request the token + var requestMessage = new HttpRequestMessage(HttpMethod.Post, Options.Endpoints.TokenEndpoint); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", Options.ClientId, Options.ClientSecret)))); + requestMessage.Content = new FormUrlEncodedContent(new List>{ + new KeyValuePair("grant_type", "authorization_code"), + new KeyValuePair("code", code), + new KeyValuePair("redirect_uri", redirectUri), + }); + var tokenResponse = await _httpClient.SendAsync(requestMessage); + tokenResponse.EnsureSuccessStatusCode(); + var text = await tokenResponse.Content.ReadAsStringAsync(); + + // Deserializes the token response + var response = JsonConvert.DeserializeObject(text); + var accessToken = (string)response.access_token; + var refreshToken = (string)response.refresh_token; + + // Get the PayPal user + var userRequest = new HttpRequestMessage(HttpMethod.Get, Options.Endpoints.UserInfoEndpoint); + userRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + userRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); + var userResponse = await _httpClient.SendAsync(userRequest, Request.CallCancelled); + userResponse.EnsureSuccessStatusCode(); + text = await userResponse.Content.ReadAsStringAsync(); + var user = JObject.Parse(text); + + var context = new PayPalAuthenticatedContext(Context, user, accessToken, refreshToken) + { + Identity = new ClaimsIdentity(Options.AuthenticationType, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType) + }; + if(!string.IsNullOrEmpty(context.Id)) + { + context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.Id, XmlSchemaString, Options.AuthenticationType)); + } + if(!string.IsNullOrEmpty(context.Email)) + { + context.Identity.AddClaim(new Claim(ClaimTypes.Email, context.Email, XmlSchemaString, Options.AuthenticationType)); + } + if(!string.IsNullOrEmpty(context.Name)) + { + context.Identity.AddClaim(new Claim("urn:paypal:name", context.Name, XmlSchemaString, Options.AuthenticationType)); + } + context.Properties = properties; + + await Options.Provider.Authenticated(context); + + return new AuthenticationTicket(context.Identity, context.Properties); + } + catch(Exception ex) + { + _logger.WriteError(ex.Message + " : " + error); + } + return new AuthenticationTicket(null, properties); + } + + protected override Task ApplyResponseChallengeAsync() + { + if(Response.StatusCode != 401) + { + return Task.FromResult(null); + } + + AuthenticationResponseChallenge challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode); + + if(challenge != null) + { + string baseUri = + Request.Scheme + + Uri.SchemeDelimiter + + Request.Host + + Request.PathBase; + + string currentUri = + baseUri + + Request.Path + + Request.QueryString; + + string redirectUri = + baseUri + + Options.CallbackPath; + + AuthenticationProperties properties = challenge.Properties; + if(string.IsNullOrEmpty(properties.RedirectUri)) + { + properties.RedirectUri = currentUri; + } + + // OAuth2 10.12 CSRF + GenerateCorrelationId(properties); + + // comma separated + string scope = string.Join(" ", Options.Scope); + + string state = Options.StateDataFormat.Protect(properties); + + string authorizationEndpoint = + Options.Endpoints.AuthorizationEndpoint + + "?client_id=" + Uri.EscapeDataString(Options.ClientId) + + "&redirect_uri=" + Uri.EscapeDataString(redirectUri) + + "&scope=" + Uri.EscapeDataString(scope) + + "&response_type=code" + + "&state=" + Uri.EscapeDataString(state); + + Response.Redirect(authorizationEndpoint); + } + + return Task.FromResult(null); + } + + public override async Task InvokeAsync() + { + return await InvokeReplyPathAsync(); + } + + private async Task InvokeReplyPathAsync() + { + if(Options.CallbackPath.HasValue && Options.CallbackPath == Request.Path) + { + AuthenticationTicket ticket = await AuthenticateAsync(); + if(ticket == null) + { + _logger.WriteWarning("Invalid return state, unable to redirect."); + Response.StatusCode = 500; + return true; + } + + var context = new PayPalReturnEndpointContext(Context, ticket) + { + SignInAsAuthenticationType = Options.SignInAsAuthenticationType, + RedirectUri = ticket.Properties.RedirectUri + }; + + await Options.Provider.ReturnEndpoint(context); + + if(context.SignInAsAuthenticationType != null && + context.Identity != null) + { + ClaimsIdentity grantIdentity = context.Identity; + if(!string.Equals(grantIdentity.AuthenticationType, context.SignInAsAuthenticationType, StringComparison.Ordinal)) + { + grantIdentity = new ClaimsIdentity(grantIdentity.Claims, context.SignInAsAuthenticationType, grantIdentity.NameClaimType, grantIdentity.RoleClaimType); + } + Context.Authentication.SignIn(context.Properties, grantIdentity); + } + + if(!context.IsRequestCompleted && context.RedirectUri != null) + { + string redirectUri = context.RedirectUri; + if(context.Identity == null) + { + // add a redirect hint that sign-in failed in some way + redirectUri = WebUtilities.AddQueryString(redirectUri, "error", "access_denied"); + } + Response.Redirect(redirectUri); + context.RequestCompleted(); + } + + return context.IsRequestCompleted; + } + return false; + } + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/PayPal/PayPalAuthenticationMiddleware.cs b/Owin.Security.Providers/PayPal/PayPalAuthenticationMiddleware.cs new file mode 100644 index 0000000..9200e40 --- /dev/null +++ b/Owin.Security.Providers/PayPal/PayPalAuthenticationMiddleware.cs @@ -0,0 +1,87 @@ +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.Properties; + +namespace Owin.Security.Providers.PayPal +{ + public class PayPalAuthenticationMiddleware : AuthenticationMiddleware + { + private readonly HttpClient httpClient; + private readonly ILogger logger; + + public PayPalAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, + PayPalAuthenticationOptions options) + : base(next, options) + { + if (String.IsNullOrWhiteSpace(Options.ClientId)) + throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, + Resources.Exception_OptionMustBeProvided, "ClientId")); + if (String.IsNullOrWhiteSpace(Options.ClientSecret)) + throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, + Resources.Exception_OptionMustBeProvided, "ClientSecret")); + + logger = app.CreateLogger(); + + if (Options.Provider == null) + Options.Provider = new PayPalAuthenticationProvider(); + + if (Options.StateDataFormat == null) + { + IDataProtector dataProtector = app.CreateDataProtector( + typeof (PayPalAuthenticationMiddleware).FullName, + Options.AuthenticationType, "v1"); + Options.StateDataFormat = new PropertiesDataFormat(dataProtector); + } + + if (String.IsNullOrEmpty(Options.SignInAsAuthenticationType)) + Options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(); + + httpClient = new HttpClient(ResolveHttpMessageHandler(Options)) + { + Timeout = Options.BackchannelTimeout, + MaxResponseContentBufferSize = 1024*1024*10, + }; + httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Microsoft Owin PayPal middleware"); + httpClient.DefaultRequestHeaders.ExpectContinue = false; + } + + /// + /// Provides the object for processing + /// authentication-related requests. + /// + /// + /// An configured with the + /// supplied to the constructor. + /// + protected override AuthenticationHandler CreateHandler() + { + return new PayPalAuthenticationHandler(httpClient, logger); + } + + private HttpMessageHandler ResolveHttpMessageHandler(PayPalAuthenticationOptions options) + { + HttpMessageHandler handler = options.BackchannelHttpHandler ?? new WebRequestHandler(); + + // If they provided a validator, apply it or fail. + if (options.BackchannelCertificateValidator != null) + { + // Set the cert validate callback + var webRequestHandler = handler as WebRequestHandler; + if (webRequestHandler == null) + { + throw new InvalidOperationException(Resources.Exception_ValidatorHandlerMismatch); + } + webRequestHandler.ServerCertificateValidationCallback = options.BackchannelCertificateValidator.Validate; + } + + return handler; + } + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/PayPal/PayPalAuthenticationOptions.cs b/Owin.Security.Providers/PayPal/PayPalAuthenticationOptions.cs new file mode 100644 index 0000000..d03c670 --- /dev/null +++ b/Owin.Security.Providers/PayPal/PayPalAuthenticationOptions.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using Microsoft.Owin; +using Microsoft.Owin.Security; + +namespace Owin.Security.Providers.PayPal +{ + public class PayPalAuthenticationOptions : AuthenticationOptions + { + public class PayPalAuthenticationEndpoints + { + /// + /// Endpoint which is used to redirect users to request PayPal access + /// + /// + /// Defaults to https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize + /// + public string AuthorizationEndpoint { get; set; } + + /// + /// Endpoint which is used to exchange code for access token + /// + /// + /// Defaults to https://api.paypal.com/v1/identity/openidconnect/tokenservice + /// + public string TokenEndpoint { get; set; } + + /// + /// Endpoint which is used to obtain user information after authentication + /// + /// + /// Defaults to https://api.paypal.com/v1/identity/openidconnect/userinfo/?schema=openid + /// + public string UserInfoEndpoint { get; set; } + } + + private const string AuthorizationEndPoint = "https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize"; + private const string TokenEndpoint = "https://api.paypal.com/v1/identity/openidconnect/tokenservice"; + private const string UserInfoEndpoint = "https://api.paypal.com/v1/identity/openidconnect/userinfo/?schema=openid"; + + private const string SandboxAuthorizationEndPoint = "https://www.sandbox.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize"; + private const string SandboxTokenEndpoint = "https://api.sandbox.paypal.com/v1/identity/openidconnect/tokenservice"; + private const string SandboxUserInfoEndpoint = "https://api.sandbox.paypal.com/v1/identity/openidconnect/userinfo/?schema=openid"; + + /// + /// Gets or sets the a pinned certificate validator to use to validate the endpoints used + /// in back channel communications belong to PayPal. + /// + /// + /// The pinned certificate validator. + /// + /// + /// 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 PayPal. + /// 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 PayPal. + /// + /// + /// The back channel timeout in milliseconds. + /// + 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. + /// Default value is "/signin-github". + /// + 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 { return Description.Caption; } + set { Description.Caption = value; } + } + + /// + /// Gets or sets the PayPal supplied Client ID + /// + public string ClientId { get; set; } + + /// + /// Gets or sets the PayPal supplied Client Secret + /// + public string ClientSecret { get; set; } + + /// + /// Gets or sets the PayPal Sandbox server to connect + /// + public bool IsSandbox { get; set; } + + /// + /// Gets the sets of OAuth endpoints used to authenticate against PayPal. Overriding these endpoints allows you to use PayPal Enterprise for + /// authentication. + /// + public PayPalAuthenticationEndpoints Endpoints { get; set; } + + /// + /// Gets or sets the used in the authentication events + /// + public IPayPalAuthenticationProvider Provider { get; set; } + + /// + /// A list of permissions to request. + /// + public IList Scope { get; private 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 data handled by the middleware. + /// + public ISecureDataFormat StateDataFormat { get; set; } + + /// + /// Initializes a new + /// + public PayPalAuthenticationOptions(bool isSandbox=false) + : base("PayPal") + { + IsSandbox = isSandbox; + Caption = Constants.DefaultAuthenticationType; + CallbackPath = new PathString("/signin-paypal"); + AuthenticationMode = AuthenticationMode.Passive; + Scope = new List{ + "openid","profile","email","address","phone" + }; + BackchannelTimeout = TimeSpan.FromSeconds(60); + Endpoints = new PayPalAuthenticationEndpoints + { + AuthorizationEndpoint = isSandbox ? SandboxAuthorizationEndPoint : AuthorizationEndPoint, + TokenEndpoint = isSandbox ? SandboxTokenEndpoint : TokenEndpoint, + UserInfoEndpoint = isSandbox ? SandboxUserInfoEndpoint : UserInfoEndpoint + }; + } + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/PayPal/Provider/IPayPalAuthenticationProvider.cs b/Owin.Security.Providers/PayPal/Provider/IPayPalAuthenticationProvider.cs new file mode 100644 index 0000000..a01d6d3 --- /dev/null +++ b/Owin.Security.Providers/PayPal/Provider/IPayPalAuthenticationProvider.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; + +namespace Owin.Security.Providers.PayPal +{ + /// + /// Specifies callback methods which the invokes to enable developer control over the authentication process. /> + /// + public interface IPayPalAuthenticationProvider + { + /// + /// Invoked whenever PayPal succesfully authenticates a user + /// + /// Contains information about the login session as well as the user . + /// A representing the completed operation. + Task Authenticated(PayPalAuthenticatedContext context); + + /// + /// Invoked prior to the being saved in a local cookie and the browser being redirected to the originally requested URL. + /// + /// + /// A representing the completed operation. + Task ReturnEndpoint(PayPalReturnEndpointContext context); + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/PayPal/Provider/PayPalAuthenticatedContext.cs b/Owin.Security.Providers/PayPal/Provider/PayPalAuthenticatedContext.cs new file mode 100644 index 0000000..05cf1dd --- /dev/null +++ b/Owin.Security.Providers/PayPal/Provider/PayPalAuthenticatedContext.cs @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; +using System.Globalization; +using System.Security.Claims; +using Microsoft.Owin; +using Microsoft.Owin.Security; +using Microsoft.Owin.Security.Provider; +using Newtonsoft.Json.Linq; + +namespace Owin.Security.Providers.PayPal +{ + /// + /// Contains information about the login session as well as the user . + /// + public class PayPalAuthenticatedContext : BaseContext + { + /// + /// Initializes a + /// + /// The OWIN environment + /// The JSON-serialized user + /// PayPal Access token + /// PayPal Refresh token + public PayPalAuthenticatedContext(IOwinContext context, JObject user, string accessToken, string refreshToken) + : base(context) + { + User = user; + AccessToken = accessToken; + RefreshToken = refreshToken; + + Id = TryGetValue(user, "user_id").Replace("https://www.paypal.com/webapps/auth/identity/user/",""); + Name = TryGetValue(user, "name"); + Email = TryGetValue(user, "email"); + } + + /// + /// Gets the JSON-serialized user + /// + /// + /// Contains the PayPal user obtained from the User Info endpoint. By default this is https://api.paypal.com/user but it can be + /// overridden in the options + /// + public JObject User { get; private set; } + + /// + /// Gets the PayPal access token + /// + public string AccessToken { get; private set; } + + public string RefreshToken { get; private set; } + + /// + /// Gets the PayPal user ID + /// + public string Id { get; private set; } + + /// + /// Gets the user's name + /// + public string Name { get; private set; } + + /// + /// Gets the PayPal emails + /// + public string Email { get; private set; } + + /// + /// Gets the representing the user + /// + public ClaimsIdentity Identity { get; set; } + + /// + /// Gets or sets a property bag for common authentication properties + /// + public AuthenticationProperties Properties { get; set; } + + private static string TryGetValue(JObject user, string propertyName) + { + JToken value; + return user.TryGetValue(propertyName, out value) ? value.ToString() : null; + } + } +} diff --git a/Owin.Security.Providers/PayPal/Provider/PayPalAuthenticationProvider.cs b/Owin.Security.Providers/PayPal/Provider/PayPalAuthenticationProvider.cs new file mode 100644 index 0000000..6d907c4 --- /dev/null +++ b/Owin.Security.Providers/PayPal/Provider/PayPalAuthenticationProvider.cs @@ -0,0 +1,50 @@ +using System; +using System.Threading.Tasks; + +namespace Owin.Security.Providers.PayPal +{ + /// + /// Default implementation. + /// + public class PayPalAuthenticationProvider : IPayPalAuthenticationProvider + { + /// + /// Initializes a + /// + public PayPalAuthenticationProvider() + { + OnAuthenticated = context => Task.FromResult(null); + 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 PayPal succesfully authenticates a user + /// + /// Contains information about the login session as well as the user . + /// A representing the completed operation. + public virtual Task Authenticated(PayPalAuthenticatedContext context) + { + return OnAuthenticated(context); + } + + /// + /// Invoked prior to the being saved in a local cookie and the browser being redirected to the originally requested URL. + /// + /// + /// A representing the completed operation. + public virtual Task ReturnEndpoint(PayPalReturnEndpointContext context) + { + return OnReturnEndpoint(context); + } + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/PayPal/Provider/PayPalReturnEndpointContext.cs b/Owin.Security.Providers/PayPal/Provider/PayPalReturnEndpointContext.cs new file mode 100644 index 0000000..68f9772 --- /dev/null +++ b/Owin.Security.Providers/PayPal/Provider/PayPalReturnEndpointContext.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using Microsoft.Owin; +using Microsoft.Owin.Security; +using Microsoft.Owin.Security.Provider; + +namespace Owin.Security.Providers.PayPal +{ + /// + /// Provides context information to middleware providers. + /// + public class PayPalReturnEndpointContext : ReturnEndpointContext + { + /// + /// + /// + /// OWIN environment + /// The authentication ticket + public PayPalReturnEndpointContext( + IOwinContext context, + AuthenticationTicket ticket) + : base(context, ticket) + { + } + } +} diff --git a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs index bf04d4a..d4a7884 100755 --- a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs +++ b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs @@ -17,6 +17,7 @@ using Owin.Security.Providers.GooglePlus.Provider; using Owin.Security.Providers.HealthGraph; using Owin.Security.Providers.Instagram; using Owin.Security.Providers.LinkedIn; +using Owin.Security.Providers.PayPal; using Owin.Security.Providers.Reddit; using Owin.Security.Providers.Salesforce; using Owin.Security.Providers.StackExchange; @@ -209,6 +210,12 @@ namespace OwinOAuthProvidersDemo //app.UseFoursquareAuthentication( // clientId: "", // clientSecret: ""); + + //app.UsePayPalAuthentication( + // clientId: "", + // clientSecret: "", + // isSandbox: false); + } } } \ No newline at end of file From 4bf2cbc1c01e70e693199ca763ca320873079073 Mon Sep 17 00:00:00 2001 From: Jerrie Pelser Date: Wed, 8 Apr 2015 15:29:14 +0700 Subject: [PATCH 17/22] Fix naming conventions while I'm at it... --- .../BattleNetAuthenticationHandler.cs | 99 +++++++++---------- .../BattleNetAuthenticationMiddleware.cs | 10 +- 2 files changed, 54 insertions(+), 55 deletions(-) diff --git a/Owin.Security.Providers/BattleNet/BattleNetAuthenticationHandler.cs b/Owin.Security.Providers/BattleNet/BattleNetAuthenticationHandler.cs index 77c0e10..8a8454a 100644 --- a/Owin.Security.Providers/BattleNet/BattleNetAuthenticationHandler.cs +++ b/Owin.Security.Providers/BattleNet/BattleNetAuthenticationHandler.cs @@ -16,58 +16,57 @@ namespace Owin.Security.Providers.BattleNet { private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; - private string _tokenEndpoint = "https://eu.battle.net/oauth/token"; - private string _accountUserIdEndpoint = "https://eu.api.battle.net/account/user/id"; - private string _accountUserBattleTagEndpoint = "https://eu.api.battle.net/account/user/battletag"; - private string _oauthAuthEndpoint = "https://eu.battle.net/oauth/authorize"; + private string tokenEndpoint = "https://eu.battle.net/oauth/token"; + private string accountUserIdEndpoint = "https://eu.api.battle.net/account/user/id"; + private string accountUserBattleTagEndpoint = "https://eu.api.battle.net/account/user/battletag"; + private string oauthAuthEndpoint = "https://eu.battle.net/oauth/authorize"; - private readonly ILogger _logger; - private readonly HttpClient _httpClient; + private readonly ILogger logger; + private readonly HttpClient httpClient; public BattleNetAuthenticationHandler(HttpClient httpClient, ILogger logger) { - _httpClient = httpClient; - _logger = logger; + this.httpClient = httpClient; + this.logger = logger; } protected override Task InitializeCoreAsync() { - return Task.Run(() => + switch (Options.Region) { - switch (Options.Region) - { - case Region.China: - _tokenEndpoint = "https://cn.battle.net/oauth/token"; - _accountUserIdEndpoint = "https://cn.api.battle.net/account/user/id"; - _accountUserBattleTagEndpoint = "https://cn.api.battle.net/account/user/battletag"; - _oauthAuthEndpoint = "https://cn.battle.net/oauth/authorize"; - break; - case Region.Korea: - _tokenEndpoint = "https://kr.battle.net/oauth/token"; - _accountUserIdEndpoint = "https://kr.api.battle.net/account/user/id"; - _accountUserBattleTagEndpoint = "https://kr.api.battle.net/account/user/battletag"; - _oauthAuthEndpoint = "https://kr.battle.net/oauth/authorize"; - break; - case Region.Taiwan: - _tokenEndpoint = "https://tw.battle.net/oauth/token"; - _accountUserIdEndpoint = "https://tw.api.battle.net/account/user/id"; - _accountUserBattleTagEndpoint = "https://tw.api.battle.net/account/user/battletag"; - _oauthAuthEndpoint = "https://tw.battle.net/oauth/authorize"; - break; - case Region.Europe: - _tokenEndpoint = "https://eu.battle.net/oauth/token"; - _accountUserIdEndpoint = "https://eu.api.battle.net/account/user/id"; - _accountUserBattleTagEndpoint = "https://eu.api.battle.net/account/user/battletag"; - _oauthAuthEndpoint = "https://eu.battle.net/oauth/authorize"; - break; - default: - _tokenEndpoint = "https://us.battle.net/oauth/token"; - _accountUserIdEndpoint = "https://us.api.battle.net/account/user/id"; - _accountUserBattleTagEndpoint = "https://us.api.battle.net/account/user/battletag"; - _oauthAuthEndpoint = "https://us.battle.net/oauth/authorize"; - break; - } - }); + case Region.China: + tokenEndpoint = "https://cn.battle.net/oauth/token"; + accountUserIdEndpoint = "https://cn.api.battle.net/account/user/id"; + accountUserBattleTagEndpoint = "https://cn.api.battle.net/account/user/battletag"; + oauthAuthEndpoint = "https://cn.battle.net/oauth/authorize"; + break; + case Region.Korea: + tokenEndpoint = "https://kr.battle.net/oauth/token"; + accountUserIdEndpoint = "https://kr.api.battle.net/account/user/id"; + accountUserBattleTagEndpoint = "https://kr.api.battle.net/account/user/battletag"; + oauthAuthEndpoint = "https://kr.battle.net/oauth/authorize"; + break; + case Region.Taiwan: + tokenEndpoint = "https://tw.battle.net/oauth/token"; + accountUserIdEndpoint = "https://tw.api.battle.net/account/user/id"; + accountUserBattleTagEndpoint = "https://tw.api.battle.net/account/user/battletag"; + oauthAuthEndpoint = "https://tw.battle.net/oauth/authorize"; + break; + case Region.Europe: + tokenEndpoint = "https://eu.battle.net/oauth/token"; + accountUserIdEndpoint = "https://eu.api.battle.net/account/user/id"; + accountUserBattleTagEndpoint = "https://eu.api.battle.net/account/user/battletag"; + oauthAuthEndpoint = "https://eu.battle.net/oauth/authorize"; + break; + default: + tokenEndpoint = "https://us.battle.net/oauth/token"; + accountUserIdEndpoint = "https://us.api.battle.net/account/user/id"; + accountUserBattleTagEndpoint = "https://us.api.battle.net/account/user/battletag"; + oauthAuthEndpoint = "https://us.battle.net/oauth/authorize"; + break; + } + + return Task.FromResult(true); } protected override async Task AuthenticateCoreAsync() @@ -98,7 +97,7 @@ namespace Owin.Security.Providers.BattleNet } // OAuth2 10.12 CSRF - if (!ValidateCorrelationId(properties, _logger)) + if (!ValidateCorrelationId(properties, logger)) { return new AuthenticationTicket(null, properties); } @@ -121,7 +120,7 @@ namespace Owin.Security.Providers.BattleNet }; // Request the token - var tokenResponse = await _httpClient.PostAsync(_tokenEndpoint, new FormUrlEncodedContent(body)); + var tokenResponse = await httpClient.PostAsync(tokenEndpoint, new FormUrlEncodedContent(body)); tokenResponse.EnsureSuccessStatusCode(); var text = await tokenResponse.Content.ReadAsStringAsync(); @@ -131,13 +130,13 @@ namespace Owin.Security.Providers.BattleNet var expires = (string)response.expires_in; // Get WoW User Id - var graphResponse = await _httpClient.GetAsync(_accountUserIdEndpoint + "?access_token=" + Uri.EscapeDataString(accessToken), Request.CallCancelled); + var graphResponse = await httpClient.GetAsync(accountUserIdEndpoint + "?access_token=" + Uri.EscapeDataString(accessToken), Request.CallCancelled); graphResponse.EnsureSuccessStatusCode(); text = await graphResponse.Content.ReadAsStringAsync(); var userId = JObject.Parse(text); // Get WoW BattleTag - graphResponse = await _httpClient.GetAsync(_accountUserBattleTagEndpoint + "?access_token=" + Uri.EscapeDataString(accessToken), Request.CallCancelled); + graphResponse = await httpClient.GetAsync(accountUserBattleTagEndpoint + "?access_token=" + Uri.EscapeDataString(accessToken), Request.CallCancelled); graphResponse.EnsureSuccessStatusCode(); text = await graphResponse.Content.ReadAsStringAsync(); var battleTag = JObject.Parse(text); @@ -172,7 +171,7 @@ namespace Owin.Security.Providers.BattleNet } catch (Exception ex) { - _logger.WriteError(ex.Message); + logger.WriteError(ex.Message); } return new AuthenticationTicket(null, properties); } @@ -218,7 +217,7 @@ namespace Owin.Security.Providers.BattleNet var state = Options.StateDataFormat.Protect(properties); var authorizationEndpoint = - _oauthAuthEndpoint + + oauthAuthEndpoint + "?response_type=code" + "&client_id=" + Uri.EscapeDataString(Options.ClientId) + "&redirect_uri=" + Uri.EscapeDataString(redirectUri) + @@ -250,7 +249,7 @@ namespace Owin.Security.Providers.BattleNet var ticket = await AuthenticateAsync(); if (ticket == null) { - _logger.WriteWarning("Invalid return state, unable to redirect."); + logger.WriteWarning("Invalid return state, unable to redirect."); Response.StatusCode = 500; return true; } diff --git a/Owin.Security.Providers/BattleNet/BattleNetAuthenticationMiddleware.cs b/Owin.Security.Providers/BattleNet/BattleNetAuthenticationMiddleware.cs index e54e1fa..acda7ca 100644 --- a/Owin.Security.Providers/BattleNet/BattleNetAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/BattleNet/BattleNetAuthenticationMiddleware.cs @@ -13,8 +13,8 @@ namespace Owin.Security.Providers.BattleNet { public class BattleNetAuthenticationMiddleware : AuthenticationMiddleware { - private readonly HttpClient _httpClient; - private readonly ILogger _logger; + private readonly HttpClient httpClient; + private readonly ILogger logger; public BattleNetAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, BattleNetAuthenticationOptions options) : base(next, options) @@ -26,7 +26,7 @@ namespace Owin.Security.Providers.BattleNet throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, "ClientSecret")); - _logger = app.CreateLogger(); + logger = app.CreateLogger(); if (Options.Provider == null) Options.Provider = new BattleNetAuthenticationProvider(); @@ -42,7 +42,7 @@ namespace Owin.Security.Providers.BattleNet if (String.IsNullOrEmpty(Options.SignInAsAuthenticationType)) Options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(); - _httpClient = new HttpClient(ResolveHttpMessageHandler(Options)) + httpClient = new HttpClient(ResolveHttpMessageHandler(Options)) { Timeout = Options.BackchannelTimeout, MaxResponseContentBufferSize = 1024 * 1024 * 10 @@ -59,7 +59,7 @@ namespace Owin.Security.Providers.BattleNet /// protected override AuthenticationHandler CreateHandler() { - return new BattleNetAuthenticationHandler(_httpClient, _logger); + return new BattleNetAuthenticationHandler(httpClient, logger); } private static HttpMessageHandler ResolveHttpMessageHandler(BattleNetAuthenticationOptions options) From 6bf11d015912e5b4a36db8920763040c45a31067 Mon Sep 17 00:00:00 2001 From: Anuj Pandey Date: Wed, 8 Apr 2015 17:43:20 +0530 Subject: [PATCH 18/22] Update PayPalAuthenticationOptions.cs --- Owin.Security.Providers/PayPal/PayPalAuthenticationOptions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Owin.Security.Providers/PayPal/PayPalAuthenticationOptions.cs b/Owin.Security.Providers/PayPal/PayPalAuthenticationOptions.cs index d03c670..f57079d 100644 --- a/Owin.Security.Providers/PayPal/PayPalAuthenticationOptions.cs +++ b/Owin.Security.Providers/PayPal/PayPalAuthenticationOptions.cs @@ -140,7 +140,7 @@ namespace Owin.Security.Providers.PayPal CallbackPath = new PathString("/signin-paypal"); AuthenticationMode = AuthenticationMode.Passive; Scope = new List{ - "openid","profile","email","address","phone" + "openid" }; BackchannelTimeout = TimeSpan.FromSeconds(60); Endpoints = new PayPalAuthenticationEndpoints @@ -151,4 +151,4 @@ namespace Owin.Security.Providers.PayPal }; } } -} \ No newline at end of file +} From d0981d98e116deb93e2501d596b89d83eb98ec30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Roussin-B=C3=A9langer?= Date: Wed, 8 Apr 2015 12:26:56 -0400 Subject: [PATCH 19/22] Fixed documentation --- .../Wargaming/WargamingAuthenticationMiddleware.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Owin.Security.Providers/Wargaming/WargamingAuthenticationMiddleware.cs b/Owin.Security.Providers/Wargaming/WargamingAuthenticationMiddleware.cs index 7fa890b..3f541e3 100644 --- a/Owin.Security.Providers/Wargaming/WargamingAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/Wargaming/WargamingAuthenticationMiddleware.cs @@ -18,7 +18,7 @@ namespace Owin.Security.Providers.Wargaming { /// - /// Initializes a + /// Initializes a /// /// The next middleware in the OWIN pipeline to invoke /// The OWIN application From cf3d1f8b811ad74f9309445bb1a5013c220a3e66 Mon Sep 17 00:00:00 2001 From: Jerrie Pelser Date: Thu, 9 Apr 2015 09:57:12 +0700 Subject: [PATCH 20/22] Add support for regions --- .../Owin.Security.Providers.csproj | 2 +- Owin.Security.Providers/Wargaming/Constant.cs | 12 ----- .../Wargaming/Constants.cs | 18 +++++++ ...argamingAccountAuthenticationExtensions.cs | 46 +++++++++++++----- .../WargamingAuthenticationOptions.cs | 6 ++- ...-OwinOAuthProvidersDemo-20131113093838.mdf | Bin 3211264 -> 3211264 bytes ...nOAuthProvidersDemo-20131113093838_log.ldf | Bin 1048576 -> 1048576 bytes .../App_Start/Startup.Auth.cs | 2 + 8 files changed, 58 insertions(+), 28 deletions(-) delete mode 100644 Owin.Security.Providers/Wargaming/Constant.cs create mode 100644 Owin.Security.Providers/Wargaming/Constants.cs diff --git a/Owin.Security.Providers/Owin.Security.Providers.csproj b/Owin.Security.Providers/Owin.Security.Providers.csproj index e311456..ee77c09 100644 --- a/Owin.Security.Providers/Owin.Security.Providers.csproj +++ b/Owin.Security.Providers/Owin.Security.Providers.csproj @@ -260,7 +260,7 @@ - + diff --git a/Owin.Security.Providers/Wargaming/Constant.cs b/Owin.Security.Providers/Wargaming/Constant.cs deleted file mode 100644 index 9abca13..0000000 --- a/Owin.Security.Providers/Wargaming/Constant.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; - -namespace Owin.Security.Providers.Wargaming -{ - internal static class Constants - { - internal const string DefaultAuthenticationType = "Wargaming"; - } -} \ No newline at end of file diff --git a/Owin.Security.Providers/Wargaming/Constants.cs b/Owin.Security.Providers/Wargaming/Constants.cs new file mode 100644 index 0000000..a2fc304 --- /dev/null +++ b/Owin.Security.Providers/Wargaming/Constants.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Owin.Security.Providers.Wargaming +{ + internal static class Constants + { + internal const string DefaultAuthenticationType = "Wargaming"; + + internal const string ProviderDiscoveryUriNorthAmerica = "https://na.wargaming.net/id/openid/"; + internal const string ProviderDiscoveryUriEurope = "https://eu.wargaming.net/id/openid/"; + internal const string ProviderDiscoveryUriRussia = "https://ru.wargaming.net/id/openid/"; + internal const string ProviderDiscoveryUriAsia = "https://asia.wargaming.net/id/openid/"; + internal const string ProviderDiscoveryUriKorea = "https://kr.wargaming.net/id/openid/"; + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/Wargaming/WargamingAccountAuthenticationExtensions.cs b/Owin.Security.Providers/Wargaming/WargamingAccountAuthenticationExtensions.cs index ea0fd36..02b9403 100644 --- a/Owin.Security.Providers/Wargaming/WargamingAccountAuthenticationExtensions.cs +++ b/Owin.Security.Providers/Wargaming/WargamingAccountAuthenticationExtensions.cs @@ -1,19 +1,38 @@ -using Microsoft.Owin; -using System; +using System; +using Microsoft.Owin; namespace Owin.Security.Providers.Wargaming { /// - /// Extension methods for using + /// Extension methods for using /// public static class WargamingAccountAuthenticationExtensions { + private static string ResolveRegionDiscoveryUri(WargamingAuthenticationOptions.Region region) + { + switch (region) + { + case WargamingAuthenticationOptions.Region.NorthAmerica: + return Constants.ProviderDiscoveryUriNorthAmerica; + case WargamingAuthenticationOptions.Region.Europe: + return Constants.ProviderDiscoveryUriEurope; + case WargamingAuthenticationOptions.Region.Russia: + return Constants.ProviderDiscoveryUriRussia; + case WargamingAuthenticationOptions.Region.Asia: + return Constants.ProviderDiscoveryUriAsia; + case WargamingAuthenticationOptions.Region.Korea: + return Constants.ProviderDiscoveryUriKorea; + default: + return Constants.ProviderDiscoveryUriNorthAmerica; + } + } + /// - /// Authenticate users using Wargaming + /// Authenticate users using Wargaming /// - /// The passed to the configuration method + /// The passed to the configuration method /// Middleware configuration options - /// The updated + /// The updated public static IAppBuilder UseWargamingAccountAuthentication(this IAppBuilder app, WargamingAuthenticationOptions options) { if (app == null) @@ -25,20 +44,21 @@ namespace Owin.Security.Providers.Wargaming throw new ArgumentNullException("options"); } - return app.Use(typeof(WargamingAuthenticationMiddleware), app, options); + return app.Use(typeof (WargamingAuthenticationMiddleware), app, options); } /// - /// Authenticate users using Steam + /// Authenticate users using Steam /// - /// The passed to the configuration method - /// The wargaming application key - /// The updated - public static IAppBuilder UseWargamingAccountAuthentication(this IAppBuilder app, string appId) + /// The passed to the configuration method + /// The wargaming application ID + /// The to authenticate + /// The updated + public static IAppBuilder UseWargamingAccountAuthentication(this IAppBuilder app, string appId, WargamingAuthenticationOptions.Region region = WargamingAuthenticationOptions.Region.NorthAmerica) { return UseWargamingAccountAuthentication(app, new WargamingAuthenticationOptions { - ProviderDiscoveryUri = "https://na.wargaming.net/id/openid/", + ProviderDiscoveryUri = ResolveRegionDiscoveryUri(region), Caption = "Wargaming", AuthenticationType = "Wargaming", CallbackPath = new PathString("/signin-wargaming"), diff --git a/Owin.Security.Providers/Wargaming/WargamingAuthenticationOptions.cs b/Owin.Security.Providers/Wargaming/WargamingAuthenticationOptions.cs index 040cf0a..be1a2a7 100644 --- a/Owin.Security.Providers/Wargaming/WargamingAuthenticationOptions.cs +++ b/Owin.Security.Providers/Wargaming/WargamingAuthenticationOptions.cs @@ -15,9 +15,11 @@ namespace Owin.Security.Providers.Wargaming /// public enum Region { + NorthAmerica, Europe, - US, - Russia + Russia, + Asia, + Korea } /// diff --git a/OwinOAuthProvidersDemo/App_Data/aspnet-OwinOAuthProvidersDemo-20131113093838.mdf b/OwinOAuthProvidersDemo/App_Data/aspnet-OwinOAuthProvidersDemo-20131113093838.mdf index 93d2e48cc2b4de74808e50270618c9e798058c12..36759ec9eed69915d80dadeefe96aecbfde14c1b 100644 GIT binary patch delta 2428 zcmb7FYfKbZ6ux(6ce%U3vdb(B0^;xxmSyE7J}{atShcZ9p@LLf)R8K!tyomBtrA?L zU5GIa)X;;qDi~^OV;YIdpnU*Me-P7Ht;AZ4y8U6LHEA)m7MoUk?#wPB_@|!CH}}lB z=brnWb06dLeM5a5r>RShlL;Zsln{KzrT$>zC;Rixr>IpjeUTbv>}ZC8WGY2!D!K}2 zx&%KZQ`I{zwOF~>lY|J#?&4#+F_x?ETD?o=n`g8`jL7% zQ^>NQIWSW*Clv@*kE0i-2n$8P_WHf=-_nC9LWG4fwdOV9^O#r}yZC(55Fy#I=>fD} zrpZl;Pf!(~*t5o+PUd58HnYZYN1mvRa3MrQNRF=QI-<`J5c_QATw*8l!#w{cK=*Ai z$;CCEG#3-kKaHFcc2XXU3nv?pj*xn|^qV*pS~A2&P<}Bo_+mt~SO<#<@jazElEGr= zo-X>}yE~#Sdbe&P3Bfq26z<*;Q|S)qllnHzTslK zEk54M8AVNE2`6K2tAKP zr=`dq5h*&mtoI}sdL))>yQ3Xf!odB5GNc@?;k)9DVzAK6g=8M7Bu`_3c#$@eH%Kk1 zL2VPML;DgeSRHwW)RQW>n=cKhrGg=es#`>Z?Folof?q{Ldt1P;t!b~xfH10iO{RTs zyA?VIi77OYP=GDpH8LU&p(Tkem-n{K*{W}4pJ`)))fw8n++Wzg>+&ubtrTxT@gdWz z^xLN6hfM16Lt#6s#?S9`EsFk{cTi5}vDy^opl2cPnlY=bgIQ7C{0`%)sV%@5es;cW z(mu_+d>m(?`-CMHER+^%!BPo27*GJ-XiQVX>eD!VOSY9pZJ>%|=6Rfh<-T)YWni z8!8)LmBdg9u>G>RWPfml+0k$s2?NVn7POQzlbPQS9Ffram!#X^vofr3B!$vF%&mDr z{DEO7BbKhS73N@+Cb+ z|9vTiuG00tx&AEJH(->*%h9Kovn<30i4_XHxDBdJZcr+4H}&d6N;eA*$Q_f$4LCa= zr!i?6!+1fxW1V1t3u6*4NCgsp?gb>gM00DxRYRB&7DPBA0uhO@s@W}3BRTF)yf_Fs zYF-iFi0#Bf#CJ|e<_~1w)=S(U)icF3TRTKxyAtJz$|J>OFvRJkwuA0;gi-xzlw7?%Is`1Qq;IL3DX%87!&n&4@X zswA-HNGZ_ZmRztRM@nj4WP_`DQnR>@R)9TMTKk0e8{qxMK*__H7d#mA)4cJRducU~ zxDp;_OSbfb^v$aMsaO*O!Qxibz6C oL&%6^L<%Amk%pL#NJnHKT!>7B8>Y||09?31b7Ig(O<6@R+!lGt#QWGW1{xB?N44pF1eeG+w>96ZJrOXP9NDzz;V|kk|CJ$6S+t? z7tr_{_{~p(!T~zcT=7{jK-RQi%^2yUd?Fm>-mC&=12hc?in5^lEZ)Tw;^s1+mWjnS8j;b-VXwEq5JLshiBe=3Az^u@tqT zc<>nIqBNGF6n}p5vZVbq^BOrbaQ+KRG58itZf<5Vp^k&a`V!OwnKuM&0p2B)3Y5T( zowOR%m#75Y0+rZRLibg=dFR52K9=4y_hn1*(W?c-4*njY4l*05l;7A6bN6L0_*P{{ zc0u16ji0ApIM*X&7vOpjQ@6vtztDW`M^nzc0Qcg!!5N}W#0{<8LNPQ9Q@0ilj)XKX zP3wzL5mF&qiDAfXEce`gNranO#oyc=vpIzByTde~%SW^F`FdImYNk+x-Yz|(pTl%n zH_Oz~_MFV3_4Gz0e?UWeH*o&i?Eg4-w)A8nvBF#%t%KnxHiW-Cjul28$XOkniD0v> z1X_;Lux16Z`!a>!UlB^+ho`Yb?g>#s9k3d~FW(kj*B-^Pt$5B@&Fmg5J08WdbBgX= zsAyS{^NQst*1H$(MX<)%6*)lKv+_S&-VM&zFv^KGv|&8qCY&(GCV}DQ=#s*q?!i08 zvMwzL1vfOV%6SFu&i%AZhF39OPEPF;M7Yk69o;2(_61CMmu8m4(?iUN1t~6WFRHv!^VE^ZJ*>ua7={n)p7F?e?sFx|9W)U6Ufa{Hwi@B$pTMh=VOJ zI%{XcpBnhXR0{j#F`V^qzo5*omOfU_^ar!yQm!%?-oN0gg4JVA4?BCoWiG_CgPF^& zF6K+S{#C2*l+DW@pr;;;KMnrMC-@oT`0u$Z&fL?GJ7pHzF2@R3OP}#8QB<8adqR;D ziaVifNGP6!Qk+mq5=v=8DN88cX{FqwhFi4`oVHwY|AEo;U3kjt|F+s5j6Ri1x%@>p z@4#sbw5Q8G$=-B1Qh`(=RfrGqBLU#& D>D zLppfEil{5PfyfHZ4&s?00%3G^b#(PPv!jUUfcMROUsZkYb-x^IW>x+9eH%Bk=%6c<9si*P*+T8UP_x@kj>n6?%vL22x-;Y}PUG6Wx z%Qf&YpZG4pI>=X>EnAYrpr%9bTKlI8!&dL3ZceW zp{~h*SrG$(>ejw856@&+<13!)NJlIlY`Bzn0;~#tR~~AU3Tj*gl=2xLiRhjUHY~is z#12t+kPZy2Ndu$v_W|Z#T_$_Le?d$#DT@R)e(Mw^*X6*{O~O+y1FCLP4q;##Z~$J} zs1!g@RR|slN)3Fbf*3BqiaDRMl!t010J?W3ZYY#zg|5`aM?pNF1n_i|0-zB=nYNTI z{{cWrTtSYfGZp7cXSapV0rqqO^rbO4@ zIAgQRmkdIm>nEoN2n(xc7q5>{&o*#AtG6etaj9q6d}g?jdj0RJ(D-iU6O%q70E~<6 z;D-2~6%f;EH5$JDDuBcAcu`&&HN9%Ha+kOI38|K=^O@Ua^-N-x`<@>r-P-g^rAL;p zFHB7j>I}vq71S4I7fjJr{rb!WSR(|LM$WG<%<9e8T;|v@G+=NP1rA<}3~(f}Tt)=m zTn**05UzwpummoFDR5AGk*zxNsb;7Sie0Oe6^)18%-#BR*gMoi+)Mxcp&XL~koFff zICEHV0}v5y4Dj0JN+G+I&n$mQx4>ZpC%h#^e7`62jij$J3KT8nMad_h$+J=+hYP$c z+3+(t=yFBB9%2Aqkp)NBzb|JMRf~QP%KqH;-D7G@({asuxc=$k3IO%z#!xUNa-k@X zAHE9I7xoSCr za3fWdXUTCU7L-pI3{|H7;BpMc>(bh8!ht$Dyh6BFo?ETLi|gqEe2Ztdyj7QHt3m}W zbrneqma|?}uNP+n;4quH=DgT|u3zW%$>88&o`-#I&;Kihr}GKUjd%U6>b_2&Sx*Rn zzf}fTpot4A56K>JPH@kCtGbyD;b;U6Jf!eoct)YTNQZEbQ9wH67a#L!%lO=+X~Bro zWpM!iZOWp1uGMkJ`Aj1ne@z^RcHU+qGbVS3oKHpV-1LDoNJZk(T0(enjI;fw%NW(K8Z1l>fu2t9wz`F{$=1f z8LLO3#DGCC3s;_>1o6eLEu;=6L&w(r(f?S>y zVUa&#jtN;5QWeJSA>1zC8q&Ait5PI$$hTig-+l>Sq9*y^31^8n&;PUd@Ump>-AF8v z^IZsw_U=@}F9Nfsp@ysg^(n?n2i}bep^P@yVHxrrd6!Xo@E&AN_x!!USit^<3^D4$ z+)h1CafWd~9zUhM$2+wWYf-9*Ao<7Q!2nC7OMSt;B?W$ zxSomXCpJ+=L6J27BdfCT2HerarHp$@OEqoSQ_^+}tz|(3&Q3 ztq|+qg=c(TE&4p8{yd*pKlfgg)A9hz@5XB*Brh+W*|5<(D{XjaRwNyxu#6chvwp76 z@QA!SYi<8VGdgWVs3^gucd&5L@=~98XnDLCdFRctaQ~66!h}N`0e2glvlA~ZPH8^`Xuo!N;0I@?F&`uWU+T4=dD_#@>0Y-i%^68 z_MgmJG4pDb*;_2UnwuJ0uJTgF8Re8${XnhwLg%H4gbFU#T9F(}=FrN4DXQn@#wOqu zC1qOUHA+v0c=Q^obM(PlQMOp+Wr`aYuN29Z4q{<^?TR-t86My+;jcqA~<)Zn0bS$JwPnH;rca= zelhe$m60#bxbfKpe%vFM3=|0~_N36&AX143B~-fNDXDa@cr zf{@pHrV#i$n?nAUKnlNNo6ye)uTBMZAhmqD@J$S)h!x%zxx%}{d!Jn4Eenr~GQwJD zg*UIW6<(#;gcflWSGcwt&4+fT8_mZGJ&An{aK7aq)DViMd`z)?nqS5;Rj0+*7TM@Z zSmAifufyhf*k=QtB#>g^u1Vbn^kqUid*>0q7c9jdFt#N`eVmIQQG}QCNJPt{2o3hv zEvQDc`VC2;V6@dB(QH&tWkEx}A(>^SxaOJhe*-+n`bZr7S}o5f6Bb^GE}cGPa{JC} zm7Vuis_MKyMs!}QU2(oSHUNg&Tk_J=L}XXexIwL0@|Wy3p;hX68L!pyyi-p7rR2Ax zJQ=)kkZi_`{5IRw_V|!K4_I8mH2;i^7;qMh#WOYh1|Csh4{kCBL{oj!sxRy#O3I_` zU%h4wO`M2DC&Or5Brkw*VCP+6q@FtCQ2x$0wqaSB!tKy9v%+P1R-lZQ!u@!rX8K@f zdcpp%$;dTK`}jW?$0xW{OUb9| zD~eoTKYfldV$6iR_yM>(tW#J|v_sEYlp46yKMv2*5n|fQ`CjQpd(P{|kWp`^HCIhJ zk#vL=#Do=i@G}ckFv4I3eZ+y6Ev+E&LL(=z=ES{T{~=O9DXhd7QWE8|#==q*Ytg6{ zq^pOhH zjzjB2T)vy2%C}Awd4*N>kp?rl_e!lJTPw>q>^s((`Ms`(B3KUdaL3&*YG>u!pFd}u zYzJ&J&odg|kLrt$lR14Ubo`{kz-;mhK*s6HnMsq({>Qm{q!=tLpm@bSTOERKiD`G_ znt#NvLo$+v#`vP@JjtF_X3)qo4vO67img-iyI;}#u{dK#L90g%w4{>`YW%aD;g7WE z>Tb!^;c1Gi9}{Rt+HF@%HcuNANl)5SWBOTGoanjRK5(m6!?-TPo)c z&XC zY-HD<7%5;vndb=Xl1s~!S?jK#_2K;`IFXw0lv~ zZiJ@YC$jIcuud=j&$LtOO?Xk#&Q5sEh|!-sDAJLfNcW;t&7{i;km!Ztg(@OgMuF3{Xd!R{E~NrVMz{H*#Gj;ls4HYCO=v5P7d;pmO62w6c;!2 zO;w*IfaV0ibSS5FPTUyhbxwMZ_1SCpnQF0!26n?ltAr*iR>U)~23>Oa|bp#0!(E4nesQ?YS$K zC9(Dc(X!S7&h=y2ID2Uf<`&tbyq>j5<6OFW*=PDtmSk7>9D3sI^jM`Q6ZSI0ZFrPzZK zF!yYGOOu(~&}5d|!30lyI-5&tJfUP8iJsqtMAY9DBr=gGQ}1!`dld=tI4rST)ndzA8w^Meby9c-;G1cCd={dXM zesfvsKv(F|1B7Ak$V6ivz@RT}c+xDe{e2uj`rFg{cpedLn=+EZufr6UciMycVtYI6 zX?;C+jj>P>d63R>h{ZEM#LG+k@#_ng@38Z-9R}pt&u5cDTK!J-xGWxkHBI}XJ{aaZ za9yGZ*JthG{tlG+_LcoTBkXdYr_Q!=9D;%Nm>d-NV?Ec6E0Hfc?&YfnSQ@)Qt~+RO zczVWE6RFCXiqDcmp4d9r)5{PAg-;KW?^TnfvCc(U%fjM*JSfzj9Fs&7N+z$u_6$lY zI{u*tC0cd8_5Oa@IWFpTYha2kq3FSsi$T}%x~zrLsd!Mqyj~YQh0`9c%Tg}UZ!jJz zt%GGcur16`GG3Q83TU2FyCOZ)-rvu(_kSN@yd+tSgElYNQoI!7K@rwcaoMi+FEo4P z3(W;t_jmY7?w(E;Y{QyOKpitvy_8cRj&40cWIgq61QZhV^BFV|CQMQd@$}5y1V2FTW1~=BpQd z)i49B2KJR~%Kk;Zk!_5k86s8O{LIJ>7i(onsr!3@GU2e^xS@(=vLZm~usvH46h0RZ zkghHk7d2#0frL{Qk}~T5XT; zkKUJ*kLcxCjr=oz#@X~?s-6-1{+MuhOUptSl^V{R>KAF7R1clxFMcWkSO*)l)l@^t zc<2<{|NW%q!#h*kS?%Ue6;>pxrz~930e@bS{24q>xpqLfWvl`4QkVRx!V(mys6+Fo ztSkPklEpDRA3WsX4=Ex3sDGBT5^i?z=T($3f2bUpA)$83A62q5SP}8T--21Fx(*L& zV*j6(I`~s1a~WW@0UC3$+^OdZd z+-cIyv?NUJfIE97cWR21Yqy45###V-yX212Y+@+omP3{D-B8{dk$1d)GJNqPezP?Jiwvr;%k@j`TogkK^ zc?Wgqd8gII9o#tM?RE=`5)2!zPLY*NE9XiSd$W0!ypKLBI zJM1D)P?Cp9qdey(k2{PS;I%+|^6cw?JcGiI{{}c8+6V_hng8yB52*KCPi;RO9@j&* zlRZ9-XO8y+2Ybk2PWG_b7UnBiH`$Y{o0&51_zu{!U$Q4~i}LLyQP_$j?eCI3O0x;5 zL$l|LuGo{MffOCr>|_sVA@=Oo?77v!9&!=0hwYG9yJSz-xLm>NW{;&2?*Gpdh&}j$ ziiOSysnhJK(#}#c^?}MIQC-p}q@qJlxe&SOGgKog&AN%{6Rp~%{eX$g8|6DUf82r8 z0K@NZ&!7F>;ZK3aGQZSx@#lvI)G2{Z)_~?*vC=^xa+#ArBedP*HYMvOf&99emQkm4 zK%h2BpuLYM=Z;jL1YuJuwRK4#rP;*)3l0)Ux^bxETd#=8XR3x#WN&oRhjb8q+BAJ` zbI^wv$Mj(Y>MVXrId^*mbq;h%9i`dC|M3)4XJ+Tr zsnjrv-h0eR9nwM6IiRU?hl4s40!$sYLL%*wI$fc1g{qr6RgCZOXa{vd$~1M@QPdmd znmXINrcOvj2VQdFaZ_iN##5T|po==?iaJag|crT417r3`=H0yUOH70fmhTn^-nq5-??)yr6+av7eEFfe8qafjp1{ z5ocgHIyr|;gDH<=qND8Q&1@yCY12z}fbItL*`I+XJ4q O2fS?$_?A83R{#K%{zF9o diff --git a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs index d4a7884..a239123 100755 --- a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs +++ b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs @@ -27,6 +27,7 @@ using Owin.Security.Providers.Yahoo; using Owin.Security.Providers.OpenID; using Owin.Security.Providers.SoundCloud; using Owin.Security.Providers.Steam; +using Owin.Security.Providers.Wargaming; using Owin.Security.Providers.WordPress; namespace OwinOAuthProvidersDemo @@ -216,6 +217,7 @@ namespace OwinOAuthProvidersDemo // clientSecret: "", // isSandbox: false); + //app.UseWargamingAccountAuthentication("", WargamingAuthenticationOptions.Region.NorthAmerica); } } } \ No newline at end of file From 1e6f75df065c23e7b34397a7ecca067c44fd32b3 Mon Sep 17 00:00:00 2001 From: Jerrie Pelser Date: Thu, 9 Apr 2015 11:26:05 +0700 Subject: [PATCH 21/22] Release version 1.17 --- NuGet/Owin.Security.Providers.nuspec | 13 ++++++++----- Owin.Security.Providers/Properties/AssemblyInfo.cs | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/NuGet/Owin.Security.Providers.nuspec b/NuGet/Owin.Security.Providers.nuspec index 54e862f..3900a1d 100644 --- a/NuGet/Owin.Security.Providers.nuspec +++ b/NuGet/Owin.Security.Providers.nuspec @@ -2,7 +2,7 @@ Owin.Security.Providers - 1.16.0 + 1.17.0 Jerrie Pelser and contributors Jerrie Pelser http://opensource.org/licenses/MIT @@ -12,14 +12,17 @@ Adds additional OAuth providers for OWIN to use with ASP.NET - Additional OAuth providers for Katana (OWIN). Includes providers for LinkedIn, Yahoo, Google+, GitHub, Reddit, Instagram, StackExchange, SalesForce, TripIt, Buffer, ArcGIS, Dropbox, Wordpress, Battle.NET, Twitch and Yammer - Also adds generic OpenID 2.0 providers as well as a Steam-specific implementatio + Additional OAuth providers for Katana (OWIN). Includes providers for LinkedIn, Yahoo, Google+, GitHub, Reddit, Instagram, StackExchange, SalesForce, TripIt, Buffer, ArcGIS, Dropbox, Wordpress, Battle.NET, Twitch, Yammer, Flickr and PayPal. + Also adds generic OpenID 2.0 providers as well implementations for Steam and Wargaming. - Version 1.16 + Version 1.17 Added - - Added Foursquare Provider (Thank you Ricardo Peres - https://github.com/rjperes) + - Added Flickr, Paypal and Wargaming providers + + Fixes + - Fixes issue with LinkedIn provider not working due to changes on LinkedIn side Copyright 2013, 2014 owin katana oauth LinkedIn Yahoo Google+ GitHub Reddit Instagram StackExchange SalesForce TripIt Buffer ArcGIS Dropbox Wordpress Battle.NET Yammer OpenID Steam Twitch diff --git a/Owin.Security.Providers/Properties/AssemblyInfo.cs b/Owin.Security.Providers/Properties/AssemblyInfo.cs index e3fb8b0..1dd84fe 100644 --- a/Owin.Security.Providers/Properties/AssemblyInfo.cs +++ b/Owin.Security.Providers/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.16.0.0")] -[assembly: AssemblyFileVersion("1.16.0.0")] +[assembly: AssemblyVersion("1.17.0.0")] +[assembly: AssemblyFileVersion("1.17.0.0")] From c03cb2b78433b9b22de0d874ec2f1276085c1c98 Mon Sep 17 00:00:00 2001 From: Jerrie Pelser Date: Thu, 9 Apr 2015 11:33:37 +0700 Subject: [PATCH 22/22] Oops, my bad. Added LI fix. release 1.17.1 --- NuGet/Owin.Security.Providers.nuspec | 2 +- .../LinkedIn/LinkedInAuthenticationMiddleware.cs | 3 +++ Owin.Security.Providers/Properties/AssemblyInfo.cs | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/NuGet/Owin.Security.Providers.nuspec b/NuGet/Owin.Security.Providers.nuspec index 3900a1d..d947c92 100644 --- a/NuGet/Owin.Security.Providers.nuspec +++ b/NuGet/Owin.Security.Providers.nuspec @@ -2,7 +2,7 @@ Owin.Security.Providers - 1.17.0 + 1.17.1 Jerrie Pelser and contributors Jerrie Pelser http://opensource.org/licenses/MIT diff --git a/Owin.Security.Providers/LinkedIn/LinkedInAuthenticationMiddleware.cs b/Owin.Security.Providers/LinkedIn/LinkedInAuthenticationMiddleware.cs index 2fa7f05..3ba9bcd 100644 --- a/Owin.Security.Providers/LinkedIn/LinkedInAuthenticationMiddleware.cs +++ b/Owin.Security.Providers/LinkedIn/LinkedInAuthenticationMiddleware.cs @@ -48,6 +48,9 @@ namespace Owin.Security.Providers.LinkedIn Timeout = Options.BackchannelTimeout, MaxResponseContentBufferSize = 1024*1024*10 }; + + // Fix for LinkedIn Expect: 100- continue issue + httpClient.DefaultRequestHeaders.ExpectContinue = false; } /// diff --git a/Owin.Security.Providers/Properties/AssemblyInfo.cs b/Owin.Security.Providers/Properties/AssemblyInfo.cs index 1dd84fe..c950a1b 100644 --- a/Owin.Security.Providers/Properties/AssemblyInfo.cs +++ b/Owin.Security.Providers/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.17.0.0")] -[assembly: AssemblyFileVersion("1.17.0.0")] +[assembly: AssemblyVersion("1.17.1.0")] +[assembly: AssemblyFileVersion("1.17.1.0")]