diff --git a/src/Umbraco.Core/Sync/ApplicationUrlHelper.cs b/src/Umbraco.Core/Sync/ApplicationUrlHelper.cs index 52af734f1c..d934e24575 100644 --- a/src/Umbraco.Core/Sync/ApplicationUrlHelper.cs +++ b/src/Umbraco.Core/Sync/ApplicationUrlHelper.cs @@ -102,5 +102,22 @@ namespace Umbraco.Core.Sync return url.TrimEnd(Constants.CharArrays.ForwardSlash); } + + /// + /// Will get the application URL from configuration, if none is specified will fall back to URL from request. + /// + /// + /// + /// + /// + public static Uri GetApplicationUriUncached( + HttpRequestBase request, + IUmbracoSettingsSection umbracoSettingsSection) + { + var settingUrl = umbracoSettingsSection.WebRouting.UmbracoApplicationUrl; + return string.IsNullOrEmpty(settingUrl) + ? new Uri(request.Url, IOHelper.ResolveUrl(SystemDirectories.Umbraco)) + : new Uri(settingUrl); + } } } diff --git a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs index 3d264663b5..9bd9ee73ed 100644 --- a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs @@ -16,6 +16,7 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; @@ -82,7 +83,8 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), - helper); + helper, + Factory.GetInstance()); return usersController; } diff --git a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs index 85dd303432..b9289c1392 100644 --- a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs @@ -14,6 +14,7 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; @@ -84,7 +85,8 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), - helper); + helper, + Factory.GetInstance()); return usersController; } @@ -148,7 +150,8 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), - helper); + helper, + Factory.GetInstance()); return usersController; } @@ -183,7 +186,8 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), - helper); + helper, + Factory.GetInstance()); return usersController; } @@ -253,7 +257,8 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), - helper); + helper, + Factory.GetInstance()); return usersController; } diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs index 3ecc6b64a4..54612377e0 100644 --- a/src/Umbraco.Web/Editors/AuthenticationController.cs +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -27,6 +27,8 @@ using Umbraco.Web.Composing; using IUser = Umbraco.Core.Models.Membership.IUser; using Umbraco.Web.Editors.Filters; using Microsoft.Owin.Security; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Sync; namespace Umbraco.Web.Editors { @@ -40,12 +42,23 @@ namespace Umbraco.Web.Editors [DisableBrowserCache] public class AuthenticationController : UmbracoApiController { + private readonly IUmbracoSettingsSection _umbracoSettingsSection; private BackOfficeUserManager _userManager; private BackOfficeSignInManager _signInManager; - public AuthenticationController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) + public AuthenticationController( + IGlobalSettings globalSettings, + IUmbracoContextAccessor umbracoContextAccessor, + ISqlContext sqlContext, + ServiceContext services, + AppCaches appCaches, + IProfilingLogger logger, + IRuntimeState runtimeState, + UmbracoHelper umbracoHelper, + IUmbracoSettingsSection umbracoSettingsSection) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper, Current.Mapper) { + _umbracoSettingsSection = umbracoSettingsSection; } protected BackOfficeUserManager UserManager => _userManager @@ -552,8 +565,8 @@ namespace Umbraco.Web.Editors r = code }); - // Construct full URL using configured application URL (which will fall back to request) - var applicationUri = Current.RuntimeState.ApplicationUrl; + // Construct full URL using configured application URL (which will fall back to current request) + var applicationUri = ApplicationUrlHelper.GetApplicationUriUncached(http.Request, _umbracoSettingsSection); var callbackUri = new Uri(applicationUri, action); return callbackUri.ToString(); } diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index dda0dfc933..4bfd72854f 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -17,6 +17,7 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -27,6 +28,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Security; using Umbraco.Core.Services; +using Umbraco.Core.Sync; using Umbraco.Web.Editors.Filters; using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; @@ -46,9 +48,21 @@ namespace Umbraco.Web.Editors [IsCurrentUserModelFilter] public class UsersController : UmbracoAuthorizedJsonController { - public UsersController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) + private readonly IUmbracoSettingsSection _umbracoSettingsSection; + + public UsersController( + IGlobalSettings globalSettings, + IUmbracoContextAccessor umbracoContextAccessor, + ISqlContext sqlContext, + ServiceContext services, + AppCaches appCaches, + IProfilingLogger logger, + IRuntimeState runtimeState, + UmbracoHelper umbracoHelper, + IUmbracoSettingsSection umbracoSettingsSection) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { + _umbracoSettingsSection = umbracoSettingsSection; } /// @@ -390,7 +404,7 @@ namespace Umbraco.Web.Editors user = CheckUniqueEmail(userSave.Email, u => u.LastLoginDate != default || u.EmailConfirmedDate.HasValue); var userMgr = TryGetOwinContext().Result.GetBackOfficeUserManager(); - + if (!EmailSender.CanSendRequiredEmail && !userMgr.HasSendingUserInviteEventHandler) { throw new HttpResponseException( @@ -462,12 +476,12 @@ namespace Umbraco.Web.Editors Email = userSave.Email, Username = userSave.Username }; - } + } } else { //send the email - await SendUserInviteEmailAsync(display, Security.CurrentUser.Name, Security.CurrentUser.Email, user, userSave.Message); + await SendUserInviteEmailAsync(display, Security.CurrentUser.Name, Security.CurrentUser.Email, user, userSave.Message); } display.AddSuccessNotification(Services.TextService.Localize("speechBubbles", "resendInviteHeader"), Services.TextService.Localize("speechBubbles", "resendInviteSuccess", new[] { user.Name })); @@ -525,9 +539,9 @@ namespace Umbraco.Web.Editors invite = inviteToken }); - // Construct full URL using configured application URL (which will fall back to request) - var applicationUri = RuntimeState.ApplicationUrl; - var inviteUri = new Uri(applicationUri, action); + // Construct full URL will use the value in settings if specified, otherwise will use the current request URL + var requestUrl = ApplicationUrlHelper.GetApplicationUriUncached(http.Request, _umbracoSettingsSection); + var inviteUri = new Uri(requestUrl, action); var emailSubject = Services.TextService.Localize("user", "inviteEmailCopySubject", //Ensure the culture of the found user is used for the email! @@ -622,7 +636,7 @@ namespace Umbraco.Web.Editors if (Current.Configs.Settings().Security.UsernameIsEmail && found.Username == found.Email && userSave.Username != userSave.Email) { userSave.Username = userSave.Email; - } + } if (hasErrors) throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); @@ -647,13 +661,13 @@ namespace Umbraco.Web.Editors } /// - /// + /// /// /// /// public async Task> PostChangePassword(ChangingPasswordModel changingPasswordModel) { - changingPasswordModel = changingPasswordModel ?? throw new ArgumentNullException(nameof(changingPasswordModel)); + changingPasswordModel = changingPasswordModel ?? throw new ArgumentNullException(nameof(changingPasswordModel)); if (ModelState.IsValid == false) {