From 5fc53dcad206062be8c3b6fa0a2295386996a97a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Ca=C3=B1izares=20Est=C3=A9vez?= Date: Thu, 29 Dec 2016 16:26:02 +0100 Subject: [PATCH] Identity Server: When click on logo redirects to original application instead of identity home --- .../Controllers/ConsentController.cs | 3 + .../Controllers/HomeController.cs | 13 +- .../Controllers/ManageController.cs | 360 ------------------ .../Services/IRedirectService.cs | 12 + .../Services/RedirectService.cs | 36 ++ .../eShopOnContainers.Identity/Startup.cs | 1 + .../Views/Shared/_Layout.cshtml | 2 +- 7 files changed, 65 insertions(+), 362 deletions(-) delete mode 100644 src/Services/Identity/eShopOnContainers.Identity/Controllers/ManageController.cs create mode 100644 src/Services/Identity/eShopOnContainers.Identity/Services/IRedirectService.cs create mode 100644 src/Services/Identity/eShopOnContainers.Identity/Services/RedirectService.cs diff --git a/src/Services/Identity/eShopOnContainers.Identity/Controllers/ConsentController.cs b/src/Services/Identity/eShopOnContainers.Identity/Controllers/ConsentController.cs index 0aec38c0e..f9c37cdf0 100644 --- a/src/Services/Identity/eShopOnContainers.Identity/Controllers/ConsentController.cs +++ b/src/Services/Identity/eShopOnContainers.Identity/Controllers/ConsentController.cs @@ -11,6 +11,7 @@ using IdentityServer4.Models; using IdentityServer4.Stores; using IdentityServer4.Quickstart.UI.Models; using eShopOnContainers.Identity.Models.AccountViewModels; +using eShopOnContainers.Identity.Services; namespace IdentityServer4.Quickstart.UI.Controllers { @@ -23,6 +24,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers private readonly IClientStore _clientStore; private readonly IScopeStore _scopeStore; private readonly IIdentityServerInteractionService _interaction; + public ConsentController( ILogger logger, @@ -45,6 +47,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers public async Task Index(string returnUrl) { var vm = await BuildViewModelAsync(returnUrl); + ViewData["ReturnUrl"] = returnUrl; if (vm != null) { return View("Index", vm); diff --git a/src/Services/Identity/eShopOnContainers.Identity/Controllers/HomeController.cs b/src/Services/Identity/eShopOnContainers.Identity/Controllers/HomeController.cs index 5c0cbd9a9..3e68ee5d3 100644 --- a/src/Services/Identity/eShopOnContainers.Identity/Controllers/HomeController.cs +++ b/src/Services/Identity/eShopOnContainers.Identity/Controllers/HomeController.cs @@ -3,6 +3,7 @@ using eShopOnContainers.Identity; +using eShopOnContainers.Identity.Services; using IdentityServer4.Quickstart.UI.Models; using IdentityServer4.Services; using Microsoft.AspNetCore.Mvc; @@ -15,11 +16,13 @@ namespace IdentityServer4.Quickstart.UI.Controllers { private readonly IIdentityServerInteractionService _interaction; private readonly IOptions _settings; + private readonly IRedirectService _redirectSvc; - public HomeController(IIdentityServerInteractionService interaction, IOptions settings) + public HomeController(IIdentityServerInteractionService interaction, IOptions settings,IRedirectService redirectSvc) { _interaction = interaction; _settings = settings; + _redirectSvc = redirectSvc; } public IActionResult Index(string returnUrl) @@ -27,6 +30,14 @@ namespace IdentityServer4.Quickstart.UI.Controllers return View(); } + public IActionResult ReturnToOriginalApplication(string returnUrl) + { + if (returnUrl != null) + return Redirect(_redirectSvc.ExtractRedirectUriFromReturnUrl(returnUrl)); + else + return RedirectToAction("Index", "Home"); + } + /// /// Shows the error page /// diff --git a/src/Services/Identity/eShopOnContainers.Identity/Controllers/ManageController.cs b/src/Services/Identity/eShopOnContainers.Identity/Controllers/ManageController.cs deleted file mode 100644 index c1d912842..000000000 --- a/src/Services/Identity/eShopOnContainers.Identity/Controllers/ManageController.cs +++ /dev/null @@ -1,360 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; -using eShopOnContainers.Identity.Models; -using eShopOnContainers.Identity.Models.ManageViewModels; -using eShopOnContainers.Identity.Services; - -namespace eShopOnContainers.Identity.Controllers -{ - [Authorize] - public class ManageController : Controller - { - private readonly UserManager _userManager; - private readonly SignInManager _signInManager; - private readonly IEmailSender _emailSender; - private readonly ISmsSender _smsSender; - private readonly ILogger _logger; - - public ManageController( - UserManager userManager, - SignInManager signInManager, - IEmailSender emailSender, - ISmsSender smsSender, - ILoggerFactory loggerFactory) - { - _userManager = userManager; - _signInManager = signInManager; - _emailSender = emailSender; - _smsSender = smsSender; - _logger = loggerFactory.CreateLogger(); - } - - // - // GET: /Manage/Index - [HttpGet] - public async Task Index(ManageMessageId? message = null) - { - ViewData["StatusMessage"] = - message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." - : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." - : message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set." - : message == ManageMessageId.Error ? "An error has occurred." - : message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added." - : message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed." - : ""; - - var user = await GetCurrentUserAsync(); - if (user == null) - { - return View("Error"); - } - var model = new IndexViewModel - { - HasPassword = await _userManager.HasPasswordAsync(user), - PhoneNumber = await _userManager.GetPhoneNumberAsync(user), - TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user), - Logins = await _userManager.GetLoginsAsync(user), - BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user) - }; - return View(model); - } - - // - // POST: /Manage/RemoveLogin - [HttpPost] - [ValidateAntiForgeryToken] - public async Task RemoveLogin(RemoveLoginViewModel account) - { - ManageMessageId? message = ManageMessageId.Error; - var user = await GetCurrentUserAsync(); - if (user != null) - { - var result = await _userManager.RemoveLoginAsync(user, account.LoginProvider, account.ProviderKey); - if (result.Succeeded) - { - await _signInManager.SignInAsync(user, isPersistent: false); - message = ManageMessageId.RemoveLoginSuccess; - } - } - return RedirectToAction(nameof(ManageLogins), new { Message = message }); - } - - // - // GET: /Manage/AddPhoneNumber - public IActionResult AddPhoneNumber() - { - return View(); - } - - // - // POST: /Manage/AddPhoneNumber - [HttpPost] - [ValidateAntiForgeryToken] - public async Task AddPhoneNumber(AddPhoneNumberViewModel model) - { - if (!ModelState.IsValid) - { - return View(model); - } - // Generate the token and send it - var user = await GetCurrentUserAsync(); - if (user == null) - { - return View("Error"); - } - var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber); - await _smsSender.SendSmsAsync(model.PhoneNumber, "Your security code is: " + code); - return RedirectToAction(nameof(VerifyPhoneNumber), new { PhoneNumber = model.PhoneNumber }); - } - - // - // POST: /Manage/EnableTwoFactorAuthentication - [HttpPost] - [ValidateAntiForgeryToken] - public async Task EnableTwoFactorAuthentication() - { - var user = await GetCurrentUserAsync(); - if (user != null) - { - await _userManager.SetTwoFactorEnabledAsync(user, true); - await _signInManager.SignInAsync(user, isPersistent: false); - _logger.LogInformation(1, "User enabled two-factor authentication."); - } - return RedirectToAction(nameof(Index), "Manage"); - } - - // - // POST: /Manage/DisableTwoFactorAuthentication - [HttpPost] - [ValidateAntiForgeryToken] - public async Task DisableTwoFactorAuthentication() - { - var user = await GetCurrentUserAsync(); - if (user != null) - { - await _userManager.SetTwoFactorEnabledAsync(user, false); - await _signInManager.SignInAsync(user, isPersistent: false); - _logger.LogInformation(2, "User disabled two-factor authentication."); - } - return RedirectToAction(nameof(Index), "Manage"); - } - - // - // GET: /Manage/VerifyPhoneNumber - [HttpGet] - public async Task VerifyPhoneNumber(string phoneNumber) - { - var user = await GetCurrentUserAsync(); - if (user == null) - { - return View("Error"); - } - var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, phoneNumber); - // Send an SMS to verify the phone number - return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber }); - } - - // - // POST: /Manage/VerifyPhoneNumber - [HttpPost] - [ValidateAntiForgeryToken] - public async Task VerifyPhoneNumber(VerifyPhoneNumberViewModel model) - { - if (!ModelState.IsValid) - { - return View(model); - } - var user = await GetCurrentUserAsync(); - if (user != null) - { - var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code); - if (result.Succeeded) - { - await _signInManager.SignInAsync(user, isPersistent: false); - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.AddPhoneSuccess }); - } - } - // If we got this far, something failed, redisplay the form - ModelState.AddModelError(string.Empty, "Failed to verify phone number"); - return View(model); - } - - // - // POST: /Manage/RemovePhoneNumber - [HttpPost] - [ValidateAntiForgeryToken] - public async Task RemovePhoneNumber() - { - var user = await GetCurrentUserAsync(); - if (user != null) - { - var result = await _userManager.SetPhoneNumberAsync(user, null); - if (result.Succeeded) - { - await _signInManager.SignInAsync(user, isPersistent: false); - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.RemovePhoneSuccess }); - } - } - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); - } - - // - // GET: /Manage/ChangePassword - [HttpGet] - public IActionResult ChangePassword() - { - return View(); - } - - // - // POST: /Manage/ChangePassword - [HttpPost] - [ValidateAntiForgeryToken] - public async Task ChangePassword(ChangePasswordViewModel model) - { - if (!ModelState.IsValid) - { - return View(model); - } - var user = await GetCurrentUserAsync(); - if (user != null) - { - var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword); - if (result.Succeeded) - { - await _signInManager.SignInAsync(user, isPersistent: false); - _logger.LogInformation(3, "User changed their password successfully."); - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangePasswordSuccess }); - } - AddErrors(result); - return View(model); - } - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); - } - - // - // GET: /Manage/SetPassword - [HttpGet] - public IActionResult SetPassword() - { - return View(); - } - - // - // POST: /Manage/SetPassword - [HttpPost] - [ValidateAntiForgeryToken] - public async Task SetPassword(SetPasswordViewModel model) - { - if (!ModelState.IsValid) - { - return View(model); - } - - var user = await GetCurrentUserAsync(); - if (user != null) - { - var result = await _userManager.AddPasswordAsync(user, model.NewPassword); - if (result.Succeeded) - { - await _signInManager.SignInAsync(user, isPersistent: false); - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetPasswordSuccess }); - } - AddErrors(result); - return View(model); - } - return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); - } - - //GET: /Manage/ManageLogins - [HttpGet] - public async Task ManageLogins(ManageMessageId? message = null) - { - ViewData["StatusMessage"] = - message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." - : message == ManageMessageId.AddLoginSuccess ? "The external login was added." - : message == ManageMessageId.Error ? "An error has occurred." - : ""; - var user = await GetCurrentUserAsync(); - if (user == null) - { - return View("Error"); - } - var userLogins = await _userManager.GetLoginsAsync(user); - var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList(); - ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1; - return View(new ManageLoginsViewModel - { - CurrentLogins = userLogins, - OtherLogins = otherLogins - }); - } - - // - // POST: /Manage/LinkLogin - [HttpPost] - [ValidateAntiForgeryToken] - public IActionResult LinkLogin(string provider) - { - // Request a redirect to the external login provider to link a login for the current user - var redirectUrl = Url.Action("LinkLoginCallback", "Manage"); - var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User)); - return Challenge(properties, provider); - } - - // - // GET: /Manage/LinkLoginCallback - [HttpGet] - public async Task LinkLoginCallback() - { - var user = await GetCurrentUserAsync(); - if (user == null) - { - return View("Error"); - } - var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user)); - if (info == null) - { - return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error }); - } - var result = await _userManager.AddLoginAsync(user, info); - var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error; - return RedirectToAction(nameof(ManageLogins), new { Message = message }); - } - - #region Helpers - - private void AddErrors(IdentityResult result) - { - foreach (var error in result.Errors) - { - ModelState.AddModelError(string.Empty, error.Description); - } - } - - public enum ManageMessageId - { - AddPhoneSuccess, - AddLoginSuccess, - ChangePasswordSuccess, - SetTwoFactorSuccess, - SetPasswordSuccess, - RemoveLoginSuccess, - RemovePhoneSuccess, - Error - } - - private Task GetCurrentUserAsync() - { - return _userManager.GetUserAsync(HttpContext.User); - } - - #endregion - } -} diff --git a/src/Services/Identity/eShopOnContainers.Identity/Services/IRedirectService.cs b/src/Services/Identity/eShopOnContainers.Identity/Services/IRedirectService.cs new file mode 100644 index 000000000..20982460b --- /dev/null +++ b/src/Services/Identity/eShopOnContainers.Identity/Services/IRedirectService.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace eShopOnContainers.Identity.Services +{ + public interface IRedirectService + { + string ExtractRedirectUriFromReturnUrl(string url); + } +} diff --git a/src/Services/Identity/eShopOnContainers.Identity/Services/RedirectService.cs b/src/Services/Identity/eShopOnContainers.Identity/Services/RedirectService.cs new file mode 100644 index 000000000..d38ad9d38 --- /dev/null +++ b/src/Services/Identity/eShopOnContainers.Identity/Services/RedirectService.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace eShopOnContainers.Identity.Services +{ + public class RedirectService : IRedirectService + { + public string ExtractRedirectUriFromReturnUrl(string url) + { + var result = ""; + var decodedUrl = System.Net.WebUtility.HtmlDecode(url); + var results = Regex.Split(decodedUrl, "redirect_uri="); + if (results.Length < 2) + return ""; + + result = results[1]; + + var splitKey = ""; + if (result.Contains("signin-oidc")) + splitKey = "signin-oidc"; + else + splitKey = "scope"; + + results = Regex.Split(result, splitKey); + if (results.Length < 2) + return ""; + + result = results[0]; + + return result.Replace("%3A", ":").Replace("%2F", "/").Replace("&", ""); + } + } +} diff --git a/src/Services/Identity/eShopOnContainers.Identity/Startup.cs b/src/Services/Identity/eShopOnContainers.Identity/Startup.cs index 716c1dbe9..cf2fd9213 100644 --- a/src/Services/Identity/eShopOnContainers.Identity/Startup.cs +++ b/src/Services/Identity/eShopOnContainers.Identity/Startup.cs @@ -59,6 +59,7 @@ namespace eShopOnContainers.Identity services.AddTransient(); services.AddTransient(); services.AddTransient, EFLoginService>(); + services.AddTransient(); //callbacks urls from config: Dictionary clientUrls = new Dictionary(); diff --git a/src/Services/Identity/eShopOnContainers.Identity/Views/Shared/_Layout.cshtml b/src/Services/Identity/eShopOnContainers.Identity/Views/Shared/_Layout.cshtml index 4e582e712..5086d12ec 100644 --- a/src/Services/Identity/eShopOnContainers.Identity/Views/Shared/_Layout.cshtml +++ b/src/Services/Identity/eShopOnContainers.Identity/Views/Shared/_Layout.cshtml @@ -14,7 +14,7 @@