Merge pull request #8572 from umbraco/netcore/bugfix/6970-backoffice-controller
Migrates remaining non-oauth actions on back office controller to netcore
This commit is contained in:
@@ -321,7 +321,6 @@ namespace Umbraco.Core.Migrations.Install
|
||||
var database = scope.Database;
|
||||
var dbSchema = new DatabaseSchemaCreator(database, _logger, _umbracoVersion, _globalSettings);
|
||||
_databaseSchemaValidationResult = dbSchema.ValidateSchema();
|
||||
scope.Complete();
|
||||
return _databaseSchemaValidationResult;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
/// <inheritdoc />
|
||||
public string GetValue(string key)
|
||||
{
|
||||
using (var scope = _scopeProvider.CreateScope())
|
||||
using (var scope = _scopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
return _repository.Get(key)?.Value;
|
||||
}
|
||||
|
||||
@@ -13,14 +13,17 @@ using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.Grid;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.WebAssets;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.Common.ActionResults;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
using Umbraco.Web.Common.Filters;
|
||||
using Umbraco.Web.Common.Security;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.WebAssets;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
|
||||
@@ -40,6 +43,8 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
private readonly BackOfficeServerVariables _backOfficeServerVariables;
|
||||
private readonly AppCaches _appCaches;
|
||||
private readonly BackOfficeSignInManager _signInManager;
|
||||
private readonly IWebSecurity _webSecurity;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public BackOfficeController(
|
||||
BackOfficeUserManager userManager,
|
||||
@@ -51,7 +56,10 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
IGridConfig gridConfig,
|
||||
BackOfficeServerVariables backOfficeServerVariables,
|
||||
AppCaches appCaches,
|
||||
BackOfficeSignInManager signInManager)
|
||||
BackOfficeSignInManager signInManager,
|
||||
IWebSecurity webSecurity,
|
||||
ILogger logger)
|
||||
|
||||
{
|
||||
_userManager = userManager;
|
||||
_runtimeMinifier = runtimeMinifier;
|
||||
@@ -63,6 +71,8 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
_backOfficeServerVariables = backOfficeServerVariables;
|
||||
_appCaches = appCaches;
|
||||
_signInManager = signInManager;
|
||||
_webSecurity = webSecurity;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
@@ -76,6 +86,84 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
() => View(viewPath));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> VerifyInvite(string invite)
|
||||
{
|
||||
//if you are hitting VerifyInvite, you're already signed in as a different user, and the token is invalid
|
||||
//you'll exit on one of the return RedirectToAction(nameof(Default)) but you're still logged in so you just get
|
||||
//dumped at the default admin view with no detail
|
||||
if (_webSecurity.IsAuthenticated())
|
||||
{
|
||||
await _signInManager.SignOutAsync();
|
||||
}
|
||||
|
||||
if (invite == null)
|
||||
{
|
||||
_logger.Warn<BackOfficeController>("VerifyUser endpoint reached with invalid token: NULL");
|
||||
return RedirectToAction(nameof(Default));
|
||||
}
|
||||
|
||||
var parts = System.Net.WebUtility.UrlDecode(invite).Split('|');
|
||||
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
_logger.Warn<BackOfficeController>("VerifyUser endpoint reached with invalid token: {Invite}", invite);
|
||||
return RedirectToAction(nameof(Default));
|
||||
}
|
||||
|
||||
var token = parts[1];
|
||||
|
||||
var decoded = token.FromUrlBase64();
|
||||
if (decoded.IsNullOrWhiteSpace())
|
||||
{
|
||||
_logger.Warn<BackOfficeController>("VerifyUser endpoint reached with invalid token: {Invite}", invite);
|
||||
return RedirectToAction(nameof(Default));
|
||||
}
|
||||
|
||||
var id = parts[0];
|
||||
|
||||
var identityUser = await _userManager.FindByIdAsync(id);
|
||||
if (identityUser == null)
|
||||
{
|
||||
_logger.Warn<BackOfficeController>("VerifyUser endpoint reached with non existing user: {UserId}", id);
|
||||
return RedirectToAction(nameof(Default));
|
||||
}
|
||||
|
||||
var result = await _userManager.ConfirmEmailAsync(identityUser, decoded);
|
||||
|
||||
if (result.Succeeded == false)
|
||||
{
|
||||
_logger.Warn<BackOfficeController>("Could not verify email, Error: {Errors}, Token: {Invite}", result.Errors.ToErrorMessage(), invite);
|
||||
return new RedirectResult(Url.Action(nameof(Default)) + "#/login/false?invite=3");
|
||||
}
|
||||
|
||||
//sign the user in
|
||||
DateTime? previousLastLoginDate = identityUser.LastLoginDateUtc;
|
||||
await _signInManager.SignInAsync(identityUser, false);
|
||||
//reset the lastlogindate back to previous as the user hasn't actually logged in, to add a flag or similar to BackOfficeSignInManager would be a breaking change
|
||||
identityUser.LastLoginDateUtc = previousLastLoginDate;
|
||||
await _userManager.UpdateAsync(identityUser);
|
||||
|
||||
return new RedirectResult(Url.Action(nameof(Default)) + "#/login/false?invite=1");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This Action is used by the installer when an upgrade is detected but the admin user is not logged in. We need to
|
||||
/// ensure the user is authenticated before the install takes place so we redirect here to show the standard login screen.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[StatusCodeResult(System.Net.HttpStatusCode.ServiceUnavailable)]
|
||||
public async Task<IActionResult> AuthorizeUpgrade()
|
||||
{
|
||||
var viewPath = Path.Combine(_globalSettings.UmbracoPath, Umbraco.Core.Constants.Web.Mvc.BackOfficeArea, nameof(AuthorizeUpgrade) + ".cshtml");
|
||||
return await RenderDefaultOrProcessExternalLoginAsync(
|
||||
//The default view to render when there is no external login info or errors
|
||||
() => View(viewPath),
|
||||
//The IActionResult to perform if external login is successful
|
||||
() => Redirect("/"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the JavaScript main file including all references found in manifests
|
||||
/// </summary>
|
||||
@@ -97,8 +185,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
[HttpGet]
|
||||
public Dictionary<string, Dictionary<string, string>> LocalizedText(string culture = null)
|
||||
{
|
||||
var securityHelper = _umbracoContextAccessor.GetRequiredUmbracoContext().Security;
|
||||
var isAuthenticated = securityHelper.IsAuthenticated();
|
||||
var isAuthenticated = _webSecurity.IsAuthenticated();
|
||||
|
||||
var cultureInfo = string.IsNullOrWhiteSpace(culture)
|
||||
//if the user is logged in, get their culture, otherwise default to 'en'
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
@using Umbraco.Core
|
||||
@using Umbraco.Web.WebAssets
|
||||
@using Umbraco.Web.Common.Security
|
||||
@using Umbraco.Core.WebAssets
|
||||
@using Umbraco.Core.Configuration
|
||||
@using Umbraco.Core.Hosting
|
||||
@using Umbraco.Extensions
|
||||
@using Umbraco.Core.Logging
|
||||
@using Umbraco.Web.BackOffice.Controllers
|
||||
@inject BackOfficeSignInManager signInManager
|
||||
@inject BackOfficeServerVariables backOfficeServerVariables
|
||||
@inject IUmbracoVersion umbracoVersion
|
||||
@inject IHostingEnvironment hostingEnvironment
|
||||
@inject IGlobalSettings globalSettings
|
||||
@inject IRuntimeMinifier runtimeMinifier
|
||||
|
||||
@{
|
||||
var backOfficePath = globalSettings.GetBackOfficePath(hostingEnvironment);
|
||||
}
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<base href="@backOfficePath.EnsureEndsWith('/')" />
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Umbraco</title>
|
||||
|
||||
@Html.Raw(await runtimeMinifier.RenderCssHereAsync(BackOfficeWebAssets.UmbracoUpgradeCssBundleName))
|
||||
|
||||
@*Because we're lazy loading angular js, the embedded cloak style will not be loaded initially, but we need it*@
|
||||
<style>
|
||||
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body id="umbracoMainPageBody" ng-controller="Umbraco.AuthorizeUpgradeController" class="login-only">
|
||||
|
||||
<umb-login on-login="loginAndRedirect()"></umb-login>
|
||||
|
||||
<umb-notifications></umb-notifications>
|
||||
|
||||
@{
|
||||
var externalLoginUrl = Url.Action("ExternalLogin", "BackOffice", new
|
||||
{
|
||||
area = ViewData.GetUmbracoPath(),
|
||||
//Custom redirect URL since we don't want to just redirect to the back office since this is for authing upgrades
|
||||
redirectUrl = Url.Action("AuthorizeUpgrade", "BackOffice")
|
||||
});
|
||||
}
|
||||
|
||||
@await Html.BareMinimumServerVariablesScriptAsync(backOfficeServerVariables)
|
||||
|
||||
<script type="text/javascript">
|
||||
document.angularReady = function (app) {
|
||||
|
||||
@await Html.AngularValueExternalLoginInfoScriptAsync(signInManager, ViewData.GetExternalSignInError())
|
||||
@Html.AngularValueResetPasswordCodeInfoScript(ViewData["PasswordResetCode"])
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
@*And finally we can load in our angular app*@
|
||||
<script type="text/javascript" src="lib/lazyload-js/lazyload.min.js"></script>
|
||||
<script src="@Url.GetUrlWithCacheBust("Application", "BackOffice", null, hostingEnvironment, umbracoVersion, runtimeMinifier)"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,32 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.UI;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Owin.Security;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Features;
|
||||
using Umbraco.Web.Security;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using Umbraco.Core.Configuration.Grid;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.WebAssets;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.Trees;
|
||||
using Umbraco.Web.WebAssets;
|
||||
using BackOfficeIdentityUser = Umbraco.Core.BackOffice.BackOfficeIdentityUser;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
@@ -77,85 +66,6 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
protected IAuthenticationManager AuthenticationManager => OwinContext.Authentication;
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult> VerifyInvite(string invite)
|
||||
{
|
||||
//if you are hitting VerifyInvite, you're already signed in as a different user, and the token is invalid
|
||||
//you'll exit on one of the return RedirectToAction("Default") but you're still logged in so you just get
|
||||
//dumped at the default admin view with no detail
|
||||
if(Security.IsAuthenticated())
|
||||
{
|
||||
AuthenticationManager.SignOut(
|
||||
Core.Constants.Security.BackOfficeAuthenticationType,
|
||||
Core.Constants.Security.BackOfficeExternalAuthenticationType);
|
||||
}
|
||||
|
||||
if (invite == null)
|
||||
{
|
||||
Logger.Warn<BackOfficeController>("VerifyUser endpoint reached with invalid token: NULL");
|
||||
return RedirectToAction("Default");
|
||||
}
|
||||
|
||||
var parts = Server.UrlDecode(invite).Split('|');
|
||||
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
Logger.Warn<BackOfficeController>("VerifyUser endpoint reached with invalid token: {Invite}", invite);
|
||||
return RedirectToAction("Default");
|
||||
}
|
||||
|
||||
var token = parts[1];
|
||||
|
||||
var decoded = token.FromUrlBase64();
|
||||
if (decoded.IsNullOrWhiteSpace())
|
||||
{
|
||||
Logger.Warn<BackOfficeController>("VerifyUser endpoint reached with invalid token: {Invite}", invite);
|
||||
return RedirectToAction("Default");
|
||||
}
|
||||
|
||||
var id = parts[0];
|
||||
|
||||
var identityUser = await UserManager.FindByIdAsync(id);
|
||||
if (identityUser == null)
|
||||
{
|
||||
Logger.Warn<BackOfficeController>("VerifyUser endpoint reached with non existing user: {UserId}", id);
|
||||
return RedirectToAction("Default");
|
||||
}
|
||||
|
||||
var result = await UserManager.ConfirmEmailAsync(identityUser, decoded);
|
||||
|
||||
if (result.Succeeded == false)
|
||||
{
|
||||
Logger.Warn<BackOfficeController>("Could not verify email, Error: {Errors}, Token: {Invite}", result.Errors.ToErrorMessage(), invite);
|
||||
return new RedirectResult(Url.Action("Default") + "#/login/false?invite=3");
|
||||
}
|
||||
|
||||
//sign the user in
|
||||
DateTime? previousLastLoginDate = identityUser.LastLoginDateUtc;
|
||||
await SignInManager.SignInAsync(identityUser, false, false);
|
||||
//reset the lastlogindate back to previous as the user hasn't actually logged in, to add a flag or similar to SignInManager would be a breaking change
|
||||
identityUser.LastLoginDateUtc = previousLastLoginDate;
|
||||
await UserManager.UpdateAsync(identityUser);
|
||||
|
||||
return new RedirectResult(Url.Action("Default") + "#/login/false?invite=1");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This Action is used by the installer when an upgrade is detected but the admin user is not logged in. We need to
|
||||
/// ensure the user is authenticated before the install takes place so we redirect here to show the standard login screen.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[StatusCodeResult(System.Net.HttpStatusCode.ServiceUnavailable)]
|
||||
public async Task<ActionResult> AuthorizeUpgrade()
|
||||
{
|
||||
return await RenderDefaultOrProcessExternalLoginAsync(
|
||||
//The default view to render when there is no external login info or errors
|
||||
() => View(GlobalSettings.GetBackOfficePath(_hostingEnvironment).EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _contentSettings, _hostingEnvironment, _runtimeSettings, _securitySettings)),
|
||||
//The ActionResult to perform if external login is successful
|
||||
() => Redirect("/"));
|
||||
}
|
||||
|
||||
|
||||
// TODO: for converting to netcore, some examples:
|
||||
// * https://github.com/dotnet/aspnetcore/blob/master/src/Identity/samples/IdentitySample.Mvc/Controllers/AccountController.cs
|
||||
|
||||
Reference in New Issue
Block a user