diff --git a/Owin.Security.Providers/Owin.Security.Providers.csproj b/Owin.Security.Providers/Owin.Security.Providers.csproj index e952a9f..8ac071a 100644 --- a/Owin.Security.Providers/Owin.Security.Providers.csproj +++ b/Owin.Security.Providers/Owin.Security.Providers.csproj @@ -282,11 +282,31 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Owin.Security.Providers/Untappd/ApiResponse.cs b/Owin.Security.Providers/Untappd/ApiResponse.cs new file mode 100644 index 0000000..4edaadf --- /dev/null +++ b/Owin.Security.Providers/Untappd/ApiResponse.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.Untappd +{ + + internal class ResponseRoot + { + public Meta meta { get; set; } + public Response response { get; set; } + } + + public class Meta + { + public int http_code { get; set; } + } + + public class Response + { + public string access_token { get; set; } + } + +} diff --git a/Owin.Security.Providers/Untappd/Constants.cs b/Owin.Security.Providers/Untappd/Constants.cs new file mode 100644 index 0000000..fef3041 --- /dev/null +++ b/Owin.Security.Providers/Untappd/Constants.cs @@ -0,0 +1,7 @@ +namespace Owin.Security.Providers.Untappd +{ + internal static class Constants + { + public const string DefaultAuthenticationType = "Untappd"; + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/Untappd/Provider/IUntappdAuthenticationProvider.cs b/Owin.Security.Providers/Untappd/Provider/IUntappdAuthenticationProvider.cs new file mode 100644 index 0000000..f3aab47 --- /dev/null +++ b/Owin.Security.Providers/Untappd/Provider/IUntappdAuthenticationProvider.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; + +namespace Owin.Security.Providers.Untappd +{ + /// + /// Specifies callback methods which the invokes to enable developer control over the authentication process. /> + /// + public interface IUntappdAuthenticationProvider + { + /// + /// Invoked whenever Untappd succesfully authenticates a user + /// + /// Contains information about the login session as well as the user . + /// A representing the completed operation. + Task Authenticated(UntappdAuthenticatedContext 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(UntappdReturnEndpointContext context); + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/Untappd/Provider/UntappdAuthenticatedContext.cs b/Owin.Security.Providers/Untappd/Provider/UntappdAuthenticatedContext.cs new file mode 100644 index 0000000..a40a8da --- /dev/null +++ b/Owin.Security.Providers/Untappd/Provider/UntappdAuthenticatedContext.cs @@ -0,0 +1,95 @@ +// 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.Untappd +{ + /// + /// Contains information about the login session as well as the user . + /// + public class UntappdAuthenticatedContext : BaseContext + { + /// + /// Initializes a + /// + /// The OWIN environment + /// The JSON-serialized user + /// Untappd Access token + public UntappdAuthenticatedContext(IOwinContext context, JObject user, string accessToken) + : base(context) + { + User = user; + AccessToken = accessToken; + + Id = user["response"]["user"]["id"].ToString(); + Name = user["response"]["user"]["first_name"].ToString() + " " + user["response"]["user"]["last_name"].ToString(); + Link = user["response"]["user"]["url"].ToString(); + UserName = user["response"]["user"]["user_name"].ToString(); + Email = user["response"]["user"]["settings"]["email_address"].ToString(); + AvatarUrl = user["response"]["user"]["user_avatar"].ToString(); + } + + /// + /// Gets the JSON-serialized user + /// + /// + /// Contains the Untappd user obtained from the User Info endpoint. By default this is https://api.Untappd.com/user but it can be + /// overridden in the options + /// + public JObject User { get; private set; } + + /// + /// Gets the Untappd access token + /// + public string AccessToken { get; private set; } + + /// + /// Gets the Untappd user ID + /// + public string Id { get; private set; } + + /// + /// Gets the user's name + /// + public string Name { get; private set; } + + public string Link { get; private set; } + + /// + /// Gets the Untappd username + /// + public string UserName { get; private set; } + + /// + /// Gets the Untappd email + /// + public string Email { get; private set; } + + /// + /// Gets the Untappd avatar url 100x100 + /// + public string AvatarUrl { 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; + } + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/Untappd/Provider/UntappdAuthenticationProvider.cs b/Owin.Security.Providers/Untappd/Provider/UntappdAuthenticationProvider.cs new file mode 100644 index 0000000..a290334 --- /dev/null +++ b/Owin.Security.Providers/Untappd/Provider/UntappdAuthenticationProvider.cs @@ -0,0 +1,50 @@ +using System; +using System.Threading.Tasks; + +namespace Owin.Security.Providers.Untappd +{ + /// + /// Default implementation. + /// + public class UntappdAuthenticationProvider : IUntappdAuthenticationProvider + { + /// + /// Initializes a + /// + public UntappdAuthenticationProvider() + { + 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 Untappd succesfully authenticates a user + /// + /// Contains information about the login session as well as the user . + /// A representing the completed operation. + public virtual Task Authenticated(UntappdAuthenticatedContext 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(UntappdReturnEndpointContext context) + { + return OnReturnEndpoint(context); + } + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/Untappd/Provider/UntappdReturnEndpointContext.cs b/Owin.Security.Providers/Untappd/Provider/UntappdReturnEndpointContext.cs new file mode 100644 index 0000000..688d513 --- /dev/null +++ b/Owin.Security.Providers/Untappd/Provider/UntappdReturnEndpointContext.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.Untappd +{ + /// + /// Provides context information to middleware providers. + /// + public class UntappdReturnEndpointContext : ReturnEndpointContext + { + /// + /// + /// + /// OWIN environment + /// The authentication ticket + public UntappdReturnEndpointContext( + IOwinContext context, + AuthenticationTicket ticket) + : base(context, ticket) + { + } + } +} diff --git a/Owin.Security.Providers/Untappd/UntappdAuthenticationExtensions.cs b/Owin.Security.Providers/Untappd/UntappdAuthenticationExtensions.cs new file mode 100644 index 0000000..f16a748 --- /dev/null +++ b/Owin.Security.Providers/Untappd/UntappdAuthenticationExtensions.cs @@ -0,0 +1,41 @@ +using System; + +namespace Owin.Security.Providers.Untappd +{ + public static class UntappdAuthenticationExtensions + { + /// + /// Login with Untappd. http://yourUrl/signin-Untappd will be used as the redirect URI + /// + /// + /// + /// + public static IAppBuilder UseUntappdAuthentication(this IAppBuilder app, + UntappdAuthenticationOptions options) + { + if (app == null) + throw new ArgumentNullException("app"); + if (options == null) + throw new ArgumentNullException("options"); + + app.Use(typeof(UntappdAuthenticationMiddleware), app, options); + + return app; + } + /// + /// Login with Untappd. http://yourUrl/signin-Untappd will be used as the redirect URI + /// + /// + /// + /// + /// + public static IAppBuilder UseUntappdAuthentication(this IAppBuilder app, string clientId, string clientSecret) + { + return app.UseUntappdAuthentication(new UntappdAuthenticationOptions + { + ClientId = clientId, + ClientSecret = clientSecret + }); + } + } +} \ No newline at end of file diff --git a/Owin.Security.Providers/Untappd/UntappdAuthenticationHandler.cs b/Owin.Security.Providers/Untappd/UntappdAuthenticationHandler.cs new file mode 100644 index 0000000..4a1eb15 --- /dev/null +++ b/Owin.Security.Providers/Untappd/UntappdAuthenticationHandler.cs @@ -0,0 +1,252 @@ +using System; +using System.Collections.Generic; +using System.Linq; +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; + +namespace Owin.Security.Providers.Untappd +{ + public class UntappdAuthenticationHandler : AuthenticationHandler + { + private const string StateCookie = "_StateCookie"; + private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string"; + + private readonly ILogger logger; + private readonly HttpClient httpClient; + + public UntappdAuthenticationHandler(HttpClient httpClient, ILogger logger) + { + this.httpClient = httpClient; + this.logger = logger; + } + + protected override async Task AuthenticateCoreAsync() + { + AuthenticationProperties properties = null; + + try + { + string code = null; + string state = null; + + IReadableStringCollection query = Request.Query; + IList values = query.GetValues("code"); + if (values != null && values.Count == 1) + { + code = string.Copy(values.First()); + } + + // restore State from Cookie + state = Request.Cookies[StateCookie]; + 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; + + //// Build up the body for the token request + //var body = new List>(); + //body.Add(new KeyValuePair("client_id", Options.ClientId)); + //body.Add(new KeyValuePair("client_secret", Options.ClientSecret)); + //body.Add(new KeyValuePair("redirect_url", redirectUri)); + //body.Add(new KeyValuePair("response_type", "code")); + //body.Add(new KeyValuePair("code", code)); + + // Request the token + var requestMessage = new HttpRequestMessage(HttpMethod.Get, + String.Format(@"{0}/?client_id={1}&client_secret={2}&response_type=code&redirect_url={3}&code={4}", Options.Endpoints.TokenEndpoint, Options.ClientId, Options.ClientSecret, redirectUri, code)); + requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + HttpResponseMessage tokenResponse = await httpClient.SendAsync(requestMessage); + tokenResponse.EnsureSuccessStatusCode(); + string text = await tokenResponse.Content.ReadAsStringAsync(); + + // Deserializes the token response + var response = JsonConvert.DeserializeObject(text); + string accessToken = response.response.access_token; + + // Get the Untappd user + HttpRequestMessage userRequest = new HttpRequestMessage(HttpMethod.Get, Options.Endpoints.UserInfoEndpoint + "?access_token=" + Uri.EscapeDataString(accessToken)); + userRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + HttpResponseMessage userResponse = await httpClient.SendAsync(userRequest, Request.CallCancelled); + userResponse.EnsureSuccessStatusCode(); + text = await userResponse.Content.ReadAsStringAsync(); + JObject user = JObject.Parse(text); + + var context = new UntappdAuthenticatedContext(Context, user, accessToken); + context.Identity = new ClaimsIdentity( + Options.AuthenticationType, + ClaimsIdentity.DefaultNameClaimType, + ClaimsIdentity.DefaultRoleClaimType); + + // Add access_token to Claims to be used later on authenticated Untappd API requests + context.Identity.AddClaim(new Claim("UntappdAccessToken", accessToken)); + + if (!string.IsNullOrEmpty(context.Id)) + { + context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.Id, XmlSchemaString, Options.AuthenticationType)); + } + if (!string.IsNullOrEmpty(context.UserName)) + { + context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.UserName, 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:Untappd:name", context.Name, XmlSchemaString, Options.AuthenticationType)); + } + if (!string.IsNullOrEmpty(context.Link)) + { + context.Identity.AddClaim(new Claim("urn:Untappd:url", context.Link, XmlSchemaString, Options.AuthenticationType)); + } + if (!string.IsNullOrEmpty(context.AvatarUrl)) + { + context.Identity.AddClaim(new Claim("urn:Untappd:avatar", context.AvatarUrl, XmlSchemaString, Options.AuthenticationType)); + } + + //IDictionary data = new Dictionary + // { + // { "userData", "Data" } + // }; + //properties = new AuthenticationProperties(data); + + context.Properties = properties; + await Options.Provider.Authenticated(context); + + return new AuthenticationTicket(context.Identity, context.Properties); + } + catch (Exception ex) + { + logger.WriteError(ex.Message); + } + 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); + + string authorizationEndpoint = + Options.Endpoints.AuthorizationEndpoint + + "?client_id=" + Uri.EscapeDataString(Options.ClientId) + + "&redirect_url=" + Uri.EscapeDataString(redirectUri) + + "&response_type=" + "code"; + + var cookieOptions = new CookieOptions + { + HttpOnly = true, + Secure = Request.IsSecure + }; + + Response.Cookies.Append(StateCookie, Options.StateDataFormat.Protect(properties), cookieOptions); + 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) + { + // TODO: error responses + + AuthenticationTicket ticket = await AuthenticateAsync(); + if (ticket == null) + { + logger.WriteWarning("Invalid return state, unable to redirect."); + Response.StatusCode = 500; + return true; + } + + var context = new UntappdReturnEndpointContext(Context, ticket); + context.SignInAsAuthenticationType = Options.SignInAsAuthenticationType; + context.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/Untappd/UntappdAuthenticationMiddleware.cs b/Owin.Security.Providers/Untappd/UntappdAuthenticationMiddleware.cs new file mode 100644 index 0000000..eb9d6c8 --- /dev/null +++ b/Owin.Security.Providers/Untappd/UntappdAuthenticationMiddleware.cs @@ -0,0 +1,85 @@ +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.Untappd +{ + public class UntappdAuthenticationMiddleware : AuthenticationMiddleware + { + private readonly HttpClient httpClient; + private readonly ILogger logger; + + public UntappdAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, + UntappdAuthenticationOptions 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 UntappdAuthenticationProvider(); + + if (Options.StateDataFormat == null) + { + IDataProtector dataProtector = app.CreateDataProtector( + typeof(UntappdAuthenticationMiddleware).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 Untappd 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 UntappdAuthenticationHandler(httpClient, logger); + } + + private HttpMessageHandler ResolveHttpMessageHandler(UntappdAuthenticationOptions options) + { + HttpMessageHandler handler = options.BackchannelHttpHandler ?? new WebRequestHandler(); + + // If they provided a validator, apply it or fail. + if (options.BackchannelCertificateValidator == null) return handler; + // 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/Untappd/UntappdAuthenticationOptions.cs b/Owin.Security.Providers/Untappd/UntappdAuthenticationOptions.cs new file mode 100644 index 0000000..43cc055 --- /dev/null +++ b/Owin.Security.Providers/Untappd/UntappdAuthenticationOptions.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using Microsoft.Owin; +using Microsoft.Owin.Security; + +namespace Owin.Security.Providers.Untappd +{ + public class UntappdAuthenticationOptions : AuthenticationOptions + { + public class UntappdAuthenticationEndpoints + { + /// + /// Endpoint which is used to redirect users to request Untappd access + /// + /// + /// Defaults to https://untappd.com/oauth/authenticate/ + /// + public string AuthorizationEndpoint { get; set; } + + /// + /// Endpoint which is used to exchange code for access token + /// + /// + /// Defaults to https://untappd.com/oauth/authorize + /// + public string TokenEndpoint { get; set; } + + /// + /// Endpoint which is used to obtain user information after authentication + /// + /// + /// Defaults tohttps://untappd.com/v4/user/info + /// + public string UserInfoEndpoint { get; set; } + } + + private const string AuthorizationEndPoint = "https://untappd.com/oauth/authenticate"; + private const string TokenEndpoint = "https://untappd.com/oauth/authorize"; + private const string UserInfoEndpoint = "https://api.untappd.com/v4/user/info"; + + /// + /// Gets or sets the a pinned certificate validator to use to validate the endpoints used + /// in back channel communications belong to Untappd. + /// + /// + /// 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 Untappd. + /// 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 Untappd. + /// + /// + /// 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-Untappd". + /// + 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 Untappd supplied Client ID + /// + public string ClientId { get; set; } + + /// + /// Gets or sets the Untappd supplied Client Secret + /// + public string ClientSecret { get; set; } + + /// + /// Gets the sets of OAuth endpoints used to authenticate against Untappd. Overriding these endpoints allows you to use Untappd Enterprise for + /// authentication. + /// + public UntappdAuthenticationEndpoints Endpoints { get; set; } + + /// + /// Gets or sets the used in the authentication events + /// + public IUntappdAuthenticationProvider 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 UntappdAuthenticationOptions() + : base("Untappd") + { + Caption = Constants.DefaultAuthenticationType; + CallbackPath = new PathString("/signin-untappd"); + AuthenticationMode = AuthenticationMode.Passive; + //untappd has no scopes AFAIK + Scope = new List{}; + BackchannelTimeout = TimeSpan.FromSeconds(60); + Endpoints = new UntappdAuthenticationEndpoints + { + AuthorizationEndpoint = AuthorizationEndPoint, + TokenEndpoint = TokenEndpoint, + UserInfoEndpoint = UserInfoEndpoint + }; + } + } +} \ No newline at end of file diff --git a/OwinOAuthProvidersDemo/App_Data/aspnet-OwinOAuthProvidersDemo-20131113093838.mdf b/OwinOAuthProvidersDemo/App_Data/aspnet-OwinOAuthProvidersDemo-20131113093838.mdf index 36759ec..0961ca7 100644 Binary files a/OwinOAuthProvidersDemo/App_Data/aspnet-OwinOAuthProvidersDemo-20131113093838.mdf and b/OwinOAuthProvidersDemo/App_Data/aspnet-OwinOAuthProvidersDemo-20131113093838.mdf differ diff --git a/OwinOAuthProvidersDemo/App_Data/aspnet-OwinOAuthProvidersDemo-20131113093838_log.ldf b/OwinOAuthProvidersDemo/App_Data/aspnet-OwinOAuthProvidersDemo-20131113093838_log.ldf index 106558c..75f6af2 100644 Binary files a/OwinOAuthProvidersDemo/App_Data/aspnet-OwinOAuthProvidersDemo-20131113093838_log.ldf and b/OwinOAuthProvidersDemo/App_Data/aspnet-OwinOAuthProvidersDemo-20131113093838_log.ldf differ diff --git a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs old mode 100644 new mode 100755 index 4bc02b7..77ec5fb --- a/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs +++ b/OwinOAuthProvidersDemo/App_Start/Startup.Auth.cs @@ -28,8 +28,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; +using Owin.Security.Providers.Wargaming;using Owin.Security.Providers.Untappd;using Owin.Security.Providers.WordPress; namespace OwinOAuthProvidersDemo { @@ -47,6 +46,7 @@ namespace OwinOAuthProvidersDemo // Use a cookie to temporarily store information about a user logging in with a third party login provider app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); + //app.UseUntappdAuthentication("id", "secret"); // Uncomment the following lines to enable logging in with third party login providers //app.UseMicrosoftAccountAuthentication( // clientId: "", @@ -67,7 +67,7 @@ namespace OwinOAuthProvidersDemo //app.UseYahooAuthentication("", ""); //app.UseTripItAuthentication("", ""); - + //app.UseGitHubAuthentication("", ""); //app.UseBufferAuthentication("", ""); @@ -112,7 +112,7 @@ namespace OwinOAuthProvidersDemo // ClientSecret = "", // Provider = new TwitchAuthenticationProvider() // { - + // OnAuthenticated = async z => // { //// Getting the twitch users picture @@ -121,7 +121,7 @@ namespace OwinOAuthProvidersDemo //// You should be able to access these claims with HttpContext.GetOwinContext().Authentication.GetExternalLoginInfoAsync().Claims in your Account Controller // // Commonly used in the ExternalLoginCallback() in AccountController.cs // /* - + // if (user != null) // { // var claim = (await AuthenticationManager.GetExternalLoginInfoAsync()).ExternalIdentity.Claims.First( @@ -134,7 +134,7 @@ namespace OwinOAuthProvidersDemo // } //}; //app.UseTwitchAuthentication(opt); - + //app.UseOpenIDAuthentication("http://me.yahoo.com/", "Yahoo"); @@ -194,24 +194,24 @@ namespace OwinOAuthProvidersDemo // clientSecret: ""); - //app.UseBattleNetAuthentication(new BattleNetAuthenticationOptions - //{ - // ClientId = "", - // ClientSecret = "" - //}); - //app.UseBattleNetAuthentication( - // clientId: "", - // clientSecret: ""); + //app.UseBattleNetAuthentication(new BattleNetAuthenticationOptions + //{ + // ClientId = "", + // ClientSecret = "" + //}); + //app.UseBattleNetAuthentication( + // clientId: "", + // clientSecret: ""); //app.UseAsanaAuthentication("", ""); //app.UseEveOnlineAuthentication("", ""); - //app.UseSoundCloudAuthentication("", ""); + //app.UseSoundCloudAuthentication("", ""); - //app.UseFoursquareAuthentication( - // clientId: "", - // clientSecret: ""); + //app.UseFoursquareAuthentication( + // clientId: "", + // clientSecret: ""); //app.UsePayPalAuthentication( // clientId: "",