From 287b22455def8bc283d1f6597ce7681592c1772b Mon Sep 17 00:00:00 2001 From: Tommy Parnell Date: Mon, 3 Oct 2016 17:20:56 -0400 Subject: [PATCH] save wordpress token to identity --- .../App_Start/IdentityConfig.cs | 20 ++--- .../App_Start/Startup.Auth.cs | 24 +++++- .../Controllers/AccountController.cs | 75 ++++++++++++++----- .../Controllers/ManageController.cs | 51 ++++++++++--- .../GetWordpressOAuthToken.csproj | 11 ++- .../Models/IdentityModels.cs | 6 +- GetWordpressOAuthToken/Web.config | 15 ++-- GetWordpressOAuthToken/packages.config | 3 +- 8 files changed, 149 insertions(+), 56 deletions(-) diff --git a/GetWordpressOAuthToken/App_Start/IdentityConfig.cs b/GetWordpressOAuthToken/App_Start/IdentityConfig.cs index 34fcfeb..a3b1b83 100644 --- a/GetWordpressOAuthToken/App_Start/IdentityConfig.cs +++ b/GetWordpressOAuthToken/App_Start/IdentityConfig.cs @@ -1,16 +1,16 @@ -using System; +using GetWordpressOAuthToken.Models; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.EntityFramework; +using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin; +using Microsoft.Owin.Security; +using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using System.Web; -using Microsoft.AspNet.Identity; -using Microsoft.AspNet.Identity.EntityFramework; -using Microsoft.AspNet.Identity.Owin; -using Microsoft.Owin; -using Microsoft.Owin.Security; -using GetWordpressOAuthToken.Models; namespace GetWordpressOAuthToken { @@ -40,7 +40,7 @@ namespace GetWordpressOAuthToken { } - public static ApplicationUserManager Create(IdentityFactoryOptions options, IOwinContext context) + public static ApplicationUserManager Create(IdentityFactoryOptions options, IOwinContext context) { var manager = new ApplicationUserManager(new UserStore(context.Get())); // Configure validation logic for usernames @@ -81,7 +81,7 @@ namespace GetWordpressOAuthToken var dataProtectionProvider = options.DataProtectionProvider; if (dataProtectionProvider != null) { - manager.UserTokenProvider = + manager.UserTokenProvider = new DataProtectorTokenProvider(dataProtectionProvider.Create("ASP.NET Identity")); } return manager; @@ -106,4 +106,4 @@ namespace GetWordpressOAuthToken return new ApplicationSignInManager(context.GetUserManager(), context.Authentication); } } -} +} \ No newline at end of file diff --git a/GetWordpressOAuthToken/App_Start/Startup.Auth.cs b/GetWordpressOAuthToken/App_Start/Startup.Auth.cs index 0837f0a..3eba39c 100644 --- a/GetWordpressOAuthToken/App_Start/Startup.Auth.cs +++ b/GetWordpressOAuthToken/App_Start/Startup.Auth.cs @@ -1,11 +1,13 @@ -using System; +using GetWordpressOAuthToken.Models; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.Owin; using Microsoft.Owin; using Microsoft.Owin.Security.Cookies; using Microsoft.Owin.Security.Google; using Owin; -using GetWordpressOAuthToken.Models; +using Owin.Security.Providers.WordPress; +using System; +using System.Threading.Tasks; namespace GetWordpressOAuthToken { @@ -29,12 +31,13 @@ namespace GetWordpressOAuthToken Provider = new CookieAuthenticationProvider { // Enables the application to validate the security stamp when the user logs in. - // This is a security feature which is used when you change a password or add an external login to your account. + // This is a security feature which is used when you change a password or add an external login to your account. OnValidateIdentity = SecurityStampValidator.OnValidateIdentity( validateInterval: TimeSpan.FromMinutes(30), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) } - }); + }); + app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process. @@ -63,6 +66,19 @@ namespace GetWordpressOAuthToken // ClientId = "", // ClientSecret = "" //}); + app.UseWordPressAuthentication(new WordPressAuthenticationOptions() + { + ClientId = "YOURCLIENTTOKENHERE", + ClientSecret = "YOURCLIENTSECRETHERE", + Provider = new WordPressAuthenticationProvider() + { + OnAuthenticated = context => + { + context.Identity.AddClaim(new System.Security.Claims.Claim("urn:wordpress:access_token", context.AccessToken)); + return Task.FromResult(0); + } + } + }); } } } \ No newline at end of file diff --git a/GetWordpressOAuthToken/Controllers/AccountController.cs b/GetWordpressOAuthToken/Controllers/AccountController.cs index a9820ac..32c1b51 100644 --- a/GetWordpressOAuthToken/Controllers/AccountController.cs +++ b/GetWordpressOAuthToken/Controllers/AccountController.cs @@ -1,14 +1,14 @@ -using System; +using GetWordpressOAuthToken.Models; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin.Security; +using System; using System.Globalization; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using System.Web; using System.Web.Mvc; -using Microsoft.AspNet.Identity; -using Microsoft.AspNet.Identity.Owin; -using Microsoft.Owin.Security; -using GetWordpressOAuthToken.Models; namespace GetWordpressOAuthToken.Controllers { @@ -22,7 +22,7 @@ namespace GetWordpressOAuthToken.Controllers { } - public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager ) + public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager) { UserManager = userManager; SignInManager = signInManager; @@ -34,9 +34,9 @@ namespace GetWordpressOAuthToken.Controllers { return _signInManager ?? HttpContext.GetOwinContext().Get(); } - private set - { - _signInManager = value; + private set + { + _signInManager = value; } } @@ -80,10 +80,13 @@ namespace GetWordpressOAuthToken.Controllers { case SignInStatus.Success: return RedirectToLocal(returnUrl); + case SignInStatus.LockedOut: return View("Lockout"); + case SignInStatus.RequiresVerification: return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe }); + case SignInStatus.Failure: default: ModelState.AddModelError("", "Invalid login attempt."); @@ -116,17 +119,19 @@ namespace GetWordpressOAuthToken.Controllers return View(model); } - // The following code protects for brute force attacks against the two factor codes. - // If a user enters incorrect codes for a specified amount of time then the user account - // will be locked out for a specified amount of time. + // The following code protects for brute force attacks against the two factor codes. + // If a user enters incorrect codes for a specified amount of time then the user account + // will be locked out for a specified amount of time. // You can configure the account lockout settings in IdentityConfig - var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, isPersistent: model.RememberMe, rememberBrowser: model.RememberBrowser); + var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, isPersistent: model.RememberMe, rememberBrowser: model.RememberBrowser); switch (result) { case SignInStatus.Success: return RedirectToLocal(model.ReturnUrl); + case SignInStatus.LockedOut: return View("Lockout"); + case SignInStatus.Failure: default: ModelState.AddModelError("", "Invalid code."); @@ -155,8 +160,8 @@ namespace GetWordpressOAuthToken.Controllers var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { - await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false); - + await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); + // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771 // Send an email with this link // string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id); @@ -212,7 +217,7 @@ namespace GetWordpressOAuthToken.Controllers // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771 // Send an email with this link // string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id); - // var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme); + // var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme); // await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking here"); // return RedirectToAction("ForgotPasswordConfirmation", "Account"); } @@ -333,11 +338,15 @@ namespace GetWordpressOAuthToken.Controllers switch (result) { case SignInStatus.Success: + await StoreWordpressToken(await UserManager.FindAsync(loginInfo.Login)); return RedirectToLocal(returnUrl); + case SignInStatus.LockedOut: return View("Lockout"); + case SignInStatus.RequiresVerification: return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false }); + case SignInStatus.Failure: default: // If the user does not have an account, then prompt the user to create an account @@ -347,6 +356,16 @@ namespace GetWordpressOAuthToken.Controllers } } + private async Task ProcessExternalClaims(ExternalLoginInfo loginInfo) + { + var currentIdentity = await UserManager.FindByIdAsync(loginInfo.ExternalIdentity.GetUserId()); + var userId = this.AuthenticationManager.User.Identity.GetUserId(); + foreach (var claim in loginInfo.ExternalIdentity.Claims.Where(a => a.Type.StartsWith("urn:wordpress", StringComparison.Ordinal))) + { + await UserManager.AddClaimAsync(userId, claim); + } + } + // // POST: /Account/ExternalLoginConfirmation [HttpPost] @@ -374,6 +393,7 @@ namespace GetWordpressOAuthToken.Controllers result = await UserManager.AddLoginAsync(user.Id, info.Login); if (result.Succeeded) { + await StoreWordpressToken(user); await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); return RedirectToLocal(returnUrl); } @@ -385,6 +405,25 @@ namespace GetWordpressOAuthToken.Controllers return View(model); } + private async Task StoreWordpressToken(ApplicationUser user) + { + var claimsIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie); + if (claimsIdentity != null) + { + // Retrieve the existing claims for the user and add the FacebookAccessTokenClaim + var currentClaims = await UserManager.GetClaimsAsync(user.Id); + var wordpressToken = claimsIdentity.Claims.Where(a => a.Type.Contains("wordpress:access_token")).FirstOrDefault(); + if (wordpressToken != null) + { + if (currentClaims.Count(a => a.Type.Contains("wordpress:access_token")) > 0) + { + await UserManager.RemoveClaimAsync(user.Id, wordpressToken); + } + await UserManager.AddClaimAsync(user.Id, wordpressToken); + } + } + } + // // POST: /Account/LogOff [HttpPost] @@ -424,6 +463,7 @@ namespace GetWordpressOAuthToken.Controllers } #region Helpers + // Used for XSRF protection when adding external logins private const string XsrfKey = "XsrfId"; @@ -480,6 +520,7 @@ namespace GetWordpressOAuthToken.Controllers context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider); } } - #endregion + + #endregion Helpers } } \ No newline at end of file diff --git a/GetWordpressOAuthToken/Controllers/ManageController.cs b/GetWordpressOAuthToken/Controllers/ManageController.cs index 0620beb..ef086fe 100644 --- a/GetWordpressOAuthToken/Controllers/ManageController.cs +++ b/GetWordpressOAuthToken/Controllers/ManageController.cs @@ -1,12 +1,12 @@ -using System; +using GetWordpressOAuthToken.Models; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin.Security; +using System; using System.Linq; using System.Threading.Tasks; using System.Web; using System.Web.Mvc; -using Microsoft.AspNet.Identity; -using Microsoft.AspNet.Identity.Owin; -using Microsoft.Owin.Security; -using GetWordpressOAuthToken.Models; namespace GetWordpressOAuthToken.Controllers { @@ -20,6 +20,12 @@ namespace GetWordpressOAuthToken.Controllers { } + public string WhatIsMyWordpressToken() + { + //this shouldnt really exist, but this is a way to view the actual users wordpress token claim + return UserManager.GetClaims(this.User.Identity.GetUserId()).Where(a => a.Type.Contains("wordpress:access_token")).Select(a => a.Value).FirstOrDefault() ?? string.Empty; + } + public ManageController(ApplicationUserManager userManager, ApplicationSignInManager signInManager) { UserManager = userManager; @@ -32,9 +38,9 @@ namespace GetWordpressOAuthToken.Controllers { return _signInManager ?? HttpContext.GetOwinContext().Get(); } - private set - { - _signInManager = value; + private set + { + _signInManager = value; } } @@ -309,6 +315,25 @@ namespace GetWordpressOAuthToken.Controllers return new AccountController.ChallengeResult(provider, Url.Action("LinkLoginCallback", "Manage"), User.Identity.GetUserId()); } + private async Task StoreWordpressToken(ApplicationUser user) + { + var claimsIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie); + if (claimsIdentity != null) + { + // Retrieve the existing claims for the user and add the FacebookAccessTokenClaim + var currentClaims = await UserManager.GetClaimsAsync(user.Id); + var wordpressToken = claimsIdentity.Claims.Where(a => a.Type.Contains("wordpress:access_token")).FirstOrDefault(); + if (wordpressToken != null) + { + if (currentClaims.Count(a => a.Type.Contains("wordpress:access_token")) > 0) + { + await UserManager.RemoveClaimAsync(user.Id, wordpressToken); + } + await UserManager.AddClaimAsync(user.Id, wordpressToken); + } + } + } + // // GET: /Manage/LinkLoginCallback public async Task LinkLoginCallback() @@ -319,6 +344,11 @@ namespace GetWordpressOAuthToken.Controllers return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error }); } var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login); + if (result.Succeeded) + { + var currentUser = await UserManager.FindByIdAsync(User.Identity.GetUserId()); + await StoreWordpressToken(currentUser); + } return result.Succeeded ? RedirectToAction("ManageLogins") : RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error }); } @@ -333,7 +363,8 @@ namespace GetWordpressOAuthToken.Controllers base.Dispose(disposing); } -#region Helpers + #region Helpers + // Used for XSRF protection when adding external logins private const string XsrfKey = "XsrfId"; @@ -384,6 +415,6 @@ namespace GetWordpressOAuthToken.Controllers Error } -#endregion + #endregion Helpers } } \ No newline at end of file diff --git a/GetWordpressOAuthToken/GetWordpressOAuthToken.csproj b/GetWordpressOAuthToken/GetWordpressOAuthToken.csproj index 73f4f44..cf31dc3 100644 --- a/GetWordpressOAuthToken/GetWordpressOAuthToken.csproj +++ b/GetWordpressOAuthToken/GetWordpressOAuthToken.csproj @@ -49,6 +49,14 @@ True + + ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True + + + ..\packages\Owin.Security.Providers.WordPress.2.8.0\lib\net45\Owin.Security.Providers.WordPress.dll + True + @@ -112,9 +120,6 @@ - - ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll - ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll diff --git a/GetWordpressOAuthToken/Models/IdentityModels.cs b/GetWordpressOAuthToken/Models/IdentityModels.cs index 67b996c..143afd4 100644 --- a/GetWordpressOAuthToken/Models/IdentityModels.cs +++ b/GetWordpressOAuthToken/Models/IdentityModels.cs @@ -1,8 +1,8 @@ -using System.Data.Entity; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.EntityFramework; +using System.Data.Entity; using System.Security.Claims; using System.Threading.Tasks; -using Microsoft.AspNet.Identity; -using Microsoft.AspNet.Identity.EntityFramework; namespace GetWordpressOAuthToken.Models { diff --git a/GetWordpressOAuthToken/Web.config b/GetWordpressOAuthToken/Web.config index 60b16d0..5a5d4df 100644 --- a/GetWordpressOAuthToken/Web.config +++ b/GetWordpressOAuthToken/Web.config @@ -1,4 +1,4 @@ - +